ソースを参照

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

lishiqiang 1 週間 前
コミット
6782c60c8e
17 ファイル変更1599 行追加50 行削除
  1. 178 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/OrderGiftVisitorController.java
  2. 53 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderGiftVisitorPageReqVO.java
  3. 105 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderGiftVisitorRespVO.java
  4. 51 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderGiftVisitorSaveReqVO.java
  5. 20 2
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDetailBatchSignReqVO.java
  6. 66 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDetailGiftExportVO.java
  7. 10 2
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchBatchReqVO.java
  8. 4 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchPageReqVO.java
  9. 6 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchRecordRespVO.java
  10. 6 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchSaveReqVO.java
  11. 154 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/dal/dataobject/orderjzdetail/OrderGiftVisitorDO.java
  12. 66 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/dal/mysql/orderjz/OrderGiftVisitorMapper.java
  13. 146 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/orderjzdetail/OrderGiftVisitorService.java
  14. 474 0
      ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/orderjzdetail/OrderGiftVisitorServiceImpl.java
  15. 1 1
      ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/order/TradeOrderMapper.xml
  16. 173 0
      ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/orderjzdetail/OrderGiftVisitorMapper.xml
  17. 86 45
      ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/report/BankTransactionDetailsMapper.xml

+ 178 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/OrderGiftVisitorController.java

@@ -0,0 +1,178 @@
+package com.yc.ship.module.trade.controller.admin.orderjzdetail;
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.framework.common.pojo.CommonResult;
+import com.yc.ship.framework.common.util.object.BeanUtils;
+import static com.yc.ship.framework.common.pojo.CommonResult.success;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yc.ship.framework.excel.core.util.ExcelUtils;
+
+import com.yc.ship.module.trade.controller.admin.orderjzdetail.vo.*;
+import com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO;
+
+import com.yc.ship.module.trade.service.orderjzdetail.OrderGiftVisitorService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+/**
+ * 蹭送行程游客 Controller
+ *
+ * @author yc
+ */
+@Tag(name = "管理后台 - 蹭送行程游客")
+@RestController
+@RequestMapping("/trade/order-gift-visitor")
+@Validated
+public class OrderGiftVisitorController {
+
+    @Resource
+    private OrderGiftVisitorService orderGiftVisitorService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建蹭送行程游客")
+    @PreAuthorize("@ss.hasPermission('trade:order-gift-visitor:create')")
+    public CommonResult<Long> createOrderGiftVisitor(@Valid @RequestBody OrderGiftVisitorSaveReqVO createReqVO) {
+        return success(orderGiftVisitorService.createOrderGiftVisitor(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新蹭送行程游客")
+    @PreAuthorize("@ss.hasPermission('trade:order-gift-visitor:update')")
+    public CommonResult<Boolean> updateOrderGiftVisitor(@Valid @RequestBody OrderGiftVisitorSaveReqVO updateReqVO) {
+        orderGiftVisitorService.updateOrderGiftVisitor(updateReqVO);
+        return success(true);
+    }
+
+
+    @GetMapping("/get")
+    @Operation(summary = "获得蹭送行程游客")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('trade:order-gift-visitor:query')")
+    public CommonResult<OrderGiftVisitorRespVO> getOrderGiftVisitor(@RequestParam("id") Long id) {
+        OrderGiftVisitorDO orderGiftVisitor = orderGiftVisitorService.getOrderGiftVisitor(id);
+        return success(BeanUtils.toBean(orderGiftVisitor, OrderGiftVisitorRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得蹭送行程游客分页")
+    @PreAuthorize("@ss.hasPermission('trade:order-jz-detail-sign:query')")
+    public CommonResult<PageResult<OrderGiftVisitorRespVO>> getOrderGiftVisitorPage(@Valid OrderGiftVisitorPageReqVO pageReqVO) {
+        PageResult<OrderGiftVisitorDO> pageResult = orderGiftVisitorService.getOrderGiftVisitorPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, OrderGiftVisitorRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出蹭送行程接站明细 Excel")
+    @PreAuthorize("@ss.hasPermission('trade:order-jz-detail-sign:query')")
+    public void exportGiftVisitorExcel(@Valid OrderGiftVisitorPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        List<OrderGiftVisitorDO> list = orderGiftVisitorService.getExportList(pageReqVO);
+        // 导出 Excel
+        ExcelUtils.write(response, "赠送行程接站明细.xls", "数据", OrderJzDetailGiftExportVO.class,
+                        BeanUtils.toBean(list, OrderJzDetailGiftExportVO.class));
+    }
+
+    // ==================== 签到核销相关 ====================
+
+    @PostMapping("/sign")
+    @Operation(summary = "签到核销")
+    public CommonResult<Boolean> sign(@RequestBody OrderGiftVisitorSaveReqVO signReqVO) {
+        orderGiftVisitorService.signOrderGiftVisitor(
+                signReqVO
+        );
+        return success(true);
+    }
+
+    @DeleteMapping("/sign/clean")
+    @Operation(summary = "清除签到")
+    @Parameter(name = "id", description = "编号", required = true)
+    public CommonResult<Boolean> cleanSign(@RequestParam("id") Long id) {
+        orderGiftVisitorService.cleanSign(id);
+        return success(true);
+    }
+
+    @PostMapping("/batch-sign")
+    @Operation(summary = "批量签到核销")
+    public CommonResult<Integer> batchSign(@Valid @RequestBody OrderJzDetailBatchSignReqVO reqVO) {
+        Integer count = orderGiftVisitorService.batchSignOrderGiftVisitor(
+                reqVO.getItems(), reqVO.getSignRemark()
+        );
+        return success(count);
+    }
+
+    // ==================== 补登订单查询相关 ====================
+
+    @GetMapping("/gift/order/query")
+    @Operation(summary = "蹭送行程补登订单分页查询")
+    @PreAuthorize("@ss.hasPermission('trade:order-gift-visitor:query')")
+    public CommonResult<PageResult<OrderGiftVisitorRespVO>> getGiftOrderPage(@Valid OrderGiftVisitorPageReqVO pageReqVO) {
+        IPage<OrderGiftVisitorDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
+        IPage<OrderGiftVisitorDO> resultPage = orderGiftVisitorService.getGiftOrderPage(pageReqVO);
+        return success(new PageResult<>(
+            BeanUtils.toBean(resultPage.getRecords(), OrderGiftVisitorRespVO.class),
+            resultPage.getTotal()
+        ));
+    }
+
+
+
+    // ==================== 分车操作 ====================
+
+    @PostMapping("/createDispatch")
+    @Operation(summary = "创建蹭送行程分车(单个)")
+    public CommonResult<Long> createGiftDispatch(@Valid @RequestBody OrderJzDispatchSaveReqVO createReqVO,
+                                                 @RequestParam("visitorId") Long visitorId) {
+        return success(orderGiftVisitorService.createGiftDispatch(createReqVO, visitorId));
+    }
+
+    @PostMapping("/batch-create")
+    @Operation(summary = "批量保存蹭送行程分车")
+    public CommonResult<Integer> batchSaveGiftDispatch(@Valid @RequestBody OrderJzDispatchBatchReqVO batchReqVO) {
+        return success(orderGiftVisitorService.batchSaveGiftDispatch(batchReqVO));
+    }
+
+    @PutMapping("/updateDispatch")
+    @Operation(summary = "更新蹭送行程分车")
+    public CommonResult<Boolean> updateGiftDispatch(@Valid @RequestBody OrderJzDispatchSaveReqVO updateReqVO) {
+        orderGiftVisitorService.updateGiftDispatch(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/deleteDispatch")
+    @Operation(summary = "删除蹭送行程分车(根据游客ID)")
+    @Parameter(name = "id", description = "ID", required = true)
+    public CommonResult<Boolean> deleteGiftDispatch(@RequestParam("id") Long id) {
+        orderGiftVisitorService.deleteGiftDispatchByVisitorId(id);
+        return success(true);
+    }
+
+    // ==================== 分车记录查询 ====================
+
+    @GetMapping("/record/page")
+    @Operation(summary = "获得蹭送行程分车记录分页")
+    public CommonResult<PageResult<OrderJzDispatchRecordRespVO>> getGiftDispatchRecordPage(@Valid OrderJzDispatchPageReqVO pageReqVO) {
+        return success(orderGiftVisitorService.getGiftDispatchRecordPage(pageReqVO));
+    }
+
+    @GetMapping("/record/export-excel")
+    @Operation(summary = "导出蹭送行程分车记录 Excel")
+    public void exportGiftDispatchExcel(@Valid OrderJzDispatchPageReqVO pageReqVO,
+                                        HttpServletResponse response) throws IOException {
+        List<OrderJzDispatchRecordRespVO> list = orderGiftVisitorService.getExportGiftDispatchList(pageReqVO);
+        // 导出 Excel
+        ExcelUtils.write(response, "蹭送行程分车记录.xls", "数据", OrderJzDispatchRecordRespVO.class, list);
+    }
+}

+ 53 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderGiftVisitorPageReqVO.java

@@ -0,0 +1,53 @@
+package com.yc.ship.module.trade.controller.admin.orderjzdetail.vo;
+
+import lombok.*;
+import com.yc.ship.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import javax.validation.constraints.*;
+
+/**
+ * 蹭送行程游客分页查询 Req VO
+ *
+ * @author yc
+ */
+@Schema(description = "管理后台 - 蹭送行程游客分页查询 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class OrderGiftVisitorPageReqVO extends PageParam {
+
+    @Schema(description = "航次ID", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "航次ID不能为空")
+    private Long voyageId;
+
+    @Schema(description = "证件号")
+    private String idCard;
+
+    @Schema(description = "游客姓名")
+    private String name;
+
+    @Schema(description = "接站点")
+    private String address;
+
+    @Schema(description = "抵达时间段")
+    private String arriveTime;
+
+    @Schema(description = "分车号")
+    private String dispatchNo;
+
+    @Schema(description = "核销状态 1-已核销 0-未核销")
+    private Integer signStatus;
+
+    @Schema(description = "订单号")
+    private String orderNo;
+
+    @Schema(description = "分销商ID")
+    private String otaId;
+
+    @Schema(description = "订单编号序号或证件号后4位(用于补登查询)")
+    private String queryCode;
+
+    @Schema(description = "航次方向")
+    private String direction;
+}

+ 105 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderGiftVisitorRespVO.java

@@ -0,0 +1,105 @@
+package com.yc.ship.module.trade.controller.admin.orderjzdetail.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static com.yc.ship.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+ * 蹭送行程游客 Response VO
+ *
+ * @author yc
+ */
+@Schema(description = "管理后台 - 蹭送行程游客 Response VO")
+@Data
+@ToString(callSuper = true)
+public class OrderGiftVisitorRespVO {
+
+    @Schema(description = "主键ID", example = "1")
+    private Long id;
+
+    @Schema(description = "航次ID", example = "12345")
+    private Long voyageId;
+
+    @Schema(description = "游客ID", example = "12345")
+    private Long visitorId;
+
+    @Schema(description = "订单ID", example = "12345")
+    private Long orderId;
+
+    @Schema(description = "分车ID", example = "12345")
+    private Long dispatchId;
+
+    @Schema(description = "接站点", example = "重庆北站")
+    private String address;
+
+    @Schema(description = "抵达时间段", example = "08:00-10:00")
+    private String arriveTime;
+
+    @Schema(description = "签到核销时间")
+    private String signTime;
+
+    @Schema(description = "签到人", example = "张三")
+    private String signMan;
+
+    @Schema(description = "签到备注")
+    private String signRemark;
+
+    @Schema(description = "签到图片")
+    private String signImage;
+
+    @Schema(description = "备注")
+    private String remark;
+
+    @Schema(description = "游客姓名", example = "张三")
+    private String name;
+
+    @Schema(description = "证件号", example = "500123199001011234")
+    private String credentialNo;
+
+    @Schema(description = "手机号", example = "13800138000")
+    private String mobile;
+
+    @Schema(description = "房型ID", example = "12345")
+    private Long roomModelId;
+
+    @Schema(description = "房型名称", example = "标准间")
+    private String roomModelName;
+
+    @Schema(description = "订单号", example = "ORD20240128001")
+    private String orderNo;
+
+    @Schema(description = "航次方向", example = "1")
+    private String direction;
+
+    @Schema(description = "分车号", example = "1号车")
+    private String dispatchNo;
+
+    @Schema(description = "分车组团号", example = "A组")
+    private String groupNo;
+
+    @Schema(description = "车牌号", example = "渝A12345")
+    private String busNumber;
+
+    @Schema(description = "司机姓名", example = "李四")
+    private String driverName;
+
+    @Schema(description = "司机电话", example = "13900139000")
+    private String driverPhone;
+
+    @Schema(description = "接站人员", example = "王五")
+    private String receiverName;
+
+    @Schema(description = "接站人电话", example = "13700137000")
+    private String receiverPhone;
+
+    private String idCard;
+
+    private String phone;
+}

+ 51 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderGiftVisitorSaveReqVO.java

@@ -0,0 +1,51 @@
+package com.yc.ship.module.trade.controller.admin.orderjzdetail.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 蹭送行程游客创建/更新 Req VO
+ *
+ * @author yc
+ */
+@Schema(description = "管理后台 - 蹭送行程游客创建/更新 Request VO")
+@Data
+@ToString(callSuper = true)
+public class OrderGiftVisitorSaveReqVO {
+
+    @Schema(description = "主键ID", example = "1")
+    private Long id;
+
+    @Schema(description = "航次ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12345")
+    @NotNull(message = "航次ID不能为空")
+    private Long voyageId;
+
+    @Schema(description = "游客ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12345")
+    @NotNull(message = "游客ID不能为空")
+    private Long visitorId;
+
+    @Schema(description = "订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12345")
+    @NotNull(message = "订单ID不能为空")
+    private Long orderId;
+
+    @Schema(description = "分车ID", example = "12345")
+    private Long dispatchId;
+
+    @Schema(description = "接站点", example = "重庆北站")
+    private String address;
+
+    @Schema(description = "抵达时间段", example = "08:00-10:00")
+    private String arriveTime;
+
+    @Schema(description = "签到备注")
+    private String signRemark;
+
+    @Schema(description = "签到图片")
+    private String signImage;
+
+    @Schema(description = "备注")
+    private String remark;
+}

+ 20 - 2
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDetailBatchSignReqVO.java

@@ -10,10 +10,28 @@ import java.util.List;
 @Data
 public class OrderJzDetailBatchSignReqVO {
 
-    @Schema(description = "接站人员ID列表", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotEmpty(message = "请选择需要核销的游客")
+
+    @Schema(description = "接站人员ID列表")
     private List<Long> ids;
 
+    @Schema(description = "签到信息列表")
+    private List<SignItem> items;
+
     @Schema(description = "核销备注", example = "批量核销")
     private String signRemark;
+
+    @Data
+    public static class SignItem {
+        @Schema(description = "记录ID(已存在则为更新,不存在则为新增)")
+        private Long id;
+
+        @Schema(description = "游客ID")
+        private Long visitorId;
+
+        @Schema(description = "航次ID")
+        private Long voyageId;
+
+        @Schema(description = "订单ID")
+        private Long orderId;
+    }
 }

+ 66 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDetailGiftExportVO.java

@@ -0,0 +1,66 @@
+package com.yc.ship.module.trade.controller.admin.orderjzdetail.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static com.yc.ship.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ExcelIgnoreUnannotated
+@Data
+public class OrderJzDetailGiftExportVO {
+
+    @ExcelProperty(value = "序号", index = 0)
+    private Integer index;
+
+    @ExcelProperty(value = "订单编号", index = 1)
+    private String orderNo;
+
+    @ExcelProperty(value = "姓名", index = 2)
+    private String name;
+
+    @ExcelProperty(value = "证件号", index = 3)
+    private String idCard;
+
+    @ExcelProperty(value = "联系电话", index = 4)
+    private String phone;
+
+    @ExcelProperty(value = "房型", index = 5)
+    private String roomModelName;
+
+    @ExcelProperty(value = "车次/航班号", index = 6)
+    private String remark;
+
+    @ExcelProperty(value = "核销时间", index = 7)
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private String signTime;
+
+    @ExcelProperty(value = "分车号", index = 8)
+    private String dispatchNo;
+
+    @ExcelProperty(value = "分车组团号", index = 9)
+    private String groupNo;
+
+    @ExcelProperty(value = "车牌号", index = 10)
+    private String busNumber;
+
+    @ExcelProperty(value = "司机姓名", index = 11)
+    private String driverName;
+
+    @ExcelProperty(value = "司机联系电话", index = 12)
+    private String driverPhone;
+
+    @ExcelProperty(value = "接站人员", index = 13)
+    private String receiverName;
+
+    @ExcelProperty(value = "接站人电话", index = 14)
+    private String receiverPhone;
+
+    @ExcelProperty(value = "分车情况", index = 15)
+    private String dispatchRemark;
+
+    @ExcelProperty(value = "预约情况", index = 16)
+    private String reservationInfo;
+
+}

+ 10 - 2
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchBatchReqVO.java

@@ -28,12 +28,20 @@ public class OrderJzDispatchBatchReqVO {
     @Data
     public static class OrderItem {
 
-        @Schema(description = "接站人员ID(OrderJzDetailDO.id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-        @NotNull(message = "接站人员ID不能为空")
+        @Schema(description = "蹭送行程游客记录ID,为空则新增记录", example = "1")
         private Long id;
 
         @Schema(description = "分车记录ID(OrderJzDispatchDO.id),有值则更新,无值则新建", example = "100")
         private Long dispatchId;
+
+        @Schema(description = "游客ID", example = "1")
+        private Long visitorId;
+
+        @Schema(description = "航次ID", example = "1")
+        private Long voyageId;
+
+        @Schema(description = "订单ID", example = "1")
+        private Long orderId;
     }
 
     @Schema(description = "分车信息")

+ 4 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchPageReqVO.java

@@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
 
 import static com.yc.ship.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -52,6 +53,9 @@ public class OrderJzDispatchPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
+    @Schema(description = "分车组团号")
+    private String groupNo;
+
 
 
 

+ 6 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchRecordRespVO.java

@@ -3,12 +3,18 @@ package com.yc.ship.module.trade.controller.admin.orderjzdetail.vo;
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 
 @Schema(description = "管理后台 - 分车记录 Response VO")
 @Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
 @ExcelIgnoreUnannotated
 public class OrderJzDispatchRecordRespVO implements Serializable {
 

+ 6 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/controller/admin/orderjzdetail/vo/OrderJzDispatchSaveReqVO.java

@@ -1,7 +1,10 @@
 package com.yc.ship.module.trade.controller.admin.orderjzdetail.vo;
 
 import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
@@ -9,6 +12,9 @@ import java.time.LocalDateTime;
 
 @Schema(description = "管理后台 - 订单分车创建/更新 Request VO")
 @Data
+@NoArgsConstructor
+@Builder
+@AllArgsConstructor
 public class OrderJzDispatchSaveReqVO {
 
     @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.AUTO)

+ 154 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/dal/dataobject/orderjzdetail/OrderGiftVisitorDO.java

@@ -0,0 +1,154 @@
+package com.yc.ship.module.trade.dal.dataobject.orderjzdetail;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.yc.ship.framework.mybatis.core.dataobject.BaseDO;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 蹭送行程游客 DO
+ *
+ * @author yc
+ */
+@TableName("trade_order_jz_gift_visitor")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrderGiftVisitorDO extends BaseDO {
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 航次ID
+     */
+    private Long voyageId;
+
+    /**
+     * 游客ID(关联trade_visitor)
+     */
+    private Long visitorId;
+
+    /**
+     * 订单ID(关联trade_order)
+     */
+    private Long orderId;
+
+    /**
+     * 分车ID(关联trade_order_jz_dispatch, source_type=2)
+     */
+    private Long dispatchId;
+
+    /**
+     * 接站点
+     */
+    private String address;
+
+    /**
+     * 抵达时间段
+     */
+    private String arriveTime;
+
+    /**
+     * 签到核销时间
+     */
+    private String signTime;
+
+    /**
+     * 签到人
+     */
+    private String signMan;
+
+    /**
+     * 签到备注
+     */
+    private String signRemark;
+
+    /**
+     * 签到图片
+     */
+    private String signImage;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 租户ID
+     */
+    private Long tenantId;
+
+
+    /**
+     * 订单编号(关联查询,非表字段)
+     */
+    @TableField(exist = false)
+    private String orderNo;
+
+    /**
+     * 分车号(关联查询,非表字段)
+     */
+    @TableField(exist = false)
+    private String dispatchNo;
+
+    /**
+     * 分车组团号(关联查询,非表字段)
+     */
+    @TableField(exist = false)
+    private String groupNo;
+
+    /**
+     * 方向(关联查询,非表字段)
+     */
+    @TableField(exist = false)
+    private String direction;
+
+    /**
+     * 房型名称(关联查询,非表字段)
+     */
+    @TableField(exist = false)
+    private String roomModelName;
+
+    @TableField(exist = false)
+    private String busNumber;
+
+    @TableField(exist = false)
+    private String driverName;
+
+    @TableField(exist = false)
+    private String driverPhone;
+
+    @TableField(exist = false)
+    private String receiverName;
+
+    @TableField(exist = false)
+    private String receiverPhone;
+
+    /**
+     * 分车备注(关联查询,非表字段)
+     */
+    @TableField(exist = false)
+    private String dispatchRemark;
+
+
+    @TableField(exist = false)
+    private String name;
+
+
+    @TableField(exist = false)
+    private String idCard;
+
+    @TableField(exist = false)
+    private String phone;
+
+
+
+}

+ 66 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/dal/mysql/orderjz/OrderGiftVisitorMapper.java

@@ -0,0 +1,66 @@
+package com.yc.ship.module.trade.dal.mysql.orderjz;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yc.ship.framework.mybatis.core.mapper.BaseMapperX;
+import com.yc.ship.module.trade.controller.admin.orderjzdetail.vo.OrderGiftVisitorPageReqVO;
+import com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 蹭送行程游客 Mapper
+ *
+ * @author yc
+ */
+@Mapper
+public interface OrderGiftVisitorMapper extends BaseMapperX<OrderGiftVisitorDO> {
+
+    /**
+     * 分页查询蹭送行程游客(关联trade_visitor、trade_order等表)
+     *
+     * @param page 分页参数
+     * @param reqVO 查询条件
+     * @return 分页结果
+     */
+    IPage<OrderGiftVisitorDO> selectPageWithVisitor(IPage<OrderGiftVisitorDO> page, @Param("vo") OrderGiftVisitorPageReqVO reqVO);
+
+    /**
+     * 导出蹭送行程接站明细
+     *
+     * @param reqVO 查询条件
+     * @return 导出列表
+     */
+    java.util.List<OrderGiftVisitorDO> selectExportList(@Param("vo") OrderGiftVisitorPageReqVO reqVO);
+
+    /**
+     * 根据分车ID查询蹭送行程游客列表
+     *
+     * @param dispatchId 分车ID
+     * @return 游客列表
+     */
+    java.util.List<OrderGiftVisitorDO> selectByDispatchId(@Param("dispatchId") Long dispatchId);
+
+    /**
+     * 根据游客ID和航次ID查询蹭送行程记录
+     *
+     * @param visitorId 游客ID
+     * @param voyageId 航次ID
+     * @return 蹭送行程记录
+     */
+    OrderGiftVisitorDO selectByVisitorIdAndVoyageId(@Param("visitorId") Long visitorId, @Param("voyageId") Long voyageId);
+
+    /**
+     * 根据分车ID统计游客人数
+     *
+     * @param dispatchId 分车ID
+     * @return 游客人数
+     */
+    Integer countByDispatchId(@Param("dispatchId") Long dispatchId);
+
+    /**
+     * 清除签到信息
+     *
+     * @param id 记录ID
+     */
+    void cleanSignById(@Param("id") Long id);
+}

+ 146 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/orderjzdetail/OrderGiftVisitorService.java

@@ -0,0 +1,146 @@
+package com.yc.ship.module.trade.service.orderjzdetail;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.trade.controller.admin.orderjzdetail.vo.OrderGiftVisitorPageReqVO;
+import com.yc.ship.module.trade.controller.admin.orderjzdetail.vo.*;
+import com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO;
+
+import java.util.List;
+
+/**
+ * 蹭送行程游客 Service 接口
+ *
+ * @author yc
+ */
+public interface OrderGiftVisitorService {
+
+    /**
+     * 创建蹭送行程游客
+     *
+     * @param createReqVO 创建信息
+     * @return 游客ID
+     */
+    Long createOrderGiftVisitor(OrderGiftVisitorSaveReqVO createReqVO);
+
+    /**
+     * 批量创建蹭送行程游客
+     *
+     * @param createReqVOList 创建信息列表
+     * @return 成功数量
+     */
+    Integer batchCreateOrderGiftVisitor(List<OrderGiftVisitorSaveReqVO> createReqVOList);
+
+    /**
+     * 更新蹭送行程游客
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateOrderGiftVisitor(OrderGiftVisitorSaveReqVO updateReqVO);
+
+
+    /**
+     * 获得蹭送行程游客
+     *
+     * @param id 游客ID
+     * @return 蹭送行程游客
+     */
+    OrderGiftVisitorDO getOrderGiftVisitor(Long id);
+
+    /**
+     * 获得蹭送行程游客分页
+     *
+     * @param pageReqVO 分页查询条件
+     * @return 蹭送行程游客分页
+     */
+    PageResult<OrderGiftVisitorDO> getOrderGiftVisitorPage(OrderGiftVisitorPageReqVO pageReqVO);
+
+    /**
+     * 导出蹭送行程接站明细
+     *
+     * @param pageReqVO 查询条件
+     * @return 导出列表
+     */
+    List<OrderGiftVisitorDO> getExportList(OrderGiftVisitorPageReqVO pageReqVO);
+
+    /**
+     * 蹭送行程补登订单分页查询
+     *
+     * @param pageReqVO 查询条件
+     * @return 订单分页结果
+     */
+    IPage<OrderGiftVisitorDO> getGiftOrderPage(OrderGiftVisitorPageReqVO pageReqVO);
+
+    /**
+     * 签到核销
+     *
+     */
+    void signOrderGiftVisitor(OrderGiftVisitorSaveReqVO signReqVO);
+
+    /**
+     * 清除签到信息
+     *
+     * @param id 游客ID
+     */
+    void cleanSign(Long id);
+
+    /**
+     * 批量签到核销(逐个调用单个签到逻辑)
+     *
+     * @param items 签到信息列表
+     * @param signRemark 签到备注
+     * @return 成功核销的人数
+     */
+    Integer batchSignOrderGiftVisitor(List<OrderJzDetailBatchSignReqVO.SignItem> items, String signRemark);
+
+
+
+
+    /**
+     * 创建蹭送行程分车(单个)
+     *
+     * @param createReqVO 创建信息(包含游客ID)
+     * @return 分车ID
+     */
+    Long createGiftDispatch(OrderJzDispatchSaveReqVO createReqVO, Long visitorId);
+
+    /**
+     * 批量保存蹭送行程分车
+     * 复用 trade_order_jz_dispatch 表,source_type=2
+     *
+     * @param batchReqVO 批量分车信息
+     * @return 成功数量
+     */
+    Integer batchSaveGiftDispatch(OrderJzDispatchBatchReqVO batchReqVO);
+
+    /**
+     * 更新蹭送行程分车
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateGiftDispatch(OrderJzDispatchSaveReqVO updateReqVO);
+
+    /**
+     * 删除蹭送行程分车(根据ID)
+     *
+     * @param id ID
+     */
+    void deleteGiftDispatchByVisitorId(Long id);
+
+    /**
+     * 获得蹭送行程分车记录分页(按分车号分组)
+     * 复用 trade_order_jz_dispatch 表,source_type=2
+     *
+     * @param pageReqVO 分页查询条件
+     * @return 分车记录分页
+     */
+    PageResult<OrderJzDispatchRecordRespVO> getGiftDispatchRecordPage(OrderJzDispatchPageReqVO pageReqVO);
+
+    /**
+     * 导出蹭送行程分车记录
+     *
+     * @param pageReqVO 查询条件
+     * @return 导出列表
+     */
+    List<OrderJzDispatchRecordRespVO> getExportGiftDispatchList(OrderJzDispatchPageReqVO pageReqVO);
+}

+ 474 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/orderjzdetail/OrderGiftVisitorServiceImpl.java

@@ -0,0 +1,474 @@
+package com.yc.ship.module.trade.service.orderjzdetail;
+
+import cn.hutool.core.date.DatePattern;
+import com.alibaba.excel.util.DateUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.trade.controller.admin.orderjzdetail.vo.OrderGiftVisitorPageReqVO;
+import com.yc.ship.module.trade.controller.admin.orderjzdetail.vo.*;
+import com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO;
+import com.yc.ship.module.trade.dal.dataobject.orderjzdispatch.OrderJzDispatchDO;
+import com.yc.ship.module.trade.dal.mysql.orderjz.OrderGiftVisitorMapper;
+import com.yc.ship.module.trade.dal.mysql.orderjzdispatch.OrderJzDispatchMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 蹭送行程游客 Service 实现类
+ *
+ * @author yc
+ */
+@Service
+@Validated
+@Slf4j
+public class OrderGiftVisitorServiceImpl implements OrderGiftVisitorService {
+
+    @Resource
+    private OrderGiftVisitorMapper orderGiftVisitorMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createOrderGiftVisitor(OrderGiftVisitorSaveReqVO createReqVO) {
+        // 校验唯一性
+        OrderGiftVisitorDO existing = orderGiftVisitorMapper.selectByVisitorIdAndVoyageId(
+            createReqVO.getVisitorId(), createReqVO.getVoyageId());
+        if (existing != null) {
+            throw new RuntimeException("该游客已存在蹭送行程记录");
+        }
+
+        // 插入
+        OrderGiftVisitorDO orderGiftVisitor = OrderGiftVisitorDO.builder()
+                .voyageId(createReqVO.getVoyageId())
+                .visitorId(createReqVO.getVisitorId())
+                .orderId(createReqVO.getOrderId())
+                .dispatchId(createReqVO.getDispatchId() != null ? createReqVO.getDispatchId() : 0L)
+                .address(createReqVO.getAddress())
+                .arriveTime(createReqVO.getArriveTime())
+                .signRemark(createReqVO.getSignRemark())
+                .signImage(createReqVO.getSignImage())
+                .remark(createReqVO.getRemark())
+                .build();
+        orderGiftVisitorMapper.insert(orderGiftVisitor);
+        return orderGiftVisitor.getId();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Integer batchCreateOrderGiftVisitor(List<OrderGiftVisitorSaveReqVO> createReqVOList) {
+        if (createReqVOList == null || createReqVOList.isEmpty()) {
+            return 0;
+        }
+
+        int successCount = 0;
+        for (OrderGiftVisitorSaveReqVO createReqVO : createReqVOList) {
+            try {
+                createOrderGiftVisitor(createReqVO);
+                successCount++;
+            } catch (Exception e) {
+                log.warn("批量创建蹭送行程游客失败: visitorId={}, voyageId={}", 
+                    createReqVO.getVisitorId(), createReqVO.getVoyageId(), e);
+            }
+        }
+        return successCount;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateOrderGiftVisitor(OrderGiftVisitorSaveReqVO updateReqVO) {
+        // 校验存在
+        validateOrderGiftVisitorExists(updateReqVO.getId());
+        
+        // 更新
+        OrderGiftVisitorDO updateObj = OrderGiftVisitorDO.builder()
+                .id(updateReqVO.getId())
+                .voyageId(updateReqVO.getVoyageId())
+                .visitorId(updateReqVO.getVisitorId())
+                .orderId(updateReqVO.getOrderId())
+                .dispatchId(updateReqVO.getDispatchId() != null ? updateReqVO.getDispatchId() : 0L)
+                .address(updateReqVO.getAddress())
+                .arriveTime(updateReqVO.getArriveTime())
+                .signRemark(updateReqVO.getSignRemark())
+                .signImage(updateReqVO.getSignImage())
+                .remark(updateReqVO.getRemark())
+                .build();
+        orderGiftVisitorMapper.updateById(updateObj);
+    }
+
+
+
+    private void validateOrderGiftVisitorExists(Long id) {
+        if (orderGiftVisitorMapper.selectById(id) == null) {
+            throw new RuntimeException("蹭送行程游客记录不存在");
+        }
+    }
+
+    @Override
+    public OrderGiftVisitorDO getOrderGiftVisitor(Long id) {
+        return orderGiftVisitorMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<OrderGiftVisitorDO> getOrderGiftVisitorPage(OrderGiftVisitorPageReqVO pageReqVO) {
+        IPage<OrderGiftVisitorDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
+        IPage<OrderGiftVisitorDO> resultPage = orderGiftVisitorMapper.selectPageWithVisitor(page, pageReqVO);
+        return new PageResult<>(resultPage.getRecords(), resultPage.getTotal());
+    }
+
+    @Override
+    public List<OrderGiftVisitorDO> getExportList(OrderGiftVisitorPageReqVO pageReqVO) {
+        return orderGiftVisitorMapper.selectExportList(pageReqVO);
+    }
+
+    @Override
+    public IPage<OrderGiftVisitorDO> getGiftOrderPage(OrderGiftVisitorPageReqVO pageReqVO) {
+        // 复用分页查询方法,只用于补登订单查询
+        IPage<OrderGiftVisitorDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
+        return orderGiftVisitorMapper.selectPageWithVisitor(page, pageReqVO);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void signOrderGiftVisitor(OrderGiftVisitorSaveReqVO signReqVO) {
+        // 校验存在
+        // validateOrderGiftVisitorExists(id);
+
+
+        if (signReqVO.getId() == null || signReqVO.getId() == 0) {
+            OrderGiftVisitorDO insertObj = OrderGiftVisitorDO.builder()
+                    .signTime(DateUtils.format(new Date(), DatePattern.NORM_DATETIME_PATTERN))
+                    .signRemark(signReqVO.getSignRemark())
+                    .signImage(signReqVO.getSignImage())
+                    .visitorId(signReqVO.getVisitorId())
+                    .voyageId(signReqVO.getVoyageId())
+                    .orderId(signReqVO.getOrderId())
+                    .build();
+            orderGiftVisitorMapper.insert(insertObj);
+        } else {
+            // 更新签到信息
+            OrderGiftVisitorDO updateObj = OrderGiftVisitorDO.builder()
+                    .id(signReqVO.getId())
+                    .signTime(DateUtils.format(new Date(), DatePattern.NORM_DATETIME_PATTERN))
+                    .signRemark(signReqVO.getSignRemark())
+                    .signImage(signReqVO.getSignImage())
+                    .visitorId(signReqVO.getVisitorId())
+                    .voyageId(signReqVO.getVoyageId())
+                    .orderId(signReqVO.getOrderId())
+                    .build();
+            orderGiftVisitorMapper.updateById(updateObj);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void cleanSign(Long id) {
+        // 校验存在
+        validateOrderGiftVisitorExists(id);
+        
+        // 清除签到信息
+        orderGiftVisitorMapper.cleanSignById(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Integer batchSignOrderGiftVisitor(List<OrderJzDetailBatchSignReqVO.SignItem> items, String signRemark) {
+        if (items == null || items.isEmpty()) {
+            return 0;
+        }
+
+        // 批量查询所有记录ID(只查有id的,即已存在的记录),过滤已核销的
+        List<Long> ids = items.stream()
+                .filter(item -> item.getId() != null && item.getId() > 0)
+                .map(OrderJzDetailBatchSignReqVO.SignItem::getId)
+                .collect(Collectors.toList());
+        List<Long> alreadySignedIds = Collections.emptyList();
+        if (!ids.isEmpty()) {
+            List<OrderGiftVisitorDO> visitorList = orderGiftVisitorMapper.selectBatchIds(ids);
+            alreadySignedIds = visitorList.stream()
+                    .filter(v -> v.getSignTime() != null)
+                    .map(OrderGiftVisitorDO::getId)
+                    .collect(Collectors.toList());
+        }
+        // 过滤掉已核销的条目,只处理未核销的
+        final List<Long> signedIds = alreadySignedIds;
+        List<OrderJzDetailBatchSignReqVO.SignItem> unsignedItems = items.stream()
+                .filter(item -> item.getId() == null || item.getId() == 0 || !signedIds.contains(item.getId()))
+                .collect(Collectors.toList());
+        if (unsignedItems.isEmpty()) {
+            return 0;
+        }
+
+        int successCount = 0;
+        for (OrderJzDetailBatchSignReqVO.SignItem item : unsignedItems) {
+            try {
+                // 构造单个签到的请求VO,复用单个签到逻辑
+                OrderGiftVisitorSaveReqVO signReqVO = new OrderGiftVisitorSaveReqVO();
+                signReqVO.setId(item.getId());
+                signReqVO.setVisitorId(item.getVisitorId());
+                signReqVO.setVoyageId(item.getVoyageId());
+                signReqVO.setOrderId(item.getOrderId());
+                signReqVO.setSignRemark(signRemark);
+                // 执行单个签到
+                signOrderGiftVisitor(signReqVO);
+                successCount++;
+            } catch (Exception e) {
+                log.warn("批量签到失败: visitorId={}, orderId={}", item.getVisitorId(), item.getOrderId(), e);
+            }
+        }
+        log.info("批量签到完成: 成功={}, 请求={}", successCount, items.size());
+        return successCount;
+    }
+
+
+
+
+    @Resource
+    private OrderJzDispatchMapper orderJzDispatchMapper;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createGiftDispatch(OrderJzDispatchSaveReqVO createReqVO, Long visitorId) {
+        // 创建分车记录(source_type=2)
+        OrderJzDispatchDO dispatchDO = OrderJzDispatchDO.builder()
+                .voyageId(createReqVO.getVoyageId())
+                .dispatchNo(createReqVO.getDispatchNo())
+                .groupNo(createReqVO.getGroupNo())
+                .busNumber(createReqVO.getBusNumber())
+                .driverName(createReqVO.getDriverName())
+                .driverPhone(createReqVO.getDriverPhone())
+                .receiverName(createReqVO.getReceiverName())
+                .receiverPhone(createReqVO.getReceiverPhone())
+                .sourceType(2) // 蹭送行程
+                .passengerCount(1)
+                .remark(createReqVO.getRemark())
+                .dispatchTime(LocalDateTime.now())
+                .build();
+        orderJzDispatchMapper.insert(dispatchDO);
+
+        // 更新蹭送行程游客的分车ID
+        OrderGiftVisitorDO visitorDO = orderGiftVisitorMapper.selectByVisitorIdAndVoyageId(
+                visitorId, createReqVO.getVoyageId());
+        if (visitorDO != null) {
+            OrderGiftVisitorDO updateVisitor = OrderGiftVisitorDO.builder()
+                    .id(visitorDO.getId())
+                    .dispatchId(dispatchDO.getId())
+                    .build();
+            orderGiftVisitorMapper.updateById(updateVisitor);
+        }
+
+        return dispatchDO.getId();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Integer batchSaveGiftDispatch(OrderJzDispatchBatchReqVO batchReqVO) {
+        if (batchReqVO.getOrderItems() == null || batchReqVO.getOrderItems().isEmpty()) {
+            return 0;
+        }
+
+        OrderJzDispatchBatchReqVO.DispatchInfo dispatchInfo = batchReqVO.getDispatchInfo();
+        if (dispatchInfo == null) {
+            throw new RuntimeException("分车信息不能为空");
+        }
+
+        // 确保source_type=2(蹭送行程)
+        dispatchInfo.setSourceType(2);
+
+        // 查找是否已有相同分车号、航次、分车类型的分车记录
+        LambdaQueryWrapper<OrderJzDispatchDO> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(OrderJzDispatchDO::getDispatchNo, dispatchInfo.getDispatchNo())
+                .eq(OrderJzDispatchDO::getVoyageId, dispatchInfo.getVoyageId())
+                .eq(OrderJzDispatchDO::getSourceType, 2);
+
+        if (dispatchInfo.getGroupNo() != null && !dispatchInfo.getGroupNo().isEmpty()) {
+            wrapper.eq(OrderJzDispatchDO::getGroupNo, dispatchInfo.getGroupNo());
+        }
+
+        OrderJzDispatchDO existingDispatch = orderJzDispatchMapper.selectOne(wrapper);
+        Long dispatchId;
+
+        if (existingDispatch != null) {
+            // 更新已有分车记录
+            dispatchId = existingDispatch.getId();
+            OrderJzDispatchDO updateDispatch = OrderJzDispatchDO.builder()
+                    .id(dispatchId)
+                    .busNumber(dispatchInfo.getBusNumber())
+                    .driverName(dispatchInfo.getDriverName())
+                    .driverPhone(dispatchInfo.getDriverPhone())
+                    .receiverName(dispatchInfo.getReceiverName())
+                    .receiverPhone(dispatchInfo.getReceiverPhone())
+                    .passengerCount(existingDispatch.getPassengerCount() + batchReqVO.getOrderItems().size())
+                    .remark(dispatchInfo.getRemark())
+                    .build();
+            orderJzDispatchMapper.updateById(updateDispatch);
+        } else {
+            // 创建新的分车记录
+            OrderJzDispatchDO newDispatch = OrderJzDispatchDO.builder()
+                    .voyageId(dispatchInfo.getVoyageId())
+                    .dispatchNo(dispatchInfo.getDispatchNo())
+                    .groupNo(dispatchInfo.getGroupNo())
+                    .busNumber(dispatchInfo.getBusNumber())
+                    .driverName(dispatchInfo.getDriverName())
+                    .driverPhone(dispatchInfo.getDriverPhone())
+                    .receiverName(dispatchInfo.getReceiverName())
+                    .receiverPhone(dispatchInfo.getReceiverPhone())
+                    .sourceType(2)
+                    .passengerCount(batchReqVO.getOrderItems().size())
+                    .remark(dispatchInfo.getRemark())
+                    .dispatchTime(LocalDateTime.now())
+                    .build();
+            orderJzDispatchMapper.insert(newDispatch);
+            dispatchId = newDispatch.getId();
+        }
+
+        // 批量更新蹭送行程游客的分车ID
+        int successCount = 0;
+        for (OrderJzDispatchBatchReqVO.OrderItem orderItem : batchReqVO.getOrderItems()) {
+            try {
+                Long visitorRecordId = orderItem.getId();
+                // 如果id为空或0,先按visitorId+voyageId查询是否已有记录
+                if (visitorRecordId == null || visitorRecordId == 0) {
+                    OrderGiftVisitorDO existing = orderGiftVisitorMapper.selectByVisitorIdAndVoyageId(
+                            orderItem.getVisitorId(), orderItem.getVoyageId());
+                    if (existing != null) {
+                        visitorRecordId = existing.getId();
+                    } else {
+                        // 不存在则新增
+                        OrderGiftVisitorSaveReqVO createReqVO = new OrderGiftVisitorSaveReqVO();
+                        createReqVO.setVisitorId(orderItem.getVisitorId());
+                        createReqVO.setVoyageId(orderItem.getVoyageId());
+                        createReqVO.setOrderId(orderItem.getOrderId());
+                        visitorRecordId = createOrderGiftVisitor(createReqVO);
+                    }
+                }
+
+                // 校验是否已分车
+                OrderGiftVisitorDO visitorDO = orderGiftVisitorMapper.selectById(visitorRecordId);
+                if (visitorDO != null && visitorDO.getDispatchId() != null && visitorDO.getDispatchId() > 0) {
+                    log.warn("游客已分车: visitorRecordId={}", visitorRecordId);
+                    continue;
+                }
+
+                // 更新分车ID
+                OrderGiftVisitorDO updateVisitor = OrderGiftVisitorDO.builder()
+                        .id(visitorRecordId)
+                        .dispatchId(dispatchId)
+                        .build();
+                orderGiftVisitorMapper.updateById(updateVisitor);
+                successCount++;
+            } catch (Exception e) {
+                log.error("批量分车失败: visitorId={}", orderItem.getVisitorId(), e);
+            }
+        }
+
+        return successCount;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateGiftDispatch(OrderJzDispatchSaveReqVO updateReqVO) {
+        // 更新分车记录
+        OrderJzDispatchDO updateDispatch = OrderJzDispatchDO.builder()
+                .id(updateReqVO.getId())
+                .busNumber(updateReqVO.getBusNumber())
+                .driverName(updateReqVO.getDriverName())
+                .driverPhone(updateReqVO.getDriverPhone())
+                .receiverName(updateReqVO.getReceiverName())
+                .receiverPhone(updateReqVO.getReceiverPhone())
+                .remark(updateReqVO.getRemark())
+                .build();
+        orderJzDispatchMapper.updateById(updateDispatch);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteGiftDispatchByVisitorId(Long id) {
+        // 查询游客的分车记录
+        OrderGiftVisitorDO visitorDO = orderGiftVisitorMapper.selectById(id);
+        if (visitorDO == null || visitorDO.getDispatchId() == null || visitorDO.getDispatchId() == 0) {
+            throw new RuntimeException("游客未分车");
+        }
+
+        Long dispatchId = visitorDO.getDispatchId();
+        // 更新游客的分车ID为0
+        OrderGiftVisitorDO updateVisitor = OrderGiftVisitorDO.builder()
+                .id(id)
+                .dispatchId(0L)
+                .build();
+        orderGiftVisitorMapper.updateById(updateVisitor);
+
+
+        // 统计该分车记录还有多少游客
+        Integer count = orderGiftVisitorMapper.countByDispatchId(dispatchId);
+        if (count == 0) {
+            // 如果没有游客了,物理删除分车记录
+            orderJzDispatchMapper.deleteById(dispatchId);
+        } else {
+            // 减少乘客人数
+            OrderJzDispatchDO dispatchDO = orderJzDispatchMapper.selectById(dispatchId);
+            if (dispatchDO != null) {
+                OrderJzDispatchDO updateDispatch = OrderJzDispatchDO.builder()
+                        .id(dispatchId)
+                        .passengerCount(Math.max(1, count))
+                        .build();
+                orderJzDispatchMapper.updateById(updateDispatch);
+            }
+        }
+    }
+
+    @Override
+    public PageResult<OrderJzDispatchRecordRespVO> getGiftDispatchRecordPage(OrderJzDispatchPageReqVO pageReqVO) {
+        // 查询 source_type=2 的分车记录
+        LambdaQueryWrapper<OrderJzDispatchDO> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(OrderJzDispatchDO::getSourceType, 2)
+                .eq(OrderJzDispatchDO::getVoyageId, pageReqVO.getVoyageId());
+
+        if (pageReqVO.getDispatchNo() != null && !pageReqVO.getDispatchNo().isEmpty()) {
+            wrapper.like(OrderJzDispatchDO::getDispatchNo, pageReqVO.getDispatchNo());
+        }
+
+        if (pageReqVO.getGroupNo() != null && !pageReqVO.getGroupNo().isEmpty()) {
+            wrapper.eq(OrderJzDispatchDO::getGroupNo, pageReqVO.getGroupNo());
+        }
+
+        wrapper.orderByDesc(OrderJzDispatchDO::getDispatchTime);
+
+        List<OrderJzDispatchDO> list = orderJzDispatchMapper.selectList(wrapper);
+
+        // 转换为VO
+        List<OrderJzDispatchRecordRespVO> voList = list.stream()
+                .map(dispatch -> OrderJzDispatchRecordRespVO.builder()
+                        .id(dispatch.getId())
+                        .dispatchNo(dispatch.getDispatchNo())
+                        .groupNo(dispatch.getGroupNo())
+                        .busNumber(dispatch.getBusNumber())
+                        .driverName(dispatch.getDriverName())
+                        .driverPhone(dispatch.getDriverPhone())
+                        .receiverName(dispatch.getReceiverName())
+                        .receiverPhone(dispatch.getReceiverPhone())
+                        .passengerCount(dispatch.getPassengerCount())
+                        .remark(dispatch.getRemark())
+                        .build())
+                .collect(Collectors.toList());
+
+        return new PageResult<>(voList, (long) voList.size());
+    }
+
+    @Override
+    public List<OrderJzDispatchRecordRespVO> getExportGiftDispatchList(OrderJzDispatchPageReqVO pageReqVO) {
+        PageResult<OrderJzDispatchRecordRespVO> pageResult = getGiftDispatchRecordPage(pageReqVO);
+        return pageResult.getList();
+    }
+}

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

@@ -2560,7 +2560,7 @@
     <select id="selectTotal2ByOrderIds"
             resultType="com.yc.ship.module.trade.controller.admin.order.vo.order.OrderTotalRespVO">
         SELECT
-        ifnull( sum( CASE WHEN type = 'adultTake' OR type = 'adultPlus' THEN num ELSE 0 END ), 0 ) AS adultTotalNum,
+        ifnull( sum( CASE WHEN type = 'adultTake' OR type = 'adultPlus' or type IS NULL or type = '' THEN num ELSE 0 END ), 0 ) AS adultTotalNum,
         ifnull( sum( CASE WHEN type = 'childTake' OR type = 'childNonTake' OR type = 'childPlus' THEN num ELSE 0 END ), 0 ) AS childTotalNum,
         ifnull( sum( CASE WHEN type = 'babyTake' OR type = 'babyNonTake' OR type = 'babyPlus' THEN num ELSE 0 END ), 0 ) AS babyTotalNum,
         ifnull( sum( CASE WHEN type = 'leader' THEN num ELSE 0 END ), 0 ) AS leaderTotalNum,

+ 173 - 0
ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/orderjzdetail/OrderGiftVisitorMapper.xml

@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.yc.ship.module.trade.dal.mysql.orderjz.OrderGiftVisitorMapper">
+
+    <!-- 分页查询蹭送行程游客 -->
+    <select id="selectPageWithVisitor" resultType="com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO">
+        SELECT
+            gfv.id as id,
+        gfv.sign_time as signTime,
+        gfv.dispatch_id as dispatchId,
+        v.id as visitorId,
+        o.voyage_id as voyageId,
+        v.order_id as orderId,
+        v.name as name,
+            v.credential_no as idCard,
+            v.mobile as phone,
+            v.room_model_id,
+            rm.name as roomModelName,
+            o.order_no,
+            SUBSTRING_INDEX(o.order_no, '-', -1) as orderNo,
+            r.direction,
+            dj.dispatch_no as dispatchNo,
+            dj.group_no as groupNo,
+            dj.bus_number as busNumber,
+            dj.driver_name as driverName,
+            dj.driver_phone as driverPhone,
+            dj.receiver_name as receiverName,
+            dj.receiver_phone as receiverPhone,
+              dj.remark as dispatchRemark,
+             gfv.sign_remark as remark
+        FROM trade_visitor v
+        LEFT JOIN  trade_order_jz_gift_visitor gfv ON gfv.visitor_id = v.id
+        INNER JOIN trade_order o ON v.order_id = o.id
+        INNER JOIN product_voyage pv ON o.voyage_id = pv.id
+        inner join trade_detail td on td.order_id = o.id and td.visitor_id = v.id  and td.product_id = 2034458675435925505 and td.deleted = 0
+        INNER JOIN resource_route r ON pv.route_id = r.id
+        LEFT JOIN resource_room_model rm ON v.room_model_id = rm.id
+        LEFT JOIN trade_order_jz_dispatch dj ON gfv.dispatch_id = dj.id AND dj.source_type = 2
+        WHERE v.deleted = 0 AND o.deleted = 0 AND pv.deleted = 0
+        AND o.voyage_id = #{vo.voyageId}
+        <if test="vo.idCard != null and vo.idCard != ''">
+            AND v.credential_no LIKE CONCAT('%', #{vo.idCard}, '%')
+        </if>
+        <if test="vo.name != null and vo.name != ''">
+            AND v.name LIKE CONCAT('%', #{vo.name}, '%')
+        </if>
+        <if test="vo.address != null and vo.address != ''">
+            AND gfv.address = #{vo.address}
+        </if>
+        <if test="vo.arriveTime != null and vo.arriveTime != ''">
+            AND gfv.arrive_time = #{vo.arriveTime}
+        </if>
+        <if test="vo.dispatchNo != null and vo.dispatchNo != ''">
+            AND dj.dispatch_no LIKE CONCAT('%', #{vo.dispatchNo}, '%')
+        </if>
+        <if test="vo.signStatus != null and vo.signStatus == 1">
+            AND gfv.sign_time IS NOT NULL
+        </if>
+        <if test="vo.signStatus != null and vo.signStatus == 0">
+            AND gfv.sign_time IS NULL
+        </if>
+        <if test="vo.orderNo != null and vo.orderNo != ''">
+            AND o.order_no LIKE CONCAT('%', #{vo.orderNo}, '%')
+        </if>
+        <if test="vo.otaId != null and vo.otaId != ''">
+            AND o.source_id = #{vo.otaId}
+        </if>
+        ORDER BY v.id desc
+    </select>
+
+    <!-- 导出蹭送行程接站明细 -->
+    <select id="selectExportList" resultType="com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO">
+        SELECT
+        gfv.id as id,
+        gfv.sign_time as signTime,
+        gfv.dispatch_id as dispatchId,
+        v.name as name,
+        v.credential_no as idCard,
+        v.mobile as phone,
+        v.room_model_id,
+        rm.name as roomModelName,
+            o.order_no,
+            SUBSTRING_INDEX(o.order_no, '-', -1) as orderNo,
+            r.direction,
+            dj.dispatch_no as dispatchNo,
+            dj.group_no as groupNo,
+            dj.bus_number as busNumber,
+            dj.driver_name as driverName,
+            dj.driver_phone as driverPhone,
+            dj.receiver_name as receiverName,
+            dj.receiver_phone as receiverPhone,
+            dj.remark as dispatchRemark,
+            gfv.sign_remark as remark
+        FROM trade_visitor v
+        LEFT JOIN  trade_order_jz_gift_visitor gfv ON gfv.visitor_id = v.id AND v.deleted = 0
+        INNER JOIN trade_order o ON v.order_id = o.id AND o.deleted = 0
+        inner join trade_detail td on td.order_id = o.id and td.visitor_id = v.id and td.product_id = 2034458675435925505 and td.deleted = 0
+        INNER JOIN product_voyage pv ON o.voyage_id = pv.id AND pv.deleted = 0
+        INNER JOIN resource_route r ON pv.route_id = r.id
+        LEFT JOIN resource_room_model rm ON v.room_model_id = rm.id
+        LEFT JOIN trade_order_jz_dispatch dj ON gfv.dispatch_id = dj.id AND dj.source_type = 2
+        WHERE  o.voyage_id = #{vo.voyageId}
+        <if test="vo.idCard != null and vo.idCard != ''">
+            AND v.credential_no LIKE CONCAT('%', #{vo.idCard}, '%')
+        </if>
+        <if test="vo.name != null and vo.name != ''">
+            AND v.name LIKE CONCAT('%', #{vo.name}, '%')
+        </if>
+        <if test="vo.address != null and vo.address != ''">
+            AND gfv.address = #{vo.address}
+        </if>
+        <if test="vo.arriveTime != null and vo.arriveTime != ''">
+            AND gfv.arrive_time = #{vo.arriveTime}
+        </if>
+        <if test="vo.dispatchNo != null and vo.dispatchNo != ''">
+            AND dj.dispatch_no LIKE CONCAT('%', #{vo.dispatchNo}, '%')
+        </if>
+        <if test="vo.signStatus != null and vo.signStatus == 1">
+            AND gfv.sign_time IS NOT NULL
+        </if>
+        <if test="vo.signStatus != null and vo.signStatus == 0">
+            AND gfv.sign_time IS NULL
+        </if>
+        <if test="vo.orderNo != null and vo.orderNo != ''">
+            AND o.order_no LIKE CONCAT('%', #{vo.orderNo}, '%')
+        </if>
+        <if test="vo.otaId != null and vo.otaId != ''">
+            AND o.source_id = #{vo.otaId}
+        </if>
+        ORDER BY v.id desc
+    </select>
+
+    <!-- 根据分车ID查询蹭送行程游客列表 -->
+    <select id="selectByDispatchId" resultType="com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO">
+        SELECT 
+            gfv.*,
+            v.name,
+            v.credential_no,
+            v.mobile
+        FROM trade_order_jz_gift_visitor gfv
+        INNER JOIN trade_visitor v ON gfv.visitor_id = v.id
+        WHERE gfv.deleted = 0 AND gfv.dispatch_id = #{dispatchId}
+    </select>
+
+    <!-- 根据游客ID和航次ID查询蹭送行程记录 -->
+    <select id="selectByVisitorIdAndVoyageId" resultType="com.yc.ship.module.trade.dal.dataobject.orderjzdetail.OrderGiftVisitorDO">
+        SELECT * 
+        FROM trade_order_jz_gift_visitor
+        WHERE deleted = 0 
+        AND visitor_id = #{visitorId} 
+        AND voyage_id = #{voyageId}
+        LIMIT 1
+    </select>
+
+    <!-- 根据分车ID统计游客人数 -->
+    <select id="countByDispatchId" resultType="java.lang.Integer">
+        SELECT COUNT(*) 
+        FROM trade_order_jz_gift_visitor
+        WHERE deleted = 0 
+        AND dispatch_id = #{dispatchId}
+    </select>
+
+    <!-- 清除签到信息 -->
+    <update id="cleanSignById">
+        UPDATE trade_order_jz_gift_visitor
+        SET sign_time = NULL,
+            sign_man = NULL,
+            sign_remark = NULL,
+            sign_image = NULL
+        WHERE id = #{id} AND deleted = 0
+    </update>
+
+</mapper>

+ 86 - 45
ship-module-trade/ship-module-trade-biz/src/main/resources/mapper/report/BankTransactionDetailsMapper.xml

@@ -35,19 +35,19 @@
             SELECT
                 DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
                 DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
-        IFNULL(o1.order_no,o2.order_no) AS orderNo,
-        IFNULL(o1.source_name,o2.source_name) AS travelAgencyName,
+               o1.order_no AS orderNo,
+                o1.source_name AS travelAgencyName,
                 pay.payment_type AS paymentMethod,
                 1 AS transactionType,
                 pay.pay_amount AS amount,
                 IFNULL(pay.payment_no, '') AS bankSerialNo
             FROM trade_order_pay pay
         LEFT JOIN trade_order o1 ON pay.order_id = o1.id AND o1.deleted = 0
-        LEFT JOIN trade_order o2 ON o1.id IS NULL AND pay.pos_no = o2.order_no AND o2.deleted = 0
-            LEFT JOIN product_voyage voy ON IFNULL(o1.voyage_id, o2.voyage_id) = voy.id AND voy.deleted = 0
+            LEFT JOIN product_voyage voy ON o1.voyage_id = voy.id AND voy.deleted = 0
             WHERE pay.deleted = 0
               AND pay.pay_status = 1
             AND pay.payment_type in (1,2,3,4,5,6,9,10)
+            AND pay.sell_method != 102
        /* --- and o.order_status in (3,6,7,8,9,10,12,13,15)
         -- AND pay.refund_amount = 0*/
         UNION ALL
@@ -70,6 +70,28 @@
               AND pay.pay_status = 1
               AND tr.refund_status = 6
 
+        UNION ALL
+
+        SELECT
+        DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
+        DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
+        pay.bill_no AS orderNo,
+        IFNULL(bill.agency_name,'')  AS travelAgencyName,
+        pay.payment_type AS paymentMethod,
+        2 AS transactionType,
+        -IFNULL(pay.refund_amount, 0) AS amount,
+        IFNULL(pay.payment_no, '') AS bankSerialNo
+        FROM trade_order_pay pay
+        LEFT JOIN ota_bill bill ON bill.id = pay.order_id AND bill.deleted = 0
+        LEFT JOIN (select r.bill_id ,r.order_id FROM ota_bill_order r where r.deleted = 0 GROUP BY r.bill_id) obo ON obo.bill_id = bill.id
+        LEFT JOIN  trade_order o ON obo.order_id = o.id and o.deleted = 0
+        LEFT JOIN product_voyage voy ON o.voyage_id = voy.id AND voy.deleted = 0
+        WHERE pay.deleted = 0
+        AND pay.pay_status = 1
+        AND bill.bill_status in (1,2)
+        AND pay.payment_type = 5
+        and pay.refund_amount > 0
+
             UNION ALL
 
             <!-- 3. 充值记录(分销商在线充值) -->
@@ -94,44 +116,42 @@
             UNION ALL*/
 
             <!-- 4. 后台充值记录 -->
-            SELECT
-                DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
-                 DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
-                 pay.bill_no AS orderNo,
-                IFNULL(d.name, '') AS travelAgencyName,
-                 pay.payment_type AS paymentMethod,
-                3 AS transactionType,
-                pay.pay_amount AS amount,
-                '' AS bankSerialNo
-            FROM ota_distributor_recharge r
-            INNER JOIN ota_distributor d ON r.distributor_id = d.id AND d.deleted = 0
-            INNER JOIN ota_trade_log tl ON r.recharge_log_id = tl.id AND tl.deleted = 0 AND tl.trade_type = 1
-           left join trade_order_pay pay on pay.order_id = tl.order_id
-        LEFT JOIN trade_order o ON pay.order_id = o.id AND o.deleted = 0
-        LEFT JOIN product_voyage voy ON o.voyage_id = voy.id AND voy.deleted = 0
-            WHERE r.deleted = 0
-              AND r.status = 1
+        SELECT
+        DATE_FORMAT(tl.trade_time, '%Y-%m-%d %H:%i:%s') AS transactionTime,
+        '' AS boardingTime,
+        '' AS orderNo,
+        IFNULL(d.name, '') AS travelAgencyName,
+        5 AS paymentMethod,
+        3 AS transactionType,
+        r.money AS amount,
+        '' AS bankSerialNo
+        FROM ota_distributor_recharge r
+        right JOIN ota_distributor d ON r.distributor_id = d.id AND d.deleted = 0
+        right JOIN ota_trade_log tl ON r.recharge_log_id = tl.id AND tl.deleted = 0 AND tl.trade_type in (1,2)
+        WHERE r.deleted = 0
+        AND r.status = 1
 
             UNION ALL
 
             <!-- 5. 账单还款记录 -->
         SELECT
         DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
-        '' AS boardingTime,
+        DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
         pay.bill_no AS orderNo,
-        IFNULL(o1.source_name, o2.source_name)  AS travelAgencyName,
+        IFNULL(bill.agency_name, '')  AS travelAgencyName,
         pay.payment_type AS paymentMethod,
         4 AS transactionType,
         pay.pay_amount AS amount,
         IFNULL(pay.payment_no, '') AS bankSerialNo
         FROM trade_order_pay pay
-        LEFT JOIN trade_order o1 ON pay.order_id = o1.id AND o1.deleted = 0
-        LEFT JOIN trade_order o2 ON o1.id IS NULL AND pay.pos_no = o2.order_no AND o2.deleted = 0
-        LEFT JOIN ota_bill_order obo ON obo.order_id = IFNULL(o1.id, o2.id)
-        INNER JOIN ota_bill bill ON bill.id = obo.bill_id AND bill.deleted = 0
+        LEFT JOIN ota_bill bill ON bill.id = pay.order_id AND bill.deleted = 0
+        LEFT JOIN (select r.bill_id ,r.order_id FROM ota_bill_order r where r.deleted = 0 GROUP BY r.bill_id) obo ON obo.bill_id = bill.id
+        LEFT JOIN  trade_order o ON obo.order_id = o.id and o.deleted = 0
+        LEFT JOIN product_voyage voy ON o.voyage_id = voy.id AND voy.deleted = 0
         WHERE pay.deleted = 0
         AND pay.pay_status = 1
         AND bill.bill_status in (1,2)
+        AND pay.sell_method = 102
         ) t
         WHERE 1 = 1
         <include refid="queryConditions"/>
@@ -146,20 +166,21 @@
         SELECT
         DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
         DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
-        IFNULL(o1.order_no,o2.order_no) AS orderNo,
-        IFNULL(o1.source_name,o2.source_name) AS travelAgencyName,
+        o1.order_no AS orderNo,
+        o1.source_name AS travelAgencyName,
         pay.payment_type AS paymentMethod,
         1 AS transactionType,
         pay.pay_amount AS amount,
         IFNULL(pay.payment_no, '') AS bankSerialNo
         FROM trade_order_pay pay
         LEFT JOIN trade_order o1 ON pay.order_id = o1.id AND o1.deleted = 0
-        LEFT JOIN trade_order o2 ON o1.id IS NULL AND pay.pos_no = o2.order_no AND o2.deleted = 0
-        LEFT JOIN product_voyage voy ON IFNULL(o1.voyage_id, o2.voyage_id) = voy.id AND voy.deleted = 0
+        LEFT JOIN product_voyage voy ON o1.voyage_id = voy.id AND voy.deleted = 0
         WHERE pay.deleted = 0
         AND pay.pay_status = 1
         AND pay.payment_type in (1,2,3,4,5,6,9,10)
-      /*  -- and o.order_status in (3,6,7,8,9,10,12,13,15)
+        AND pay.sell_method != 102
+
+        /*  -- and o.order_status in (3,6,7,8,9,10,12,13,15)
         -- AND pay.refund_amount = 0*/
 
         UNION ALL
@@ -183,22 +204,40 @@
               AND tr.refund_status = 6
             UNION ALL
 
-            <!-- 3. 充值记录(分销商在线充值) -->
+
         SELECT
         DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
         DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
         pay.bill_no AS orderNo,
-        IFNULL(d.name, '') AS travelAgencyName,
+        IFNULL(bill.agency_name,'')  AS travelAgencyName,
         pay.payment_type AS paymentMethod,
+        2 AS transactionType,
+        -IFNULL(pay.refund_amount, 0) AS amount,
+        IFNULL(pay.payment_no, '') AS bankSerialNo
+        FROM trade_order_pay pay
+        LEFT JOIN ota_bill bill ON bill.id = pay.order_id AND bill.deleted = 0
+        LEFT JOIN (select r.bill_id ,r.order_id FROM ota_bill_order r where r.deleted = 0 GROUP BY r.bill_id) obo ON obo.bill_id = bill.id
+        LEFT JOIN  trade_order o ON obo.order_id = o.id and o.deleted = 0
+        LEFT JOIN product_voyage voy ON o.voyage_id = voy.id AND voy.deleted = 0
+        WHERE pay.deleted = 0
+        AND pay.pay_status = 1
+        AND bill.bill_status in (1,2)
+        AND pay.payment_type = 5
+        and pay.refund_amount > 0
+        UNION ALL
+            <!-- 3. 充值记录(分销商在线充值) -->
+        SELECT
+        DATE_FORMAT(tl.trade_time, '%Y-%m-%d %H:%i:%s') AS transactionTime,
+        '' AS boardingTime,
+        '' AS orderNo,
+        IFNULL(d.name, '') AS travelAgencyName,
+        5 AS paymentMethod,
         3 AS transactionType,
-        pay.pay_amount AS amount,
+        r.money AS amount,
         '' AS bankSerialNo
         FROM ota_distributor_recharge r
-        INNER JOIN ota_distributor d ON r.distributor_id = d.id AND d.deleted = 0
-        INNER JOIN ota_trade_log tl ON r.recharge_log_id = tl.id AND tl.deleted = 0 AND tl.trade_type = 1
-        left join trade_order_pay pay on pay.order_id = tl.order_id
-        LEFT JOIN trade_order o ON pay.order_id = o.id AND o.deleted = 0
-        LEFT JOIN product_voyage voy ON o.voyage_id = voy.id AND voy.deleted = 0
+        right JOIN ota_distributor d ON r.distributor_id = d.id AND d.deleted = 0
+        right JOIN ota_trade_log tl ON r.recharge_log_id = tl.id AND tl.deleted = 0 AND tl.trade_type in (1,2)
         WHERE r.deleted = 0
         AND r.status = 1
 
@@ -207,20 +246,22 @@
             <!-- 5. 账单还款记录 -->
         SELECT
         DATE_FORMAT(pay.payment_date, '%Y-%m-%d %H:%i:%s') AS transactionTime,
-        '' AS boardingTime,
+        DATE_FORMAT(voy.start_time, '%Y-%m-%d') AS boardingTime,
         pay.bill_no AS orderNo,
-        o.source_name  AS travelAgencyName,
+        IFNULL(bill.agency_name, '')  AS travelAgencyName,
         pay.payment_type AS paymentMethod,
         4 AS transactionType,
         pay.pay_amount AS amount,
         IFNULL(pay.payment_no, '') AS bankSerialNo
         FROM trade_order_pay pay
-        LEFT JOIN trade_order o ON pay.order_id = o.id AND o.deleted = 0
-        LEFT JOIN ota_bill_order obo ON obo.order_id = o.id
-        INNER JOIN ota_bill bill ON bill.id = obo.bill_id AND bill.deleted = 0
+        LEFT JOIN ota_bill bill ON bill.id = pay.order_id AND bill.deleted = 0
+        LEFT JOIN (select r.bill_id ,r.order_id FROM ota_bill_order r where r.deleted = 0 GROUP BY r.bill_id) obo ON obo.bill_id = bill.id
+        LEFT JOIN  trade_order o ON obo.order_id = o.id and o.deleted = 0
+        LEFT JOIN product_voyage voy ON o.voyage_id = voy.id AND voy.deleted = 0
         WHERE pay.deleted = 0
         AND pay.pay_status = 1
         AND bill.bill_status in (1,2)
+        AND pay.sell_method = 102
         ) t
         WHERE 1 = 1
         <include refid="queryConditions"/>