Quellcode durchsuchen

Merge branch 'hurx'

hurx vor 3 Monaten
Ursprung
Commit
ad6a0c729b
24 geänderte Dateien mit 1560 neuen und 66 gelöschten Zeilen
  1. 11 25
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/OrderStatus.java
  2. 17 0
      ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java
  3. 106 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderDeliverController.java
  4. 106 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderDeliverProductController.java
  5. 114 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderDeliver.java
  6. 77 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderDeliverProduct.java
  7. 108 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderDeliverBo.java
  8. 69 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderDeliverProductBo.java
  9. 84 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderDeliverProductVo.java
  10. 129 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderDeliverVo.java
  11. 2 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderMainVo.java
  12. 13 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderQuantitySummary.java
  13. 15 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderDeliverMapper.java
  14. 22 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderDeliverProductMapper.java
  15. 7 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderProductMapper.java
  16. 70 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderDeliverProductService.java
  17. 70 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderDeliverService.java
  18. 139 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverProductServiceImpl.java
  19. 266 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverServiceImpl.java
  20. 61 40
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java
  21. 1 1
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderDeliverMapper.xml
  22. 20 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderDeliverProductMapper.xml
  23. 0 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderMainMapper.xml
  24. 53 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderProductMapper.xml

+ 11 - 25
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/OrderStatus.java

@@ -8,54 +8,40 @@ import lombok.Getter;
 public enum OrderStatus {
 
     /**
-     * 待收单(初始状态)
+     * 待支付(初始状态)
      */
-    PENDING_RECEIPT("0", "待收单"),
+    PENDING_PAYMENT("0", "待支付"),
 
     /**
-     * 已收单
+     * 待确认(已支付,等待商家处理)
      */
-    RECEIVED("1", "已收单"),
+    PENDING_CONFIRMATION("1", "待确认"),
 
     /**
-     * 待发货
+     * 待发货(商家已确认,准备发货)
      */
     PENDING_SHIPMENT("2", "待发货"),
 
     /**
-     * 部分发货
+     * 部分发货(已发部分商品)
      */
     PARTIALLY_SHIPPED("3", "部分发货"),
 
     /**
-     * 发货完成
+     * 发货完成(所有商品已发出,物流在途)
      */
     SHIPPED("4", "发货完成"),
 
     /**
-     * 待签收
+     * 已完成(全部签收,交易结束)
      */
-    PENDING_SIGN("5", "待签收"),
+    COMPLETED("5", "已完成"),
 
     /**
-     * 部分签收
+     * 已关闭(取消、超时、全额退款等)
      */
-    PARTIALLY_SIGNED("6", "部分签收"),
+    CLOSED("6", "已关闭");
 
-    /**
-     * 签收完成
-     */
-    SIGNED("7", "签收完成"),
-
-    /**
-     * 拒单(客户拒绝)
-     */
-    REJECTED("8", "拒单"),
-
-    /**
-     * 即将逾期收单(预警状态)
-     */
-    ABOUT_TO_EXPIRE("9", "即将逾期收单");
 
     private final String code;
     private final String info;

+ 17 - 0
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java

@@ -192,4 +192,21 @@ public class SequenceUtils {
         return businessKey + paddedSeq;
     }
 
+    /*生成20位发货单号方法*/
+    public static String nextIdDateTimePadded(String prefix) {
+        // 使用精确到分钟的 key,避免单秒内流水号超过9999
+        String timeKey = DateUtil.format(DateUtil.date(), "yyyyMMddHHmm");
+        String businessKey = StringUtils.blankToDefault(prefix, "") + timeKey;
+
+        // 设置过期时间为1小时(或1天),确保key不会永久占用内存
+        Duration expireTime = Duration.ofHours(1);
+
+        // 获取4位补零流水号
+        String paddedSeq = nextPaddedIdStr(businessKey, expireTime, 4);
+
+        // 拼接完整时间(到秒)+ 流水号
+        String fullTime = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_FORMATTER); // yyyyMMddHHmmss
+        return fullTime + paddedSeq;
+    }
+
 }

+ 106 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderDeliverController.java

@@ -0,0 +1,106 @@
+package org.dromara.order.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.order.domain.vo.OrderDeliverVo;
+import org.dromara.order.domain.bo.OrderDeliverBo;
+import org.dromara.order.service.IOrderDeliverService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 订单发货主
+ * 前端访问路由地址为:/system/orderDeliver
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/orderDeliver")
+public class OrderDeliverController extends BaseController {
+
+    private final IOrderDeliverService orderDeliverService;
+
+    /**
+     * 查询订单发货主列表
+     */
+//    @SaCheckPermission("system:orderDeliver:list")
+    @GetMapping("/list")
+    public TableDataInfo<OrderDeliverVo> list(OrderDeliverBo bo, PageQuery pageQuery) {
+        return orderDeliverService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出订单发货主列表
+     */
+//    @SaCheckPermission("system:orderDeliver:export")
+    @Log(title = "订单发货主", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(OrderDeliverBo bo, HttpServletResponse response) {
+        List<OrderDeliverVo> list = orderDeliverService.queryList(bo);
+        ExcelUtil.exportExcel(list, "订单发货主", OrderDeliverVo.class, response);
+    }
+
+    /**
+     * 获取订单发货主详细信息
+     *
+     * @param id 主键
+     */
+//    @SaCheckPermission("system:orderDeliver:query")
+    @GetMapping("/{id}")
+    public R<OrderDeliverVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable("id") Long id) {
+        return R.ok(orderDeliverService.queryById(id));
+    }
+
+    /**
+     * 新增订单发货主
+     */
+//    @SaCheckPermission("system:orderDeliver:add")
+    @Log(title = "订单发货主", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderDeliverBo bo) {
+        return toAjax(orderDeliverService.insertByBo(bo));
+    }
+
+    /**
+     * 修改订单发货主
+     */
+//    @SaCheckPermission("system:orderDeliver:edit")
+    @Log(title = "订单发货主", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody OrderDeliverBo bo) {
+        return toAjax(orderDeliverService.updateByBo(bo));
+    }
+
+    /**
+     * 删除订单发货主
+     *
+     * @param ids 主键串
+     */
+//    @SaCheckPermission("system:orderDeliver:remove")
+    @Log(title = "订单发货主", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(orderDeliverService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 106 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderDeliverProductController.java

@@ -0,0 +1,106 @@
+package org.dromara.order.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.order.domain.vo.OrderDeliverProductVo;
+import org.dromara.order.domain.bo.OrderDeliverProductBo;
+import org.dromara.order.service.IOrderDeliverProductService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 订单发货商品明细
+ * 前端访问路由地址为:/system/deliverProduct
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/deliverProduct")
+public class OrderDeliverProductController extends BaseController {
+
+    private final IOrderDeliverProductService orderDeliverProductService;
+
+    /**
+     * 查询订单发货商品明细列表
+     */
+//    @SaCheckPermission("system:deliverProduct:list")
+    @GetMapping("/list")
+    public TableDataInfo<OrderDeliverProductVo> list(OrderDeliverProductBo bo, PageQuery pageQuery) {
+        return orderDeliverProductService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出订单发货商品明细列表
+     */
+//    @SaCheckPermission("system:deliverProduct:export")
+    @Log(title = "订单发货商品明细", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(OrderDeliverProductBo bo, HttpServletResponse response) {
+        List<OrderDeliverProductVo> list = orderDeliverProductService.queryList(bo);
+        ExcelUtil.exportExcel(list, "订单发货商品明细", OrderDeliverProductVo.class, response);
+    }
+
+    /**
+     * 获取订单发货商品明细详细信息
+     *
+     * @param id 主键
+     */
+//    @SaCheckPermission("system:deliverProduct:query")
+    @GetMapping("/{id}")
+    public R<OrderDeliverProductVo> getInfo(@NotNull(message = "主键不能为空")
+                                            @PathVariable("id") Long id) {
+        return R.ok(orderDeliverProductService.queryById(id));
+    }
+
+    /**
+     * 新增订单发货商品明细
+     */
+//    @SaCheckPermission("system:deliverProduct:add")
+    @Log(title = "订单发货商品明细", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderDeliverProductBo bo) {
+        return toAjax(orderDeliverProductService.insertByBo(bo));
+    }
+
+    /**
+     * 修改订单发货商品明细
+     */
+//    @SaCheckPermission("system:deliverProduct:edit")
+    @Log(title = "订单发货商品明细", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody OrderDeliverProductBo bo) {
+        return toAjax(orderDeliverProductService.updateByBo(bo));
+    }
+
+    /**
+     * 删除订单发货商品明细
+     *
+     * @param ids 主键串
+     */
+//    @SaCheckPermission("system:deliverProduct:remove")
+    @Log(title = "订单发货商品明细", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(orderDeliverProductService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 114 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderDeliver.java

@@ -0,0 +1,114 @@
+package org.dromara.order.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.order.domain.vo.OrderDeliverProductVo;
+import org.dromara.order.domain.vo.OrderDeliverVo;
+
+import java.io.Serial;
+import java.util.List;
+
+/**
+ * 订单发货主对象 order_deliver
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("order_deliver")
+public class OrderDeliver extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 订单编号
+     */
+    private String orderCode;
+
+    /**
+     * 订单发货编号
+     */
+    private String deliverCode;
+
+    /**
+     * 物流包裹号
+     */
+    private String logisticPackNo;
+
+    /**
+     * 发货方式
+     */
+    private String deliverMethod;
+
+    /**
+     * 送货人姓名
+     */
+    private String deliverMan;
+
+    /**
+     * 送货人联系电话
+     */
+    private String phone;
+
+    /**
+     * 物流状态
+     */
+    private String logisticsStatus;
+
+    /**
+     * 发货备注
+     */
+    private String deliverRemark;
+
+    /**
+     * 装箱/验货备注
+     */
+    private String checklistRemark;
+
+    /**
+     * 承运物流公司
+     */
+    private Long logisticsCompany;
+
+    /**
+     * 物流单号
+     */
+    private String logisticNo;
+
+    /**
+     * 包裹状态
+     */
+    private String logisticPackStatus;
+
+    /**
+     * 收货人电话
+     */
+    private String consigneePhone;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+}

+ 77 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderDeliverProduct.java

@@ -0,0 +1,77 @@
+package org.dromara.order.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 订单发货商品明细对象 order_deliver_product
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("order_deliver_product")
+public class OrderDeliverProduct extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 发货单
+     */
+    private Long deliverId;
+
+    /**
+     * 商品编号
+     */
+    private Long productId;
+
+    /**
+     * 产品编号
+     */
+    private String productNo;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 商品单位
+     */
+    private Long productUnitId;
+
+    /**
+     * 商品单位
+     */
+    private String productUnit;
+
+    /**
+     * 本次发货数量
+     */
+    private Long deliverNum;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 108 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderDeliverBo.java

@@ -0,0 +1,108 @@
+package org.dromara.order.domain.bo;
+
+import org.dromara.order.domain.OrderDeliver;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+import java.util.List;
+
+/**
+ * 订单发货主业务对象 order_deliver
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = OrderDeliver.class, reverseConvertGenerate = false)
+public class OrderDeliverBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 订单编号
+     */
+    private String orderCode;
+
+    /**
+     * 订单发货编号
+     */
+    private String deliverCode;
+
+    /**
+     * 物流包裹号
+     */
+    private String logisticPackNo;
+
+    /**
+     * 发货方式
+     */
+    private String deliverMethod;
+
+    /**
+     * 送货人姓名
+     */
+    private String deliverMan;
+
+    /**
+     * 送货人联系电话
+     */
+    private String phone;
+
+    /**
+     * 物流状态
+     */
+    private String logisticsStatus;
+
+    /**
+     * 发货备注
+     */
+    private String deliverRemark;
+
+    /**
+     * 装箱/验货备注
+     */
+    private String checklistRemark;
+
+    /**
+     * 承运物流公司
+     */
+    private Long logisticsCompany;
+
+    /**
+     * 物流单号
+     */
+    private String logisticNo;
+
+    /**
+     * 包裹状态
+     */
+    private String logisticPackStatus;
+
+    /**
+     * 收货人电话
+     */
+    private String consigneePhone;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    private List<OrderDeliverProductBo> orderDeliverProducts;
+
+
+}

+ 69 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderDeliverProductBo.java

@@ -0,0 +1,69 @@
+package org.dromara.order.domain.bo;
+
+import org.dromara.order.domain.OrderDeliverProduct;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 订单发货商品明细业务对象 order_deliver_product
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = OrderDeliverProduct.class, reverseConvertGenerate = false)
+public class OrderDeliverProductBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 发货单
+     */
+    private Long deliverId;
+
+    /**
+     * 商品编号
+     */
+    private Long productId;
+
+    /**
+     * 产品编号(业务编码)
+     */
+    private String productNo;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 商品单位
+     */
+    private Long productUnitId;
+
+    /**
+     * 商品单位
+     */
+    private String productUnit;
+
+    /**
+     * 本次发货数量
+     */
+    private Long deliverNum;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 84 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderDeliverProductVo.java

@@ -0,0 +1,84 @@
+package org.dromara.order.domain.vo;
+
+import org.dromara.order.domain.OrderDeliverProduct;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 订单发货商品明细视图对象 order_deliver_product
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = OrderDeliverProduct.class)
+public class OrderDeliverProductVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 发货单
+     */
+    @ExcelProperty(value = "发货单")
+    private Long deliverId;
+
+    /**
+     * 商品编号
+     */
+    @ExcelProperty(value = "商品编号")
+    private Long productId;
+
+    /**
+     * 产品编号(业务编码)
+     */
+    private String productNo;
+
+    /**
+     * 商品名称
+     */
+    @ExcelProperty(value = "商品名称")
+    private String productName;
+
+    /**
+     * 商品单位
+     */
+    @ExcelProperty(value = "商品单位")
+    private Long productUnitId;
+
+    /**
+     * 商品单位
+     */
+    @ExcelProperty(value = "商品单位")
+    private String productUnit;
+
+    /**
+     * 本次发货数量
+     */
+    @ExcelProperty(value = "本次发货数量")
+    private Long deliverNum;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 129 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderDeliverVo.java

@@ -0,0 +1,129 @@
+package org.dromara.order.domain.vo;
+
+import org.dromara.order.domain.OrderDeliver;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 订单发货主视图对象 order_deliver
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = OrderDeliver.class)
+public class OrderDeliverVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    @ExcelProperty(value = "订单id")
+    private Long orderId;
+
+    /**
+     * 订单编号
+     */
+    @ExcelProperty(value = "订单编号")
+    private String orderCode;
+
+    @ExcelProperty(value = "发货单号")
+    /**
+     * 订单发货编号
+     */
+    private String deliverCode;
+
+    /**
+     * 物流包裹号
+     */
+    @ExcelProperty(value = "物流包裹号")
+    private String logisticPackNo;
+
+    /**
+     * 发货方式
+     */
+    @ExcelProperty(value = "发货方式", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "deliver_method")
+    private String deliverMethod;
+
+    /**
+     * 送货人姓名
+     */
+    @ExcelProperty(value = "送货人姓名")
+    private String deliverMan;
+
+    /**
+     * 送货人联系电话
+     */
+    @ExcelProperty(value = "送货人联系电话")
+    private String phone;
+
+    /**
+     * 物流状态
+     */
+    @ExcelProperty(value = "物流状态")
+    private String logisticsStatus;
+
+    /**
+     * 发货备注
+     */
+    @ExcelProperty(value = "发货备注")
+    private String deliverRemark;
+
+    /**
+     * 装箱/验货备注
+     */
+    @ExcelProperty(value = "装箱/验货备注")
+    private String checklistRemark;
+
+    /**
+     * 承运物流公司
+     */
+    @ExcelProperty(value = "承运物流公司")
+    private Long logisticsCompany;
+
+    /**
+     * 物流单号
+     */
+    @ExcelProperty(value = "物流单号")
+    private String logisticNo;
+
+    /**
+     * 包裹状态
+     */
+    @ExcelProperty(value = "包裹状态")
+    private String logisticPackStatus;
+
+    /**
+     * 收货人电话
+     */
+    @ExcelProperty(value = "收货人电话")
+    private String consigneePhone;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    private List<OrderDeliverProductVo> deliverProductList;
+}

+ 2 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderMainVo.java

@@ -326,5 +326,7 @@ public class OrderMainVo implements Serializable {
 
     private List<OrderProductVo> orderProductList;
 
+    private List<OrderDeliverProductVo> deliverProductList;
+
 
 }

+ 13 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderQuantitySummary.java

@@ -0,0 +1,13 @@
+package org.dromara.order.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class OrderQuantitySummary implements Serializable {
+    
+    private Long orderTotalQty;
+
+    private Long deliveredTotalQty;
+}

+ 15 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderDeliverMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.order.mapper;
+
+import org.dromara.order.domain.OrderDeliver;
+import org.dromara.order.domain.vo.OrderDeliverVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 订单发货主Mapper接口
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+public interface OrderDeliverMapper extends BaseMapperPlus<OrderDeliver, OrderDeliverVo> {
+
+}

+ 22 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderDeliverProductMapper.java

@@ -0,0 +1,22 @@
+package org.dromara.order.mapper;
+
+import org.apache.dubbo.remoting.http12.rest.Param;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.order.domain.OrderDeliverProduct;
+import org.dromara.order.domain.vo.OrderDeliverProductVo;
+
+import java.util.List;
+
+/**
+ * 订单发货商品明细Mapper接口
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+public interface OrderDeliverProductMapper extends BaseMapperPlus<OrderDeliverProduct, OrderDeliverProductVo> {
+
+    void deleteByDeliverId(@Param("deliverId") Long deliverId);
+
+    List<OrderDeliverProductVo> selectDeliverProductsByOrderId(@Param("orderId") Long orderId);
+
+}

+ 7 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderProductMapper.java

@@ -1,8 +1,12 @@
 package org.dromara.order.mapper;
 
+import org.apache.ibatis.annotations.Param;
 import org.dromara.order.domain.OrderProduct;
 import org.dromara.order.domain.vo.OrderProductVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.order.domain.vo.OrderQuantitySummary;
+
+import java.util.List;
 
 /**
  * 订单商品明细Mapper接口
@@ -12,4 +16,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  */
 public interface OrderProductMapper extends BaseMapperPlus<OrderProduct, OrderProductVo> {
 
+    List<OrderProductVo> selectProductsWithDelivered(@Param("orderId") Long orderId);
+
+    OrderQuantitySummary selectOrderAndDeliveredQuantity(@Param("orderId") Long orderId);
 }

+ 70 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderDeliverProductService.java

@@ -0,0 +1,70 @@
+package org.dromara.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.order.domain.OrderDeliverProduct;
+import org.dromara.order.domain.vo.OrderDeliverProductVo;
+import org.dromara.order.domain.bo.OrderDeliverProductBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 订单发货商品明细Service接口
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+public interface IOrderDeliverProductService extends IService<OrderDeliverProduct>{
+
+    /**
+     * 查询订单发货商品明细
+     *
+     * @param id 主键
+     * @return 订单发货商品明细
+     */
+    OrderDeliverProductVo queryById(Long id);
+
+    /**
+     * 分页查询订单发货商品明细列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单发货商品明细分页列表
+     */
+    TableDataInfo<OrderDeliverProductVo> queryPageList(OrderDeliverProductBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的订单发货商品明细列表
+     *
+     * @param bo 查询条件
+     * @return 订单发货商品明细列表
+     */
+    List<OrderDeliverProductVo> queryList(OrderDeliverProductBo bo);
+
+    /**
+     * 新增订单发货商品明细
+     *
+     * @param bo 订单发货商品明细
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(OrderDeliverProductBo bo);
+
+    /**
+     * 修改订单发货商品明细
+     *
+     * @param bo 订单发货商品明细
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(OrderDeliverProductBo bo);
+
+    /**
+     * 校验并批量删除订单发货商品明细信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 70 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderDeliverService.java

@@ -0,0 +1,70 @@
+package org.dromara.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.order.domain.OrderDeliver;
+import org.dromara.order.domain.vo.OrderDeliverVo;
+import org.dromara.order.domain.bo.OrderDeliverBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 订单发货主Service接口
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+public interface IOrderDeliverService extends IService<OrderDeliver>{
+
+    /**
+     * 查询订单发货主
+     *
+     * @param id 主键
+     * @return 订单发货主
+     */
+    OrderDeliverVo queryById(Long id);
+
+    /**
+     * 分页查询订单发货主列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单发货主分页列表
+     */
+    TableDataInfo<OrderDeliverVo> queryPageList(OrderDeliverBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的订单发货主列表
+     *
+     * @param bo 查询条件
+     * @return 订单发货主列表
+     */
+    List<OrderDeliverVo> queryList(OrderDeliverBo bo);
+
+    /**
+     * 新增订单发货主
+     *
+     * @param bo 订单发货主
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(OrderDeliverBo bo);
+
+    /**
+     * 修改订单发货主
+     *
+     * @param bo 订单发货主
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(OrderDeliverBo bo);
+
+    /**
+     * 校验并批量删除订单发货主信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 139 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverProductServiceImpl.java

@@ -0,0 +1,139 @@
+package org.dromara.order.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.order.domain.bo.OrderDeliverProductBo;
+import org.dromara.order.domain.vo.OrderDeliverProductVo;
+import org.dromara.order.domain.OrderDeliverProduct;
+import org.dromara.order.mapper.OrderDeliverProductMapper;
+import org.dromara.order.service.IOrderDeliverProductService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 订单发货商品明细Service业务层处理
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class OrderDeliverProductServiceImpl  extends ServiceImpl<OrderDeliverProductMapper, OrderDeliverProduct> implements IOrderDeliverProductService {
+
+    private final OrderDeliverProductMapper baseMapper;
+
+    /**
+     * 查询订单发货商品明细
+     *
+     * @param id 主键
+     * @return 订单发货商品明细
+     */
+    @Override
+    public OrderDeliverProductVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询订单发货商品明细列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单发货商品明细分页列表
+     */
+    @Override
+    public TableDataInfo<OrderDeliverProductVo> queryPageList(OrderDeliverProductBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<OrderDeliverProduct> lqw = buildQueryWrapper(bo);
+        Page<OrderDeliverProductVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的订单发货商品明细列表
+     *
+     * @param bo 查询条件
+     * @return 订单发货商品明细列表
+     */
+    @Override
+    public List<OrderDeliverProductVo> queryList(OrderDeliverProductBo bo) {
+        LambdaQueryWrapper<OrderDeliverProduct> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<OrderDeliverProduct> buildQueryWrapper(OrderDeliverProductBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<OrderDeliverProduct> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(OrderDeliverProduct::getId);
+        lqw.eq(bo.getDeliverId() != null, OrderDeliverProduct::getDeliverId, bo.getDeliverId());
+        lqw.eq(bo.getProductId() != null, OrderDeliverProduct::getProductId, bo.getProductId());
+        lqw.like(StringUtils.isNotBlank(bo.getProductName()), OrderDeliverProduct::getProductName, bo.getProductName());
+        lqw.eq(bo.getProductUnitId() != null, OrderDeliverProduct::getProductUnitId, bo.getProductUnitId());
+        lqw.eq(StringUtils.isNotBlank(bo.getProductUnit()), OrderDeliverProduct::getProductUnit, bo.getProductUnit());
+        lqw.eq(bo.getDeliverNum() != null, OrderDeliverProduct::getDeliverNum, bo.getDeliverNum());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), OrderDeliverProduct::getPlatformCode, bo.getPlatformCode());
+        return lqw;
+    }
+
+    /**
+     * 新增订单发货商品明细
+     *
+     * @param bo 订单发货商品明细
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(OrderDeliverProductBo bo) {
+        OrderDeliverProduct add = MapstructUtils.convert(bo, OrderDeliverProduct.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改订单发货商品明细
+     *
+     * @param bo 订单发货商品明细
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(OrderDeliverProductBo bo) {
+        OrderDeliverProduct update = MapstructUtils.convert(bo, OrderDeliverProduct.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(OrderDeliverProduct entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除订单发货商品明细信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 266 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderDeliverServiceImpl.java

@@ -0,0 +1,266 @@
+package org.dromara.order.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.enums.OrderStatus;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.SequenceUtils;
+import org.dromara.order.domain.OrderDeliver;
+import org.dromara.order.domain.OrderDeliverProduct;
+import org.dromara.order.domain.OrderMain;
+import org.dromara.order.domain.bo.OrderDeliverBo;
+import org.dromara.order.domain.bo.OrderDeliverProductBo;
+import org.dromara.order.domain.vo.OrderDeliverVo;
+import org.dromara.order.domain.vo.OrderQuantitySummary;
+import org.dromara.order.mapper.OrderDeliverMapper;
+import org.dromara.order.mapper.OrderDeliverProductMapper;
+import org.dromara.order.mapper.OrderMainMapper;
+import org.dromara.order.mapper.OrderProductMapper;
+import org.dromara.order.service.IOrderDeliverService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * 订单发货主Service业务层处理
+ *
+ * @author LionLi
+ * @date 2025-12-30
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class OrderDeliverServiceImpl extends ServiceImpl<OrderDeliverMapper, OrderDeliver> implements IOrderDeliverService {
+
+    private final OrderDeliverMapper baseMapper;
+
+    private final OrderMainMapper orderMainMapper;
+
+    private final OrderProductMapper orderProductMapper;
+
+    private final OrderDeliverProductMapper orderDeliverProductMapper;
+
+    /**
+     * 查询订单发货主
+     *
+     * @param id 主键
+     * @return 订单发货主
+     */
+    @Override
+    public OrderDeliverVo queryById(Long id) {
+        OrderDeliverVo orderDeliverVo = baseMapper.selectVoById(id);
+        orderDeliverVo.setDeliverProductList(orderDeliverProductMapper.selectVoList(new LambdaQueryWrapper<OrderDeliverProduct>()
+            .eq(OrderDeliverProduct::getDeliverId, id)));
+        return orderDeliverVo;
+    }
+
+    /**
+     * 分页查询订单发货主列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单发货主分页列表
+     */
+    @Override
+    public TableDataInfo<OrderDeliverVo> queryPageList(OrderDeliverBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<OrderDeliver> lqw = buildQueryWrapper(bo);
+        Page<OrderDeliverVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的订单发货主列表
+     *
+     * @param bo 查询条件
+     * @return 订单发货主列表
+     */
+    @Override
+    public List<OrderDeliverVo> queryList(OrderDeliverBo bo) {
+        LambdaQueryWrapper<OrderDeliver> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<OrderDeliver> buildQueryWrapper(OrderDeliverBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<OrderDeliver> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(OrderDeliver::getId);
+        lqw.eq(bo.getOrderId() != null, OrderDeliver::getOrderId, bo.getOrderId());
+        lqw.eq(StringUtils.isNotBlank(bo.getOrderCode()), OrderDeliver::getOrderCode, bo.getOrderCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getLogisticPackNo()), OrderDeliver::getLogisticPackNo, bo.getLogisticPackNo());
+        lqw.eq(StringUtils.isNotBlank(bo.getDeliverMethod()), OrderDeliver::getDeliverMethod, bo.getDeliverMethod());
+        lqw.eq(StringUtils.isNotBlank(bo.getDeliverMan()), OrderDeliver::getDeliverMan, bo.getDeliverMan());
+        lqw.eq(StringUtils.isNotBlank(bo.getPhone()), OrderDeliver::getPhone, bo.getPhone());
+        lqw.eq(StringUtils.isNotBlank(bo.getLogisticsStatus()), OrderDeliver::getLogisticsStatus, bo.getLogisticsStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getDeliverRemark()), OrderDeliver::getDeliverRemark, bo.getDeliverRemark());
+        lqw.eq(StringUtils.isNotBlank(bo.getChecklistRemark()), OrderDeliver::getChecklistRemark, bo.getChecklistRemark());
+        lqw.eq(bo.getLogisticsCompany() != null, OrderDeliver::getLogisticsCompany, bo.getLogisticsCompany());
+        lqw.eq(StringUtils.isNotBlank(bo.getLogisticNo()), OrderDeliver::getLogisticNo, bo.getLogisticNo());
+        lqw.eq(StringUtils.isNotBlank(bo.getLogisticPackStatus()), OrderDeliver::getLogisticPackStatus, bo.getLogisticPackStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getConsigneePhone()), OrderDeliver::getConsigneePhone, bo.getConsigneePhone());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), OrderDeliver::getPlatformCode, bo.getPlatformCode());
+        return lqw;
+    }
+
+    /**
+     * 新增订单发货主
+     *
+     * @param bo 订单发货主
+     * @return 是否新增成功
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean insertByBo(OrderDeliverBo bo) {
+        try {
+            // 1. 生成发货单号
+            bo.setDeliverCode(SequenceUtils.nextIdDateTimePadded(""));
+
+            Long orderId = bo.getOrderId();
+
+            // 2. 查询订单主信息(用于后续状态更新)
+            OrderMain orderMain = orderMainMapper.selectById(orderId);
+            if (orderMain == null) {
+                throw new RuntimeException("订单不存在: " + orderId);
+            }
+
+            // 3. 获取 订单总数量 和 已发货总数量
+            OrderQuantitySummary summary = orderProductMapper.selectOrderAndDeliveredQuantity(orderId);
+            long orderTotalQty = Optional.ofNullable(summary.getOrderTotalQty()).orElse(0L);
+            long deliveredTotalQty = Optional.ofNullable(summary.getDeliveredTotalQty()).orElse(0L);
+
+            // 4. 新增本次发货数量(从 BO 中累加)
+            long currentDeliverQty = bo.getOrderDeliverProducts().stream()
+                .mapToLong(OrderDeliverProductBo::getDeliverNum)
+                .sum();
+
+            // 5. 计算发货后总量
+            long newDeliveredTotalQty = deliveredTotalQty + currentDeliverQty;
+
+            // 6. 判断新状态
+            String newStatus;
+            if (newDeliveredTotalQty >= orderTotalQty) {
+                newStatus = OrderStatus.SHIPPED.getCode(); // 已全部发货
+            } else if (newDeliveredTotalQty > 0) {
+                newStatus = OrderStatus.PARTIALLY_SHIPPED.getCode(); // 部分发货
+            } else {
+                newStatus = orderMain.getOrderStatus(); // 无发货,保持原状态
+            }
+
+            // 7. 插入发货单主表
+            OrderDeliver deliver = MapstructUtils.convert(bo, OrderDeliver.class);
+            validEntityBeforeSave(deliver);
+            boolean inserted = baseMapper.insert(deliver) > 0;
+            if (!inserted) {
+                return false;
+            }
+            bo.setId(deliver.getId());
+
+            // 8. 插入发货商品明细
+            saveOrderDeliverProducts(deliver.getId(), bo.getOrderDeliverProducts(), false);
+
+            // 9. 更新订单主表状态
+            LambdaUpdateWrapper<OrderMain> updateWrapper = new LambdaUpdateWrapper<OrderMain>()
+                .eq(OrderMain::getId, orderId)
+                .set(OrderMain::getOrderStatus, newStatus);
+
+            orderMainMapper.update(null, updateWrapper);
+
+            log.info("新增订单发货单成功:{}", bo.getId());
+            return true;
+        } catch (RuntimeException e) {
+            log.error("新增订单发货主失败:{}", e.getMessage(), e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 修改订单发货主
+     *
+     * @param bo 订单发货主
+     * @return 是否修改成功
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean updateByBo(OrderDeliverBo bo) {
+        try {
+            OrderDeliver update = MapstructUtils.convert(bo, OrderDeliver.class);
+            validEntityBeforeSave(update);
+            boolean flag = baseMapper.updateById(update) > 0;
+
+            if (flag) {
+                // 保存商品明细(编辑时先删除再新增)
+                saveOrderDeliverProducts(bo.getId(), bo.getOrderDeliverProducts(), true);
+            }
+            log.info("修改订单发货主成功:{}", bo.getId());
+            return flag;
+        } catch (Exception e) {
+            log.error("修改订单发货主失败:{}", e.getMessage(), e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 保存发货商品明细(公共方法)
+     *
+     * @param deliverId   发货单ID
+     * @param productBos  商品明细列表
+     * @param deleteFirst 是否先删除已有明细(true=编辑,false=新增)
+     */
+    private void saveOrderDeliverProducts(Long deliverId, List<OrderDeliverProductBo> productBos, boolean deleteFirst) {
+        if (deliverId == null || productBos == null || productBos.isEmpty()) {
+            return;
+        }
+
+        // 编辑时:先删除明细
+        if (deleteFirst) {
+            orderDeliverProductMapper.deleteByDeliverId(deliverId);
+        }
+
+        // 批量插入新明细
+        List<OrderDeliverProduct> products = productBos.stream()
+            .map(bo -> {
+                OrderDeliverProduct product = MapstructUtils.convert(bo, OrderDeliverProduct.class);
+                product.setDeliverId(deliverId);
+                return product;
+            })
+            .collect(Collectors.toList());
+
+        if (!products.isEmpty()) {
+            orderDeliverProductMapper.insertBatch(products);
+        }
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(OrderDeliver entity) {
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除订单发货主信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 61 - 40
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderMainServiceImpl.java

@@ -18,6 +18,8 @@ import org.dromara.order.domain.bo.OrderMainBo;
 import org.dromara.order.domain.bo.OrderProductBo;
 import org.dromara.order.domain.vo.OrderMainVo;
 import org.dromara.order.domain.vo.OrderProductVo;
+import org.dromara.order.mapper.OrderDeliverMapper;
+import org.dromara.order.mapper.OrderDeliverProductMapper;
 import org.dromara.order.mapper.OrderMainMapper;
 import org.dromara.order.mapper.OrderProductMapper;
 import org.dromara.order.service.IOrderMainService;
@@ -44,6 +46,10 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
 
     private final OrderProductMapper orderProductMapper;
 
+    private final OrderDeliverMapper orderDeliverMapper;
+
+    private final OrderDeliverProductMapper orderDeliverProductMapper;
+
     /**
      * 查询订单主信息
      *
@@ -59,13 +65,14 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
         }
 
         // 2. 查询关联的商品列表
-        List<OrderProductVo> orderProductVoList = orderProductMapper.selectVoList(
-            new LambdaQueryWrapper<OrderProduct>().eq(OrderProduct::getOrderId, orderMainVo.getId())
-        );
+        List<OrderProductVo> orderProductVoList = orderProductMapper.selectProductsWithDelivered(orderMainVo.getId());
 
         // 3. 组装数据
         orderMainVo.setOrderProductList(orderProductVoList);
 
+        orderMainVo.setDeliverProductList(
+            orderDeliverProductMapper.selectDeliverProductsByOrderId(orderMainVo.getId())
+        );
         // 4. 返回已组装好的对象
         return orderMainVo;
     }
@@ -81,6 +88,8 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
     public TableDataInfo<OrderMainVo> queryPageList(OrderMainBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<OrderMain> lqw = buildQueryWrapper(bo);
         Page<OrderMainVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        List<OrderMainVo> records = result.getRecords();
+
         return TableDataInfo.build(result);
     }
 
@@ -156,48 +165,53 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
     @Transactional(rollbackFor = Exception.class)
     @Override
     public Boolean insertByBo(OrderMainBo bo) {
-        // 1. 校验商品列表
-        List<OrderProductBo> orderProductBos = bo.getOrderProductBos();
-        if (CollUtil.isEmpty(orderProductBos)) {
-            throw new IllegalArgumentException("订单商品列表不能为空");
-        }
-
-        // 可选:校验每个商品的数量、价格等
-        for (OrderProductBo productBo : orderProductBos) {
-            if (productBo.getOrderQuantity() == null || productBo.getOrderQuantity() <= 0) {
-                throw new IllegalArgumentException("商品数量必须大于0");
+        try {
+            // 1. 校验商品列表
+            List<OrderProductBo> orderProductBos = bo.getOrderProductBos();
+            if (CollUtil.isEmpty(orderProductBos)) {
+                throw new IllegalArgumentException("订单商品列表不能为空");
             }
-        }
 
-        // 2. 生成订单号并转换主单
-        String orderNo = SequenceUtils.generateOrderCode("RS");
-        bo.setOrderNo(orderNo);
-        OrderMain orderMain = MapstructUtils.convert(bo, OrderMain.class);
+            // 可选:校验每个商品的数量、价格等
+            for (OrderProductBo productBo : orderProductBos) {
+                if (productBo.getOrderQuantity() == null || productBo.getOrderQuantity() <= 0) {
+                    throw new IllegalArgumentException("商品数量必须大于0");
+                }
+            }
 
-        validEntityBeforeSave(orderMain);
+            // 2. 生成订单号并转换主单
+            String orderNo = SequenceUtils.generateOrderCode("RS");
+            bo.setOrderNo(orderNo);
+            OrderMain orderMain = MapstructUtils.convert(bo, OrderMain.class);
 
-        // 3. 插入主订单
-        boolean mainSaved = baseMapper.insert(orderMain) > 0;
-        if (!mainSaved) {
-            throw new RuntimeException("主订单保存失败");
-        }
+            validEntityBeforeSave(orderMain);
 
-        // 4. 转换并填充子订单商品
-        Long orderId = orderMain.getId();
-        List<OrderProduct> orderProducts = orderProductBos.stream()
-            .map(productBo -> {
-                OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
-                product.setOrderId(orderId);      // 关联主单ID
-                product.setOrderNo(orderNo);      // 关联订单号
-                return product;
-            })
-            .collect(Collectors.toList());
+            // 3. 插入主订单
+            boolean mainSaved = baseMapper.insert(orderMain) > 0;
+            if (!mainSaved) {
+                throw new RuntimeException("主订单保存失败");
+            }
 
-        // 5. 批量插入订单商品
-        boolean productsSaved = orderProductMapper.insertBatch(orderProducts);
+            // 4. 转换并填充子订单商品
+            Long orderId = orderMain.getId();
+            List<OrderProduct> orderProducts = orderProductBos.stream()
+                .map(productBo -> {
+                    OrderProduct product = MapstructUtils.convert(productBo, OrderProduct.class);
+                    product.setOrderId(orderId);      // 关联主单ID
+                    product.setOrderNo(orderNo);      // 关联订单号
+                    return product;
+                })
+                .collect(Collectors.toList());
 
+            // 5. 批量插入订单商品
+            boolean productsSaved = orderProductMapper.insertBatch(orderProducts);
 
-        return productsSaved;
+            log.info("成功新增订单,ID: {}", orderId);
+            return productsSaved;
+        } catch (RuntimeException e) {
+            log.error("新增订单失败: {}", e.getMessage(), e);
+            throw new RuntimeException("新增订单失败: " + e.getMessage());
+        }
     }
 
     /**
@@ -206,11 +220,18 @@ public class OrderMainServiceImpl extends ServiceImpl<OrderMainMapper, OrderMain
      * @param bo 订单主信息
      * @return 是否修改成功
      */
+    @Transactional(rollbackFor = Exception.class)
     @Override
     public Boolean updateByBo(OrderMainBo bo) {
-        OrderMain update = MapstructUtils.convert(bo, OrderMain.class);
-        validEntityBeforeSave(update);
-        return baseMapper.updateById(update) > 0;
+        try {
+            OrderMain update = MapstructUtils.convert(bo, OrderMain.class);
+            validEntityBeforeSave(update);
+            log.info("成功更新订单,ID: {}", bo.getId());
+            return baseMapper.updateById(update) > 0;
+        } catch (Exception e) {
+            log.error("更新订单失败: {}", e.getMessage(), e);
+            throw new RuntimeException("更新订单失败: " + e.getMessage());
+        }
     }
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-order/src/main/resources/mapper.order/OrderProductMapper.xml → ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderDeliverMapper.xml

@@ -2,6 +2,6 @@
 <!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="org.dromara.order.mapper.OrderProductMapper">
+<mapper namespace="org.dromara.order.mapper.OrderDeliverMapper">
 
 </mapper>

+ 20 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderDeliverProductMapper.xml

@@ -0,0 +1,20 @@
+<?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="org.dromara.order.mapper.OrderDeliverProductMapper">
+
+    <delete id="deleteByDeliverId" parameterType="java.lang.Long">
+        DELETE
+        FROM order_deliver_product
+        WHERE deliver_id = #{deliverId}
+    </delete>
+
+    <select id="selectDeliverProductsByOrderId" resultType="org.dromara.order.domain.vo.OrderDeliverProductVo">
+        SELECT odp.*
+        FROM order_deliver_product odp
+                 JOIN order_deliver od ON odp.deliver_id = od.id
+        WHERE od.order_id = #{orderId}
+    </select>
+
+</mapper>

+ 0 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper.order/OrderMainMapper.xml → ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderMainMapper.xml


+ 53 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderProductMapper.xml

@@ -0,0 +1,53 @@
+<?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="org.dromara.order.mapper.OrderProductMapper">
+
+    <select id="selectProductsWithDelivered" resultType="org.dromara.order.domain.vo.OrderProductVo">
+        SELECT op.id,
+               op.order_id                                           AS orderId,
+               op.order_no                                           AS orderNo,
+               op.shipment_no                                        AS shipmentNo,
+               op.product_id                                         AS productId,
+               op.product_no                                         AS productNo,
+               op.product_name                                       AS productName,
+               op.product_unit                                       AS productUnit,
+               op.product_image                                      AS productImage,
+               op.platform_price                                     AS platformPrice,
+               op.min_order_quantity                                 AS minOrderQuantity,
+               op.order_price                                        AS orderPrice,
+               op.order_quantity                                     AS orderQuantity,
+               op.subtotal                                           AS subtotal,
+               op.min_selling_price                                  AS minSellingPrice,
+               op.signed_quantity                                    AS signedQuantity,
+               COALESCE(SUM(odp.deliver_num), 0)                     AS quantitySent,
+               op.order_quantity - COALESCE(SUM(odp.deliver_num), 0) AS unsentQuantity,
+               op.is_after_sale                                      AS isAfterSale,
+               op.after_sale_quantity                                AS afterSaleQuantity,
+               op.return_amount                                      AS returnAmount,
+               op.pre_delivery_date                                  AS preDeliveryDate,
+               op.status                                             AS status,
+               op.del_flag                                           AS delFlag,
+               op.remark                                             AS remark
+        FROM order_product op
+                 LEFT JOIN order_deliver od ON od.order_id = op.order_id
+                 LEFT JOIN order_deliver_product odp ON odp.deliver_id = od.id
+            AND odp.product_id = op.product_id
+        WHERE op.order_id = #{orderId}
+          AND op.del_flag = '0'
+        GROUP BY op.id
+        ORDER BY op.id
+    </select>
+
+    <select id="selectOrderAndDeliveredQuantity" resultType="org.dromara.order.domain.vo.OrderQuantitySummary">
+        SELECT SUM(op.order_quantity)            AS orderTotalQty,
+               COALESCE(SUM(odp.deliver_num), 0) AS deliveredTotalQty
+        FROM order_product op
+                 LEFT JOIN order_deliver od ON od.order_id = op.order_id AND od.del_flag = '0'
+                 LEFT JOIN order_deliver_product odp ON odp.deliver_id = od.id
+        WHERE op.order_id = #{orderId}
+          AND op.del_flag = '0'
+    </select>
+
+</mapper>