Browse Source

Merge branch 'main' of http://47.98.207.247:3000/lsq/ship-ota-server

lishiqiang 1 month ago
parent
commit
2efcabf089
14 changed files with 342 additions and 9 deletions
  1. 18 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyage/VoyageController.java
  2. 6 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyage/vo/VoyageRespVO.java
  3. 8 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/dal/mysql/voyage/VoyageMapper.java
  4. 9 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/service/voyage/VoyageService.java
  5. 5 0
      ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/service/voyage/VoyageServiceImpl.java
  6. 16 1
      ship-module-product/ship-module-product-biz/src/main/resources/mapper/voyage/VoyageMapper.xml
  7. 3 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/order/vo/order/TouristExportVisitorVO.java
  8. 3 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/OtcTradeOrderServiceImpl.java
  9. 206 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/utils/IdCardProvinceUtil.java
  10. 59 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/utils/excel/ExcelStyleHandler.java
  11. 8 8
      ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeOrderMapper.xml
  12. 1 0
      ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeVisitorMapper.xml
  13. BIN
      ship-module-trade/ship-module-trade-biz/src/main/resources/templates/tourist_template_agent.xlsx
  14. BIN
      ship-module-trade/ship-module-trade-biz/src/main/resources/templates/tourist_template_operator.xlsx

+ 18 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyage/VoyageController.java

@@ -28,8 +28,10 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import static com.yc.ship.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static com.yc.ship.framework.common.pojo.CommonResult.success;
@@ -103,6 +105,18 @@ public class VoyageController {
         PageResult<VoyageDO> pageResult = voyageService.getVoyagePage(pageReqVO);
         PageResult<VoyageRespVO> page = BeanUtils.toBean(pageResult, VoyageRespVO.class);
         List<VoyageRespVO> list = page.getList();
+
+        // 批量查询预定人数
+        List<Long> voyageIds = CollectionUtils.convertList(list, VoyageRespVO::getId);
+        Map<Long, Integer> bookingCountMap = new HashMap<>();;
+        if (!voyageIds.isEmpty()) {
+            bookingCountMap = voyageService.countBatchByVoyageIds(voyageIds).stream()
+                    .collect(Collectors.toMap(
+                            countMap -> (Long) countMap.get("voyageId"),
+                            countMap -> countMap.get("count") != null ? ((Number) countMap.get("count")).intValue() : 0
+                    ));
+        }
+
         List<Long> shipIds = CollectionUtils.convertList(list, VoyageRespVO::getShipId);
         List<ResourceShipDO> shipList = shipService.getList(shipIds);
         Map<Long, ResourceShipDO> shipDoMap = CollectionUtils.convertMap(shipList, ResourceShipDO::getId);
@@ -110,9 +124,13 @@ public class VoyageController {
         List<Long> routeIds = CollectionUtils.convertList(list, VoyageRespVO::getRouteId);
         List<ResourceRouteDO> routeList = routeService.getList(routeIds);
         Map<Long, ResourceRouteDO> routeDoMap = CollectionUtils.convertMap(routeList, ResourceRouteDO::getId);
+        Map<Long, Integer> finalBookingCountMap = bookingCountMap;
         list.forEach(item -> {
             MapUtils.findAndThen(shipDoMap, item.getShipId(), shipDO -> item.setShipName(shipDO.getName()));
             MapUtils.findAndThen(routeDoMap, item.getRouteId(), routeDO -> item.setRouteName(routeDO.getName()));
+
+            // 从批量查询的 Map 中获取预定人数
+            item.setBookingCount(finalBookingCountMap.getOrDefault(item.getId(), 0));
         });
         return success(page);
     }

+ 6 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/controller/admin/voyage/vo/VoyageRespVO.java

@@ -148,4 +148,10 @@ public class VoyageRespVO {
     private Integer direction;
 
     private Integer isLock;
+
+    /**
+     * 预定人数
+     */
+    @Schema(description = "预定人数")
+    private Integer bookingCount;
 }

+ 8 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/dal/mysql/voyage/VoyageMapper.java

@@ -15,6 +15,7 @@ import org.apache.ibatis.annotations.Param;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 航次管理 Mapper
@@ -104,4 +105,11 @@ public interface VoyageMapper extends BaseMapperX<VoyageDO> {
      * @return
      */
     List<AppVoyageDayRespVO> selectVoyageListByShipIdAndDate(@Param("shipId") Long shipId, @Param("date") String date);
+
+    /**
+     * 批量统计航次的预定人数
+     * @param voyageIds
+     * @return Map<voyageId, count>
+     */
+    List<Map<String, Object>> countBatchByVoyageIds(@Param("voyageIds") List<Long> voyageIds);
 }

+ 9 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/service/voyage/VoyageService.java

@@ -4,8 +4,10 @@ import com.yc.ship.framework.common.pojo.PageResult;
 import com.yc.ship.module.product.controller.admin.voyage.vo.*;
 import com.yc.ship.module.product.controller.app.voyage.vo.AppVoyageDayRespVO;
 import com.yc.ship.module.product.dal.dataobject.voyage.VoyageDO;
+import org.apache.ibatis.annotations.Param;
 
 import javax.validation.Valid;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -96,4 +98,11 @@ public interface VoyageService {
     List<AppVoyageDayRespVO> getVoyageListByShipIdAndDate(Long shipId, String date);
 
     void updateLockVoyage(String id);
+
+    /**
+     * 统计航次的预定人数
+     * @param voyageIds
+     * @return
+     */
+    List<Map<String, Object>> countBatchByVoyageIds(@Param("voyageId") List<Long> voyageIds);
 }

+ 5 - 0
ship-module-product/ship-module-product-biz/src/main/java/com/yc/ship/module/product/service/voyage/VoyageServiceImpl.java

@@ -446,4 +446,9 @@ public class VoyageServiceImpl implements VoyageService {
         log.info("航次: {}, {}完成 ...", id, (voyageDO.getIsLock().intValue() == 0 ? "解锁" : "锁定"));
     }
 
+    @Override
+    public List<Map<String, Object>> countBatchByVoyageIds(List<Long> voyageIds) {
+        return voyageMapper.countBatchByVoyageIds(voyageIds);
+    }
+
 }

+ 16 - 1
ship-module-product/ship-module-product-biz/src/main/resources/mapper/voyage/VoyageMapper.xml

@@ -10,7 +10,7 @@
      -->
     <select id="selectVovageList" resultType="com.yc.ship.module.product.dal.dataobject.voyage.VoyageDO">
          select  w.*,r.direction from product_voyage w inner join resource_route r on w.route_id = r.id
-         where w.deleted = 0 and r.deleted = 0 and w.ship_id = #{shipId} and w.start_time > now() and w.shelf_status = 1 and w.channel like '%1%' order by w.create_time asc;
+         where w.deleted = 0 and r.deleted = 0 and w.ship_id = #{shipId} and w.start_time > DATE_SUB(now(), INTERVAL 1 MONTH) and w.shelf_status = 1 and w.channel like '%1%' order by w.create_time asc;
     </select>
     <select id="selectListCalendar2" resultType="com.yc.ship.module.product.dal.dataobject.voyage.VoyageDO">
         select w.*,r.price basicPrice from product_voyage w inner join resource_route r on w.route_id = r.id
@@ -55,4 +55,19 @@
          and w.shelf_status = 1
         order by w.start_time asc
     </select>
+
+
+    <select id="countBatchByVoyageIds" resultType="java.util.HashMap">
+        select b.voyage_id voyageId, count(tv.id) as count
+        from trade_visitor tv
+        join trade_order b on tv.order_id = b.id and b.deleted = 0
+        where b.voyage_id in
+        <foreach collection="voyageIds" item="voyageId" open="(" separator="," close=")">
+            #{voyageId}
+        </foreach>
+        and tv.deleted = 0
+        and b.order_status = 6
+        group by b.voyage_id
+    </select>
+
 </mapper>

+ 3 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/order/vo/order/TouristExportVisitorVO.java

@@ -90,6 +90,9 @@ public class TouristExportVisitorVO {
     @Schema(description = "手机号")
     private String mobile;
 
+    @Schema(description = "年龄")
+    private String age;
+
     @Schema(description = "楼层")
     private String floor;
 

+ 3 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/otc/impl/OtcTradeOrderServiceImpl.java

@@ -104,6 +104,7 @@ import com.yc.ship.module.trade.framework.annotation.TradeOrderLog;
 import com.yc.ship.module.trade.framework.common.ConfigUtils;
 import com.yc.ship.module.trade.framework.common.ThreadLocalUtil;
 import com.yc.ship.module.trade.framework.common.TradeOrderLogUtils;
+import com.yc.ship.module.trade.utils.IdCardProvinceUtil;
 import com.yc.ship.module.trade.framework.mq.TradePublishUtils;
 import com.yc.ship.module.trade.service.invoice.InvoiceService;
 import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
@@ -3211,7 +3212,9 @@ public class OtcTradeOrderServiceImpl implements OtcTradeOrderService {
                         item.put("valueAddedService", StringUtils.isEmpty(visitor.getValueAddedService()) ? "" : formatPolicyName(visitor.getValueAddedService())); // 增值服务(如:接送站、保险等)
                         item.put("policyName", ""); // 优惠政策(如:早鸟优惠、团立减等)
                         item.put("remark", StringUtils.isEmpty(visitor.getRemark()) ? "" : visitor.getRemark()); // 备注信息
+                        item.put("age", StringUtils.isEmpty(visitor.getAge()) ? "" : visitor.getAge()); // 年龄
 
+                        item.put("province", IdCardProvinceUtil.getProvinceName(visitor.getCredentialType(), visitor.getCredentialNo(), visitor.getNationalityName())); // 省份(根据身份证号解析)
 
                         item.put("visitorHome", StringUtils.isEmpty(visitor.getVisitorType()) ? "" : DictFrameworkUtils.getDictDataLabel(DictTypeConstants.TOUR_TYPE, visitor.getVisitorType())); // 游客入住类型
 

+ 206 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/utils/IdCardProvinceUtil.java

@@ -0,0 +1,206 @@
+package com.yc.ship.module.trade.utils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 证件号码解析工具类 - 根据证件号前2位省份码解析省份名称
+ * <p>
+ * 中国大陆身份证号码前6位为行政区划码,其中前2位代表省份。
+ * 港澳台居民居住证同样采用18位编码格式,前2位为大陆居住地省份码。
+ * 护照、通行证、回乡证、台胞证、户口本等证件号码格式不同,无法解析省份。
+ * </p>
+ * <p>
+ * 支持解析的证件类型:
+ *   1  - 身份证(18位/15位)
+ *   11 - 港澳台居民居住证(18位,编码规则同身份证)
+ * </p>
+ * <p>
+ * 不支持解析的证件类型(返回空字符串):
+ *   3  - 港澳台通行证
+ *   4  - 护照
+ *   5  - 港澳通行证
+ *   6  - 台湾通行证
+ *   7  - 回乡证(港澳居民来往内地通行证)
+ *   8  - 台胞证(台湾居民来往大陆通行证)
+ *   10 - 户口本
+ * </p>
+ *
+ * @Author: AI
+ * @Date: 2026/05/06
+ */
+public class IdCardProvinceUtil {
+
+    // ==================== 证件类型常量 ====================
+    /** 身份证 */
+    public static final int CREDENTIAL_TYPE_ID_CARD = 0;
+    /** 港澳台通行证 */
+    public static final int CREDENTIAL_TYPE_HK_MACAO_TAIWAN_PASS = 3;
+    /** 护照 */
+    public static final int CREDENTIAL_TYPE_PASSPORT = 1;
+    /** 港澳通行证 */
+    public static final int CREDENTIAL_TYPE_HK_MACAO_PASS = 5;
+    /** 台湾通行证 */
+    public static final int CREDENTIAL_TYPE_TAIWAN_PASS = 6;
+    /** 回乡证(港澳居民来往内地通行证) */
+    public static final int CREDENTIAL_TYPE_HOME_RETURN_PERMIT = 7;
+    /** 台胞证(台湾居民来往大陆通行证) */
+    public static final int CREDENTIAL_TYPE_TAIWAN_COMPATRIOT_PERMIT = 8;
+    /** 户口本 */
+    public static final int CREDENTIAL_TYPE_HOUSEHOLD_REGISTER = 10;
+    /** 港澳台居民居住证 */
+    public static final int CREDENTIAL_TYPE_HK_MACAO_TAIWAN_RESIDENCE_PERMIT = 11;
+
+    // ==================== 校验常量 ====================
+    /** 身份证号码长度(18位) */
+    private static final int ID_CARD_LENGTH_18 = 18;
+    /** 旧身份证号码长度(15位) */
+    private static final int ID_CARD_LENGTH_15 = 15;
+    /** 省份码长度(前2位) */
+    private static final int PROVINCE_CODE_LENGTH = 2;
+    /** 18位身份证号末位校验位可能为X */
+    private static final char ID_CARD_X = 'X';
+    private static final char ID_CARD_X_LOWER = 'x';
+
+    /**
+     * 可以解析省份的证件类型集合(号码格式与身份证相同,采用18位行政区划编码)
+     * 身份证(1) 和 港澳台居民居住证(11) 均采用GB 11643编码规则
+     */
+    private static final Set<Integer> PARSEABLE_CREDENTIAL_TYPES = Collections.unmodifiableSet(
+            new HashSet<>(Arrays.asList(CREDENTIAL_TYPE_ID_CARD, CREDENTIAL_TYPE_HK_MACAO_TAIWAN_RESIDENCE_PERMIT))
+    );
+
+    /** 省份码 -> 省份名称 映射表(不可变,基于GB/T 2260行政区划代码前2位) */
+    private static final Map<String, String> PROVINCE_MAP;
+
+    static {
+        Map<String, String> map = new HashMap<>(40);
+        map.put("11", "北京");
+        map.put("12", "天津");
+        map.put("13", "河北");
+        map.put("14", "山西");
+        map.put("15", "内蒙古");
+        map.put("21", "辽宁");
+        map.put("22", "吉林");
+        map.put("23", "黑龙江");
+        map.put("31", "上海");
+        map.put("32", "江苏");
+        map.put("33", "浙江");
+        map.put("34", "安徽");
+        map.put("35", "福建");
+        map.put("36", "江西");
+        map.put("37", "山东");
+        map.put("41", "河南");
+        map.put("42", "湖北");
+        map.put("43", "湖南");
+        map.put("44", "广东");
+        map.put("45", "广西");
+        map.put("46", "海南");
+        map.put("50", "重庆");
+        map.put("51", "四川");
+        map.put("52", "贵州");
+        map.put("53", "云南");
+        map.put("54", "西藏");
+        map.put("61", "陕西");
+        map.put("62", "甘肃");
+        map.put("63", "青海");
+        map.put("64", "宁夏");
+        map.put("65", "新疆");
+        map.put("71", "台湾");
+        map.put("81", "香港");
+        map.put("82", "澳门");
+        // 91开头的为国外身份证件,无对应省份
+        PROVINCE_MAP = Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * 根据证件类型和证件号解析省份名称
+     * <p>
+     * 身份证(1)和港澳台居民居住证(11):通过号码前2位省份码解析;
+     * 台湾通行证(6)和台胞证(8):直接返回"台湾";
+     * 其他证件类型(护照、港澳通行证等):返回空字符串。
+     * </p>
+     *
+     * @param credentialType 证件类型
+     * @param credentialNo   证件号码
+     * @return 省份名称,无法解析时返回空字符串
+     */
+    public static String getProvinceName(Integer credentialType, String credentialNo, String  nationalityName) {
+        if (credentialType == null) {
+            return "";
+        }
+        // 台湾通行证、台胞证 → 直接返回"台湾"
+        if (credentialType == CREDENTIAL_TYPE_TAIWAN_PASS
+                || credentialType == CREDENTIAL_TYPE_TAIWAN_COMPATRIOT_PERMIT) {
+            return "台湾";
+        }
+
+        if (nationalityName.contains("香港")) {
+            return "香港";
+        }
+
+        if (nationalityName.contains("澳门")) {
+            return "澳门";
+        }
+        // 非可解析的证件类型,直接返回空
+        if (!PARSEABLE_CREDENTIAL_TYPES.contains(credentialType)) {
+            return "";
+        }
+        // 证件号为空或长度不足,无法解析
+        if (credentialNo == null || credentialNo.trim().length() < PROVINCE_CODE_LENGTH) {
+            return "";
+        }
+        String trimmedNo = credentialNo.trim();
+        // 校验号码格式
+        if (!isValidIdCardFormat(trimmedNo)) {
+            return "";
+        }
+        // 提取省份码(前2位)并查表
+        String provinceCode = trimmedNo.substring(0, PROVINCE_CODE_LENGTH);
+        return PROVINCE_MAP.getOrDefault(provinceCode, "");
+    }
+
+    /**
+     * 校验号码是否符合身份证编码格式
+     * <p>
+     * 18位:前17位必须为数字,第18位可为数字或X/x
+     * 15位:全部必须为数字
+     * </p>
+     *
+     * @param idCardNo 证件号码(已trim)
+     * @return 格式是否合法
+     */
+    private static boolean isValidIdCardFormat(String idCardNo) {
+        int len = idCardNo.length();
+        if (len == ID_CARD_LENGTH_18) {
+            // 前17位必须为数字
+            String first17 = idCardNo.substring(0, 17);
+            if (!isNumeric(first17)) {
+                return false;
+            }
+            // 第18位可为数字或X/x
+            char lastChar = idCardNo.charAt(17);
+            return Character.isDigit(lastChar) || lastChar == ID_CARD_X || lastChar == ID_CARD_X_LOWER;
+        } else if (len == ID_CARD_LENGTH_15) {
+            // 15位旧身份证:全部为数字
+            return isNumeric(idCardNo);
+        }
+        return false;
+    }
+
+    /**
+     * 判断字符串是否全部由数字组成
+     */
+    private static boolean isNumeric(String str) {
+        for (int i = 0, len = str.length(); i < len; i++) {
+            if (!Character.isDigit(str.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 59 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/utils/excel/ExcelStyleHandler.java

@@ -43,6 +43,9 @@ public class ExcelStyleHandler implements CellWriteHandler {
     /** 是否已经执行过合并 */
     private boolean mergeCompleted = false;
 
+    /** 预计算的需要清空的单元格集合,key格式为 "相对行索引_列索引" */
+    private Set<String> blankCellSet;
+
     public ExcelStyleHandler(int templateRowIndex) {
         this.templateRowIndex = templateRowIndex;
     }
@@ -51,6 +54,8 @@ public class ExcelStyleHandler implements CellWriteHandler {
         this.visitorList = visitorList;
         this.fileType = fileType;
         this.totalRows = visitorList != null ? visitorList.size() : 0;
+        // 预计算需要清空的单元格(合并区域中非首行的单元格)
+        this.blankCellSet = computeBlankCells();
     }
 
 
@@ -201,6 +206,16 @@ public class ExcelStyleHandler implements CellWriteHandler {
             return;
         }
 
+        // 在单元格写入后,立即清空需要合并的非首行单元格的值
+        Cell cell = context.getCell();
+        int currentRowIndex = cell.getRow().getRowNum();
+        int colIndex = cell.getColumnIndex();
+        int relativeRow = currentRowIndex - DATA_START_ROW;
+        if (relativeRow >= 0 && blankCellSet != null
+                && blankCellSet.contains(relativeRow + "_" + colIndex)) {
+            cell.setCellValue("");
+        }
+
         // 统计处理的单元格数量
         processedCellCount++;
 
@@ -288,6 +303,50 @@ public class ExcelStyleHandler implements CellWriteHandler {
         return s != null ? s : "";
     }
 
+    /**
+     * 预计算合并区域中需要清空的单元格
+     * 合并后只有首行需要保留数据,其余行设为空字符串
+     * @return 需要清空的单元格集合,key格式为 "相对行索引_列索引"
+     */
+    private Set<String> computeBlankCells() {
+        Set<String> blankSet = new HashSet<>();
+        if (visitorList == null || visitorList.size() <= 1) {
+            return blankSet;
+        }
+
+        int n = visitorList.size();
+        Map<Integer, List<int[]>> mergeRanges = new HashMap<>();
+
+        // 预定义每种类型需要合并的列(与 performMerge 中保持一致)
+        List<Integer> sourceCols = Collections.singletonList(0);
+        List<Integer> orderCols = Arrays.asList(1, 2, 3, 4, 5, 6,
+                        fileType == 1 ? 7 : -1, fileType == 1 ? 8 : -1).stream()
+                .filter(c -> c >= 0).collect(Collectors.toList());
+        List<Integer> roomCols = (fileType == 1
+                ? Arrays.asList(9, 10, 11)
+                : Arrays.asList(7, 8, 9));
+
+        for (int col : sourceCols) collectMergeRanges(mergeRanges, col, n,
+                i -> safeString(visitorList.get(i).getSourceName()));
+        for (int col : orderCols) collectMergeRanges(mergeRanges, col, n,
+                i -> safeString(visitorList.get(i).getOrderNo()));
+        for (int col : roomCols) collectMergeRanges(mergeRanges, col, n,
+                i -> safeString(visitorList.get(i).getRoomIndexId()) + "_" + safeString(visitorList.get(i).getOrderNo()));
+
+        // 将合并区域中非首行的单元格加入清空集合
+        for (Map.Entry<Integer, List<int[]>> entry : mergeRanges.entrySet()) {
+            int col = entry.getKey();
+            for (int[] range : entry.getValue()) {
+                // range[0]+1 到 range[1] 是非首行,需要清空
+                for (int rowIdx = range[0] + 1; rowIdx <= range[1]; rowIdx++) {
+                    blankSet.add(rowIdx + "_" + col);
+                }
+            }
+        }
+
+        return blankSet;
+    }
+
 
     /**
      * 废弃

+ 8 - 8
ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeOrderMapper.xml

@@ -208,8 +208,8 @@
                 COUNT(1) AS num
                 FROM trade_order td
                 INNER JOIN trade_order_user tou ON td.id = tou.order_id AND tou.deleted = 0
-                LEFT JOIN trade_detail tdl ON td.id = tdl.order_id AND tdl.deleted = 0
-                LEFT JOIN trade_visitor tv ON tdl.id = tv.detail_id AND tv.deleted = 0
+                LEFT JOIN trade_visitor tv ON td.id = tv.order_id  AND tv.deleted = 0
+                LEFT JOIN trade_detail tdl ON tv.detail_id = tdl.id AND tdl.deleted = 0
                 LEFT JOIN trade_order_room_model torm ON tv.room_index_id = torm.room_index_id AND torm.deleted = 0 AND td.id = torm.order_id
                 LEFT JOIN resource_room_model rrm ON torm.room_model_id = rrm.id
                 LEFT JOIN product_spu ps ON ps.id = tdl.product_id
@@ -232,8 +232,8 @@
                 COUNT(DISTINCT torm.room_index_id) AS roomNum
                 FROM trade_order td
                 INNER JOIN trade_order_user tou ON td.id = tou.order_id AND tou.deleted = 0
-                LEFT JOIN trade_detail tdl ON td.id = tdl.order_id AND tdl.deleted = 0
-                LEFT JOIN trade_visitor tv ON tdl.id = tv.detail_id AND tv.deleted = 0
+                LEFT JOIN trade_visitor tv ON td.id = tv.order_id  AND tv.deleted = 0
+                LEFT JOIN trade_detail tdl ON tv.detail_id = tdl.id AND tdl.deleted = 0
                 LEFT JOIN trade_order_room_model torm ON tv.room_index_id = torm.room_index_id AND torm.deleted = 0 AND td.id = torm.order_id
                 LEFT JOIN resource_room_model rrm ON torm.room_model_id = rrm.id
                 LEFT JOIN product_spu ps ON ps.id = tdl.product_id
@@ -251,8 +251,8 @@
         SELECT COUNT(DISTINCT torm.room_index_id)
             FROM trade_order td
             INNER JOIN trade_order_user tou ON td.id = tou.order_id AND tou.deleted = 0
-            LEFT JOIN trade_detail tdl ON td.id = tdl.order_id AND tdl.deleted = 0
-            LEFT JOIN trade_visitor tv ON tdl.id = tv.detail_id AND tv.deleted = 0
+            LEFT JOIN trade_visitor tv ON td.id = tv.order_id  AND tv.deleted = 0
+            LEFT JOIN trade_detail tdl ON tv.detail_id = tdl.id AND tdl.deleted = 0
             LEFT JOIN trade_order_room_model torm ON tv.room_index_id = torm.room_index_id AND torm.deleted = 0 AND td.id = torm.order_id
             LEFT JOIN resource_room_model rrm ON torm.room_model_id = rrm.id
             LEFT JOIN product_spu ps ON ps.id = tdl.product_id
@@ -276,8 +276,8 @@
             IFNULL(topay.actual_amount, 0) AS actual_amount
             FROM trade_order td
             INNER JOIN trade_order_user tou ON td.id = tou.order_id AND tou.deleted = 0
-            LEFT JOIN trade_detail tdl ON td.id = tdl.order_id AND tdl.deleted = 0
-            LEFT JOIN trade_visitor tv ON tdl.id = tv.detail_id AND tv.deleted = 0
+            LEFT JOIN trade_visitor tv ON td.id = tv.order_id  AND tv.deleted = 0
+            LEFT JOIN trade_detail tdl ON tv.detail_id = tdl.id AND tdl.deleted = 0
             LEFT JOIN product_spu ps ON ps.id = tdl.product_id
             LEFT JOIN ota_distributor od ON od.id = td.source_id
             LEFT JOIN (select m2.order_id,sum(m2.refund_amount) refund_amount,sum(m2.origin_amount) origin_amount from trade_refund m2  where m2.refund_status = 6 and m2.refund_method !=2 GROUP BY m2.order_id) tr on td.id = tr.order_id

+ 1 - 0
ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeVisitorMapper.xml

@@ -275,6 +275,7 @@
             tv.credential_type AS credentialType,
             tv.credential_no AS credentialNo,
             tv.type AS visitorType,
+            tv.age,
             torm.floor as floor,
             a.name AS nationalityName,
             GROUP_CONCAT(ps.product_name) AS valueAddedService,

BIN
ship-module-trade/ship-module-trade-biz/src/main/resources/templates/tourist_template_agent.xlsx


BIN
ship-module-trade/ship-module-trade-biz/src/main/resources/templates/tourist_template_operator.xlsx