Jelajahi Sumber

Merge remote-tracking branch 'origin/master'

Lijingyang 1 bulan lalu
induk
melakukan
f8938aa1de
21 mengubah file dengan 1638 tambahan dan 1 penghapusan
  1. 107 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderEvaluationHeaderController.java
  2. 106 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderEvaluationItemController.java
  3. 66 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/pc/PcOrderEvaluationHeader.java
  4. 82 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderEvaluationHeader.java
  5. 87 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderEvaluationItem.java
  6. 80 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderEvaluationHeaderBo.java
  7. 79 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderEvaluationItemBo.java
  8. 95 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderEvaluationHeaderVo.java
  9. 98 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderEvaluationItemVo.java
  10. 2 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderProductBriefVo.java
  11. 31 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderEvaluationHeaderMapper.java
  12. 15 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderEvaluationItemMapper.java
  13. 5 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderProductMapper.java
  14. 81 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderEvaluationHeaderService.java
  15. 70 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderEvaluationItemService.java
  16. 427 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderEvaluationHeaderServiceImpl.java
  17. 142 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderEvaluationItemServiceImpl.java
  18. 48 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderEvaluationHeaderMapper.xml
  19. 7 0
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderEvaluationItemMapper.xml
  20. 6 1
      ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderMainMapper.xml
  21. 4 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/pc/PcSysUserController.java

+ 107 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderEvaluationHeaderController.java

@@ -0,0 +1,107 @@
+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.OrderEvaluationHeaderVo;
+import org.dromara.order.domain.bo.OrderEvaluationHeaderBo;
+import org.dromara.order.service.IOrderEvaluationHeaderService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 订单评价主
+ * 前端访问路由地址为:/order/evaluationHeader
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/evaluationHeader")
+public class OrderEvaluationHeaderController extends BaseController {
+
+    private final IOrderEvaluationHeaderService orderEvaluationHeaderService;
+
+    /**
+     * 查询订单评价主列表
+     */
+    //@SaCheckPermission("order:evaluationHeader:list")
+    @GetMapping("/list")
+    public TableDataInfo<OrderEvaluationHeaderVo> list(OrderEvaluationHeaderBo bo, PageQuery pageQuery) {
+        return orderEvaluationHeaderService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出订单评价主列表
+     */
+    //@SaCheckPermission("order:evaluationHeader:export")
+    @Log(title = "订单评价主", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(OrderEvaluationHeaderBo bo, HttpServletResponse response) {
+        List<OrderEvaluationHeaderVo> list = orderEvaluationHeaderService.queryList(bo);
+        ExcelUtil.exportExcel(list, "订单评价主", OrderEvaluationHeaderVo.class, response);
+    }
+
+    /**
+     * 获取订单评价主详细信息
+     *
+     * @param id 主键
+     */
+    //@SaCheckPermission("order:evaluationHeader:query")
+    @GetMapping("/{id}")
+    public R<OrderEvaluationHeaderVo> getInfo(@NotNull(message = "主键不能为空")
+                                              @PathVariable("id") Long id) {
+        return R.ok(orderEvaluationHeaderService.queryById(id));
+    }
+
+
+    /**
+     * 新增订单评价主
+     */
+    //@SaCheckPermission("order:evaluationHeader:add")
+    @Log(title = "订单评价主", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderEvaluationHeaderBo bo) {
+        return toAjax(orderEvaluationHeaderService.insertByBo(bo));
+    }
+
+    /**
+     * 修改订单评价主
+     */
+    //@SaCheckPermission("order:evaluationHeader:edit")
+    @Log(title = "订单评价主", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody OrderEvaluationHeaderBo bo) {
+        return toAjax(orderEvaluationHeaderService.updateByBo(bo));
+    }
+
+    /**
+     * 删除订单评价主
+     *
+     * @param ids 主键串
+     */
+    //@SaCheckPermission("order:evaluationHeader:remove")
+    @Log(title = "订单评价主", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(orderEvaluationHeaderService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 106 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/OrderEvaluationItemController.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.OrderEvaluationItemVo;
+import org.dromara.order.domain.bo.OrderEvaluationItemBo;
+import org.dromara.order.service.IOrderEvaluationItemService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 订单评价明细
+ * 前端访问路由地址为:/order/evaluationItem
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/evaluationItem")
+public class OrderEvaluationItemController extends BaseController {
+
+    private final IOrderEvaluationItemService orderEvaluationItemService;
+
+    /**
+     * 查询订单评价明细列表
+     */
+    //@SaCheckPermission("order:evaluationItem:list")
+    @GetMapping("/list")
+    public TableDataInfo<OrderEvaluationItemVo> list(OrderEvaluationItemBo bo, PageQuery pageQuery) {
+        return orderEvaluationItemService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出订单评价明细列表
+     */
+    //@SaCheckPermission("order:evaluationItem:export")
+    @Log(title = "订单评价明细", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(OrderEvaluationItemBo bo, HttpServletResponse response) {
+        List<OrderEvaluationItemVo> list = orderEvaluationItemService.queryList(bo);
+        ExcelUtil.exportExcel(list, "订单评价明细", OrderEvaluationItemVo.class, response);
+    }
+
+    /**
+     * 获取订单评价明细详细信息
+     *
+     * @param id 主键
+     */
+    //@SaCheckPermission("order:evaluationItem:query")
+    @GetMapping("/{id}")
+    public R<OrderEvaluationItemVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable("id") Long id) {
+        return R.ok(orderEvaluationItemService.queryById(id));
+    }
+
+    /**
+     * 新增订单评价明细
+     */
+    //@SaCheckPermission("order:evaluationItem:add")
+    @Log(title = "订单评价明细", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderEvaluationItemBo bo) {
+        return toAjax(orderEvaluationItemService.insertByBo(bo));
+    }
+
+    /**
+     * 修改订单评价明细
+     */
+    //@SaCheckPermission("order:evaluationItem:edit")
+    @Log(title = "订单评价明细", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody OrderEvaluationItemBo bo) {
+        return toAjax(orderEvaluationItemService.updateByBo(bo));
+    }
+
+    /**
+     * 删除订单评价明细
+     *
+     * @param ids 主键串
+     */
+    //@SaCheckPermission("order:evaluationItem:remove")
+    @Log(title = "订单评价明细", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(orderEvaluationItemService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 66 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/controller/pc/PcOrderEvaluationHeader.java

@@ -0,0 +1,66 @@
+package org.dromara.order.controller.pc;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.order.domain.bo.OrderEvaluationBo;
+import org.dromara.order.domain.bo.OrderEvaluationHeaderBo;
+import org.dromara.order.domain.vo.OrderEvaluationHeaderVo;
+import org.dromara.order.domain.vo.OrderEvaluationListVo;
+import org.dromara.order.service.IOrderEvaluationHeaderService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/pcOrderEvaluationHeader")
+public class PcOrderEvaluationHeader extends BaseController {
+
+    private final IOrderEvaluationHeaderService orderEvaluationHeaderService;
+
+    @GetMapping("/list")
+    public TableDataInfo<OrderEvaluationListVo> getEvaluationList(OrderEvaluationHeaderBo bo, PageQuery pageQuery) {
+        // 获取当前登录用户的企业ID
+        Long customerId = LoginHelper.getLoginUser().getCustomerId();
+        return orderEvaluationHeaderService.getEvaluationOrderList(customerId, bo.getEvaluationStatus(), pageQuery);
+    }
+
+
+    /**
+     * 新增订单评价
+     */
+    @Log(title = "PC端-新增订单评价", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody OrderEvaluationHeaderBo bo) {
+        // 获取当前登录用户的企业ID
+        Long userId = LoginHelper.getUserId();
+        Long customerId = LoginHelper.getLoginUser().getCustomerId();
+        // 强制设置企业ID,防止为其他企业创建售后申请
+        bo.setCustomerId(customerId);
+        bo.setUserId(userId);
+
+        return toAjax(orderEvaluationHeaderService.insertByBo(bo));
+    }
+
+    /**
+     * 获取评价详情(用于追评回显)
+     * 前端传参:
+     */
+    @GetMapping("/info/byOrder")
+    public R<OrderEvaluationHeaderVo> getInfoByOrderId(@RequestParam("orderId") Long orderId) {
+        OrderEvaluationHeaderVo vo = orderEvaluationHeaderService.queryByOrderId(orderId);
+        if (vo == null) {
+            return R.ok(vo);
+        }
+        return R.ok(vo);
+    }
+}

+ 82 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderEvaluationHeader.java

@@ -0,0 +1,82 @@
+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_evaluation_header
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("order_evaluation_header")
+public class OrderEvaluationHeader extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 关联订单ID
+     */
+    private Long orderId;
+
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 快递包装评分 (1-5)
+     */
+    private Integer logisticsPackScore;
+
+    /**
+     * 送货速度评分 (1-5)
+     */
+    private Integer deliverSpeedScore;
+
+    /**
+     * 配送员服务评分 (1-5)
+     */
+    private Integer courierServiceScore;
+
+    /**
+     * 评价类型:1-首次评价,2-追评
+     */
+    private Integer evaluationType;
+
+    /**
+     * 
+     */
+    private Long customerId;
+
+    /**
+     * 
+     */
+    private Long userId;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 87 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/OrderEvaluationItem.java

@@ -0,0 +1,87 @@
+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_evaluation_item
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("order_evaluation_item")
+public class OrderEvaluationItem extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 关联评价主表ID
+     */
+    private Long evaluationId;
+
+    /**
+     * 订单ID,方便查询
+     */
+    private Long orderId;
+
+    /**
+     * 关联订单详情表子项ID 
+     */
+    private Long orderItemId;
+
+    /**
+     * 商品ID
+     */
+    private Long productId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 商品图片
+     */
+    private String productImg;
+
+    /**
+     * 商品评分 (1-5)
+     */
+    private Integer productScore;
+
+    /**
+     * 商品评价内容
+     */
+    private String content;
+
+    /**
+     * 晒单图片地址,多张用逗号分隔
+     */
+    private String images;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 80 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderEvaluationHeaderBo.java

@@ -0,0 +1,80 @@
+package org.dromara.order.domain.bo;
+
+import org.dromara.order.domain.OrderEvaluationHeader;
+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_evaluation_header
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = OrderEvaluationHeader.class, reverseConvertGenerate = false)
+public class OrderEvaluationHeaderBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 关联订单ID
+     */
+    private Long orderId;
+
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 快递包装评分 (1-5)
+     */
+    private Integer logisticsPackScore;
+
+    /**
+     * 送货速度评分 (1-5)
+     */
+    private Integer deliverSpeedScore;
+
+    /**
+     * 配送员服务评分 (1-5)
+     */
+    private Integer courierServiceScore;
+
+    /**
+     * 评价类型:1-首次评价,2-追评
+     */
+    private Integer evaluationType;
+
+    /**
+     *
+     */
+    private Long customerId;
+
+    /**
+     *
+     */
+    private Long userId;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    private String evaluationStatus;
+
+    List<OrderEvaluationItemBo> orderEvaluationItemList;
+
+
+}

+ 79 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/bo/OrderEvaluationItemBo.java

@@ -0,0 +1,79 @@
+package org.dromara.order.domain.bo;
+
+import org.dromara.order.domain.OrderEvaluationItem;
+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_evaluation_item
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = OrderEvaluationItem.class, reverseConvertGenerate = false)
+public class OrderEvaluationItemBo extends BaseEntity {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 关联评价主表ID
+     */
+    private Long evaluationId;
+
+    /**
+     * 订单ID,方便查询
+     */
+    private Long orderId;
+
+    /**
+     * 关联订单详情表子项ID 
+     */
+    private Long orderItemId;
+
+    /**
+     * 商品ID
+     */
+    private Long productId;
+
+    /**
+     * 商品名称
+     */
+    private String productName;
+
+    /**
+     * 商品图片
+     */
+    private String productImg;
+
+    /**
+     * 商品评分 (1-5)
+     */
+    private Integer productScore;
+
+    /**
+     * 商品评价内容
+     */
+    private String content;
+
+    /**
+     * 晒单图片地址,多张用逗号分隔
+     */
+    private String images;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 95 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderEvaluationHeaderVo.java

@@ -0,0 +1,95 @@
+package org.dromara.order.domain.vo;
+
+import org.dromara.order.domain.OrderEvaluationHeader;
+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 org.dromara.order.domain.bo.OrderEvaluationItemBo;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 订单评价主视图对象 order_evaluation_header
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = OrderEvaluationHeader.class)
+public class OrderEvaluationHeaderVo 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 orderNo;
+
+    /**
+     * 快递包装评分 (1-5)
+     */
+    @ExcelProperty(value = "快递包装评分 (1-5)")
+    private Integer logisticsPackScore;
+
+    /**
+     * 送货速度评分 (1-5)
+     */
+    @ExcelProperty(value = "送货速度评分 (1-5)")
+    private Integer deliverSpeedScore;
+
+    /**
+     * 配送员服务评分 (1-5)
+     */
+    @ExcelProperty(value = "配送员服务评分 (1-5)")
+    private Integer courierServiceScore;
+
+    /**
+     * 评价类型:1-首次评价,2-追评
+     */
+    @ExcelProperty(value = "评价类型:1-首次评价,2-追评")
+    private Integer evaluationType;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long customerId;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long userId;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+    List<OrderEvaluationItemVo> orderEvaluationItemList;
+
+
+}

+ 98 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/domain/vo/OrderEvaluationItemVo.java

@@ -0,0 +1,98 @@
+package org.dromara.order.domain.vo;
+
+import org.dromara.order.domain.OrderEvaluationItem;
+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_evaluation_item
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = OrderEvaluationItem.class)
+public class OrderEvaluationItemVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @ExcelProperty(value = "主键ID")
+    private Long id;
+
+    /**
+     * 关联评价主表ID
+     */
+    @ExcelProperty(value = "关联评价主表ID")
+    private Long evaluationId;
+
+    /**
+     * 订单ID,方便查询
+     */
+    @ExcelProperty(value = "订单ID,方便查询")
+    private Long orderId;
+
+    /**
+     * 关联订单详情表子项ID 
+     */
+    @ExcelProperty(value = "关联订单详情表子项ID ")
+    private Long orderItemId;
+
+    /**
+     * 商品ID
+     */
+    @ExcelProperty(value = "商品ID")
+    private Long productId;
+
+    /**
+     * 商品名称
+     */
+    @ExcelProperty(value = "商品名称")
+    private String productName;
+
+    /**
+     * 商品图片
+     */
+    @ExcelProperty(value = "商品图片")
+    private String productImg;
+
+    /**
+     * 商品评分 (1-5)
+     */
+    @ExcelProperty(value = "商品评分 (1-5)")
+    private Integer productScore;
+
+    /**
+     * 商品评价内容
+     */
+    @ExcelProperty(value = "商品评价内容")
+    private String content;
+
+    /**
+     * 晒单图片地址,多张用逗号分隔
+     */
+    @ExcelProperty(value = "晒单图片地址,多张用逗号分隔")
+    private String images;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

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

@@ -8,6 +8,8 @@ import java.math.BigDecimal;
 @Data
 public class OrderProductBriefVo implements Serializable {
 
+    private Long orderId;
+
     private String productName;
 
     private Long quantity;

+ 31 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/mapper/OrderEvaluationHeaderMapper.java

@@ -0,0 +1,31 @@
+package org.dromara.order.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.dubbo.remoting.http12.rest.Param;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.order.domain.OrderEvaluationHeader;
+import org.dromara.order.domain.vo.OrderEvaluationHeaderVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.order.domain.vo.OrderEvaluationListVo;
+import org.dromara.order.domain.vo.OrderProductBriefVo;
+
+import java.util.List;
+
+/**
+ * 订单评价主Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+public interface OrderEvaluationHeaderMapper extends BaseMapperPlus<OrderEvaluationHeader, OrderEvaluationHeaderVo> {
+
+    /**
+     * 分页查询评价订单主列表(仅订单信息,不含商品明细)
+     */
+    Page<OrderEvaluationListVo> selectEvaluationOrderListPage(
+        @Param("page") Page<?> page,                  // 分页对象
+        @Param("customerId") Long customerId,         // 客户ID
+        @Param("evaluationStatus") String evaluationStatus // 评价状态 (String)
+    );
+
+}

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

@@ -0,0 +1,15 @@
+package org.dromara.order.mapper;
+
+import org.dromara.order.domain.OrderEvaluationItem;
+import org.dromara.order.domain.vo.OrderEvaluationItemVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 订单评价明细Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+public interface OrderEvaluationItemMapper extends BaseMapperPlus<OrderEvaluationItem, OrderEvaluationItemVo> {
+
+}

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

@@ -1,9 +1,11 @@
 package org.dromara.order.mapper;
 
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 import org.dromara.common.core.enums.OrderAssignStatus;
 import org.dromara.order.domain.OrderProduct;
 import org.dromara.order.domain.dto.AssignmentStatsDto;
+import org.dromara.order.domain.vo.OrderProductBriefVo;
 import org.dromara.order.domain.vo.OrderProductVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.dromara.order.domain.vo.OrderQuantitySummary;
@@ -62,4 +64,7 @@ public interface OrderProductMapper extends BaseMapperPlus<OrderProduct, OrderPr
      * 根据订单ID列表查询商品明细
      */
     List<OrderProduct> selectByOrderIds(@Param("orderIds") List<Long> orderIds);
+
+    @Select("SELECT order_id, product_name, quantity, unit_price, product_img as productImage FROM order_item WHERE order_id IN #{orderIds} AND del_flag = '0'")
+    List<OrderProductBriefVo> selectBriefListByOrderIds(@Param("orderIds") List<Long> orderIds);
 }

+ 81 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/IOrderEvaluationHeaderService.java

@@ -0,0 +1,81 @@
+package org.dromara.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.order.domain.OrderEvaluationHeader;
+import org.dromara.order.domain.vo.OrderEvaluationHeaderVo;
+import org.dromara.order.domain.bo.OrderEvaluationHeaderBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.order.domain.vo.OrderEvaluationListVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 订单评价主Service接口
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+public interface IOrderEvaluationHeaderService extends IService<OrderEvaluationHeader> {
+
+    /**
+     * 查询订单评价主
+     *
+     * @param id 主键
+     * @return 订单评价主
+     */
+    OrderEvaluationHeaderVo queryById(Long id);
+
+    /**
+     * 根据订单ID查询评价详情(用于追前回显)
+     *
+     * @param orderId 订单ID
+     * @return 评价VO(包含主表信息和明细列表)
+     */
+    OrderEvaluationHeaderVo queryByOrderId(Long orderId);
+
+    /**
+     * 分页查询订单评价主列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单评价主分页列表
+     */
+    TableDataInfo<OrderEvaluationHeaderVo> queryPageList(OrderEvaluationHeaderBo bo, PageQuery pageQuery);
+
+    TableDataInfo<OrderEvaluationListVo> getEvaluationOrderList(Long customerId, String evaluationStatus, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的订单评价主列表
+     *
+     * @param bo 查询条件
+     * @return 订单评价主列表
+     */
+    List<OrderEvaluationHeaderVo> queryList(OrderEvaluationHeaderBo bo);
+
+    /**
+     * 新增订单评价主
+     *
+     * @param bo 订单评价主
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(OrderEvaluationHeaderBo bo);
+
+    /**
+     * 修改订单评价主
+     *
+     * @param bo 订单评价主
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(OrderEvaluationHeaderBo 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/IOrderEvaluationItemService.java

@@ -0,0 +1,70 @@
+package org.dromara.order.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.order.domain.OrderEvaluationItem;
+import org.dromara.order.domain.vo.OrderEvaluationItemVo;
+import org.dromara.order.domain.bo.OrderEvaluationItemBo;
+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 2026-03-09
+ */
+public interface IOrderEvaluationItemService extends IService<OrderEvaluationItem>{
+
+    /**
+     * 查询订单评价明细
+     *
+     * @param id 主键
+     * @return 订单评价明细
+     */
+    OrderEvaluationItemVo queryById(Long id);
+
+    /**
+     * 分页查询订单评价明细列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单评价明细分页列表
+     */
+    TableDataInfo<OrderEvaluationItemVo> queryPageList(OrderEvaluationItemBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的订单评价明细列表
+     *
+     * @param bo 查询条件
+     * @return 订单评价明细列表
+     */
+    List<OrderEvaluationItemVo> queryList(OrderEvaluationItemBo bo);
+
+    /**
+     * 新增订单评价明细
+     *
+     * @param bo 订单评价明细
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(OrderEvaluationItemBo bo);
+
+    /**
+     * 修改订单评价明细
+     *
+     * @param bo 订单评价明细
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(OrderEvaluationItemBo bo);
+
+    /**
+     * 校验并批量删除订单评价明细信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 427 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderEvaluationHeaderServiceImpl.java

@@ -0,0 +1,427 @@
+package org.dromara.order.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.exception.ServiceException;
+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.dromara.order.domain.OrderEvaluationItem;
+import org.dromara.order.domain.bo.OrderEvaluationItemBo;
+import org.dromara.order.domain.vo.OrderEvaluationItemVo;
+import org.dromara.order.domain.vo.OrderEvaluationListVo;
+import org.dromara.order.domain.vo.OrderProductBriefVo;
+import org.dromara.order.mapper.OrderEvaluationItemMapper;
+import org.dromara.order.mapper.OrderProductMapper;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.dromara.order.domain.bo.OrderEvaluationHeaderBo;
+import org.dromara.order.domain.vo.OrderEvaluationHeaderVo;
+import org.dromara.order.domain.OrderEvaluationHeader;
+import org.dromara.order.mapper.OrderEvaluationHeaderMapper;
+import org.dromara.order.service.IOrderEvaluationHeaderService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 订单评价主Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class OrderEvaluationHeaderServiceImpl extends ServiceImpl<OrderEvaluationHeaderMapper, OrderEvaluationHeader> implements IOrderEvaluationHeaderService {
+
+    private final OrderEvaluationHeaderMapper baseMapper;
+
+    private final OrderEvaluationItemMapper itemMapper;
+
+    private final OrderProductMapper orderProductMapper;
+
+    /**
+     * 查询订单评价主
+     *
+     * @param id 主键
+     * @return 订单评价主
+     */
+    @Override
+    public OrderEvaluationHeaderVo queryById(Long id) {
+        OrderEvaluationHeader header = baseMapper.selectById(id);
+        if (header == null) return null;
+
+        OrderEvaluationHeaderVo vo = MapstructUtils.convert(header, OrderEvaluationHeaderVo.class);
+
+        // 为了保持一致性,queryById 也建议把明细查出来
+        List<OrderEvaluationItem> items = itemMapper.selectList(Wrappers.<OrderEvaluationItem>lambdaQuery()
+            .eq(OrderEvaluationItem::getEvaluationId, header.getId())
+            .eq(OrderEvaluationItem::getDelFlag, "0"));
+
+        if (!items.isEmpty()) {
+            vo.setOrderEvaluationItemList(items.stream()
+                .map(item -> MapstructUtils.convert(item, OrderEvaluationItemVo.class))
+                .collect(Collectors.toList()));
+        } else {
+            vo.setOrderEvaluationItemList(new ArrayList<>());
+        }
+
+        return vo;
+    }
+
+    @Override
+    public OrderEvaluationHeaderVo queryByOrderId(Long orderId) {
+        if (orderId == null) {
+            throw new ServiceException("订单ID不能为空");
+        }
+
+        // 1. 查询主表
+        OrderEvaluationHeader header = baseMapper.selectOne(Wrappers.<OrderEvaluationHeader>lambdaQuery()
+            .eq(OrderEvaluationHeader::getOrderId, orderId)
+            .eq(OrderEvaluationHeader::getDelFlag, "0"));
+
+        if (header == null) {
+            // 如果还没评价,返回 null 或者抛错,由前端决定如何处理(通常返回 null 表示去新建评价)
+            return null;
+        }
+
+        // 转换为 VO
+        OrderEvaluationHeaderVo vo = MapstructUtils.convert(header, OrderEvaluationHeaderVo.class);
+
+        // 2. 查询明细列表
+        List<OrderEvaluationItem> items = itemMapper.selectList(Wrappers.<OrderEvaluationItem>lambdaQuery()
+            .eq(OrderEvaluationItem::getEvaluationId, header.getId())
+            .eq(OrderEvaluationItem::getDelFlag, "0")
+            .orderByAsc(OrderEvaluationItem::getId)); // 保持顺序
+
+        // 转换明细为 VO
+        if (!items.isEmpty()) {
+            List<OrderEvaluationItemVo> itemVos = items.stream()
+                .map(item -> MapstructUtils.convert(item, OrderEvaluationItemVo.class))
+                .collect(Collectors.toList());
+            vo.setOrderEvaluationItemList(itemVos);
+        } else {
+            vo.setOrderEvaluationItemList(new ArrayList<>());
+        }
+
+        return vo;
+    }
+
+    /**
+     * 分页查询订单评价主列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单评价主分页列表
+     */
+    @Override
+    public TableDataInfo<OrderEvaluationHeaderVo> queryPageList(OrderEvaluationHeaderBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<OrderEvaluationHeader> lqw = buildQueryWrapper(bo);
+        Page<OrderEvaluationHeaderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    @Override
+    public TableDataInfo<OrderEvaluationListVo> getEvaluationOrderList(Long customerId, String evaluationStatus, PageQuery pageQuery) {
+        // 1. 创建分页对象
+        Page<OrderEvaluationListVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
+
+        // 2. 调用 Mapper
+        // ⚠️ 重点检查这里:参数顺序必须是 (page, customerId, evaluationStatus)
+        // 如果你之前传成了 (page, pageQuery, evaluationStatus) 或者其他组合,就会报这个错!
+        Page<OrderEvaluationListVo> resultPage = baseMapper.selectEvaluationOrderListPage(
+            page,
+            customerId,
+            evaluationStatus // 确保这里传的是 String 类型的 "0", "1", "2" 或 null,而不是对象
+        );
+
+        List<OrderEvaluationListVo> orders = resultPage.getRecords();
+
+        if (!orders.isEmpty()) {
+            // 3. 提取当前页所有订单 ID
+            List<Long> orderIds = orders.stream()
+                .map(OrderEvaluationListVo::getOrderId)
+                .collect(Collectors.toList());
+
+            // 4. 批量查询这些订单下的商品列表
+
+            List<OrderProductBriefVo> allProducts = orderProductMapper.selectBriefListByOrderIds(orderIds);
+
+            // 5. 按 orderId 分组商品 (Key: orderId, Value: List<Product>)
+            Map<Long, List<OrderProductBriefVo>> productMap = allProducts.stream()
+                .collect(Collectors.groupingBy(OrderProductBriefVo::getOrderId));
+
+            // 6. 将商品列表组装到对应订单的 productList 字段
+            for (OrderEvaluationListVo order : orders) {
+                List<OrderProductBriefVo> productList = productMap.getOrDefault(order.getOrderId(), Collections.emptyList());
+                order.setProductList(productList);
+            }
+        }
+
+        // 7. 构建返回结果
+        return TableDataInfo.build(resultPage);
+    }
+
+    /**
+     * 查询符合条件的订单评价主列表
+     *
+     * @param bo 查询条件
+     * @return 订单评价主列表
+     */
+    @Override
+    public List<OrderEvaluationHeaderVo> queryList(OrderEvaluationHeaderBo bo) {
+        LambdaQueryWrapper<OrderEvaluationHeader> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<OrderEvaluationHeader> buildQueryWrapper(OrderEvaluationHeaderBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<OrderEvaluationHeader> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(OrderEvaluationHeader::getId);
+        lqw.eq(bo.getOrderId() != null, OrderEvaluationHeader::getOrderId, bo.getOrderId());
+        lqw.eq(StringUtils.isNotBlank(bo.getOrderNo()), OrderEvaluationHeader::getOrderNo, bo.getOrderNo());
+        lqw.eq(bo.getLogisticsPackScore() != null, OrderEvaluationHeader::getLogisticsPackScore, bo.getLogisticsPackScore());
+        lqw.eq(bo.getDeliverSpeedScore() != null, OrderEvaluationHeader::getDeliverSpeedScore, bo.getDeliverSpeedScore());
+        lqw.eq(bo.getCourierServiceScore() != null, OrderEvaluationHeader::getCourierServiceScore, bo.getCourierServiceScore());
+        lqw.eq(bo.getEvaluationType() != null, OrderEvaluationHeader::getEvaluationType, bo.getEvaluationType());
+        lqw.eq(bo.getCustomerId() != null, OrderEvaluationHeader::getCustomerId, bo.getCustomerId());
+        lqw.eq(bo.getUserId() != null, OrderEvaluationHeader::getUserId, bo.getUserId());
+        return lqw;
+    }
+
+    /**
+     * 新增/更新 订单评价 (核心逻辑)
+     * 策略:
+     * 1. 检查订单是否已有评价。
+     * 2. 无记录 -> 首次评价 (Insert 主表 + Insert 明细)。
+     * 3. 有记录 ->
+     * - 若为首次评价请求 -> 报错。
+     * - 若为追评请求 -> 更新主表 + 更新明细 (Update)。
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertByBo(OrderEvaluationHeaderBo bo) {
+        // 1. 基础校验
+        if (bo.getOrderId() == null) {
+            throw new ServiceException("订单 ID 不能为空");
+        }
+        if (bo.getOrderEvaluationItemList() == null || bo.getOrderEvaluationItemList().isEmpty()) {
+            throw new ServiceException("至少需要评价一个商品");
+        }
+
+        // 2. 查询该订单是否已存在有效评价
+        OrderEvaluationHeader existingHeader = baseMapper.selectOne(Wrappers.<OrderEvaluationHeader>lambdaQuery()
+            .eq(OrderEvaluationHeader::getOrderId, bo.getOrderId())
+            .eq(OrderEvaluationHeader::getDelFlag, "0"));
+
+        if (existingHeader == null) {
+            // --- 场景 A: 首次评价 (INSERT) ---
+            return doFirstEvaluation(bo);
+        } else {
+            // --- 场景 B: 已存在评价 (UPDATE/追评) ---
+            return doAppendEvaluation(bo, existingHeader);
+        }
+    }
+
+    /**
+     * 执行首次评价逻辑
+     */
+    private Boolean doFirstEvaluation(OrderEvaluationHeaderBo bo) {
+        // 校验类型
+        if (bo.getEvaluationType() != null && bo.getEvaluationType() != 1) {
+            throw new ServiceException("新订单只能进行首次评价 (type=1)");
+        }
+
+        // 转换主表对象
+        OrderEvaluationHeader header = MapstructUtils.convert(bo, OrderEvaluationHeader.class);
+        header.setEvaluationType(1); // 强制设为首次
+
+        validEntityBeforeSave(header);
+
+        // 插入主表
+        if (baseMapper.insert(header) <= 0) {
+            throw new ServiceException("评价主表保存失败");
+        }
+
+        Long evaluationId = header.getId();
+
+        // 处理明细表 (Insert)
+        List<OrderEvaluationItem> items = buildEvaluationItems(bo, evaluationId);
+        if (!items.isEmpty()) {
+            if (!itemMapper.insertBatch(items)) {
+                throw new ServiceException("评价明细保存失败");
+            }
+        }
+
+        bo.setId(evaluationId);
+        return true;
+    }
+
+    /**
+     * 执行追评/更新逻辑
+     * 需求:不加字段,直接更新原记录。
+     */
+    private Boolean doAppendEvaluation(OrderEvaluationHeaderBo bo, OrderEvaluationHeader existingHeader) {
+        // 1. 校验是否为追评请求
+        // 如果前端传 type=1 但库里有数据,说明重复提交首次评价
+        if (bo.getEvaluationType() == null || bo.getEvaluationType() == 1) {
+            throw new ServiceException("该订单已完成首次评价,如需修改或补充请提交追评 (type=2)");
+        }
+
+        // 2. 准备更新主表数据
+        OrderEvaluationHeader updateHeader = new OrderEvaluationHeader();
+        updateHeader.setId(existingHeader.getId());
+
+        // 更新评价类型为追评 (如果之前是首次)
+        updateHeader.setEvaluationType(2);
+
+        // 更新评分 (如果前端传了新的评分,覆盖旧的;没传则保持原样)
+        if (bo.getLogisticsPackScore() != null) updateHeader.setLogisticsPackScore(bo.getLogisticsPackScore());
+        if (bo.getDeliverSpeedScore() != null) updateHeader.setDeliverSpeedScore(bo.getDeliverSpeedScore());
+        if (bo.getCourierServiceScore() != null) updateHeader.setCourierServiceScore(bo.getCourierServiceScore());
+
+        // 更新备注/内容
+        if (StringUtils.isNotBlank(bo.getRemark())) {
+            updateHeader.setRemark(bo.getRemark());
+        }
+
+        // 更新其他可能需要的字段 (如 userId, customerId 如果需要刷新)
+        if (bo.getUserId() != null) updateHeader.setUserId(bo.getUserId());
+        if (bo.getCustomerId() != null) updateHeader.setCustomerId(bo.getCustomerId());
+
+        // 执行主表更新
+        if (baseMapper.updateById(updateHeader) <= 0) {
+            throw new ServiceException("评价主表更新失败");
+        }
+
+        // 3. 处理明细表 (Update)
+
+        Long evaluationId = existingHeader.getId();
+        for (OrderEvaluationItemBo itemBo : bo.getOrderEvaluationItemList()) {
+            // 构建更新对象
+            OrderEvaluationItem updateItem = new OrderEvaluationItem();
+
+            // 定位逻辑:
+            // 情况 A: 前端传了明细主键 id (推荐,最准确)
+            if (itemBo.getId() != null) {
+                updateItem.setId(itemBo.getId());
+                // 额外校验:确保这个 id 属于当前的 evaluationId,防止越权
+            }
+            // 情况 B: 前端没传 id,只传了 orderItemId (需要根据 orderItemId 和 evaluationId 查询出真正的 id)
+            else if (itemBo.getOrderItemId() != null) {
+                OrderEvaluationItem existItem = itemMapper.selectOne(Wrappers.<OrderEvaluationItem>lambdaQuery()
+                    .eq(OrderEvaluationItem::getEvaluationId, evaluationId)
+                    .eq(OrderEvaluationItem::getOrderItemId, itemBo.getOrderItemId())
+                    .last("LIMIT 1"));
+
+                if (existItem == null) {
+
+                    log.warn("追评中未找到原明细记录 orderItemId: {}, 将尝试新增", itemBo.getOrderItemId());
+                    // 转去走新增逻辑 (复用 build 逻辑的一部分,但需要 evaluationId)
+                    OrderEvaluationItem newItem = MapstructUtils.convert(itemBo, OrderEvaluationItem.class);
+                    newItem.setEvaluationId(evaluationId);
+                    newItem.setOrderId(bo.getOrderId());
+                    validateItemScore(newItem);
+                    itemMapper.insert(newItem);
+                    continue;
+                }
+                updateItem.setId(existItem.getId());
+            } else {
+                throw new ServiceException("追评明细必须包含 id 或 orderItemId 以定位记录");
+            }
+
+            // 填充需要更新的字段 (非空则更新)
+            if (itemBo.getProductScore() != null) updateItem.setProductScore(itemBo.getProductScore());
+            if (StringUtils.isNotBlank(itemBo.getContent())) updateItem.setContent(itemBo.getContent());
+            if (StringUtils.isNotBlank(itemBo.getImages())) updateItem.setImages(itemBo.getImages());
+            if (StringUtils.isNotBlank(itemBo.getRemark())) updateItem.setRemark(itemBo.getRemark());
+
+            // 只有当有实际更新内容时才执行 update,避免空更新
+            // 这里简单起见,只要定位到了就更新
+            if (updateItem.getId() != null) {
+                if (itemMapper.updateById(updateItem) <= 0) {
+                    throw new ServiceException("评价明细更新失败,ID:" + updateItem.getId());
+                }
+            }
+        }
+
+        bo.setId(evaluationId);
+        return true;
+    }
+
+
+    /**
+     * 辅助方法:构建明细列表 (用于首次评价插入)
+     */
+    private List<OrderEvaluationItem> buildEvaluationItems(OrderEvaluationHeaderBo bo, Long evaluationId) {
+        return bo.getOrderEvaluationItemList().stream().map(itemBo -> {
+            OrderEvaluationItem item = MapstructUtils.convert(itemBo, OrderEvaluationItem.class);
+            item.setEvaluationId(evaluationId);
+            item.setOrderId(bo.getOrderId());
+            validateItemScore(item);
+            return item;
+        }).collect(Collectors.toList());
+    }
+
+    private void validateItemScore(OrderEvaluationItem item) {
+        if (item.getProductScore() != null && (item.getProductScore() < 1 || item.getProductScore() > 5)) {
+            throw new ServiceException("商品评分必须在 1-5 之间");
+        }
+    }
+
+    /**
+     * 修改订单评价主
+     *
+     * @param bo 订单评价主
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(OrderEvaluationHeaderBo bo) {
+        OrderEvaluationHeader update = MapstructUtils.convert(bo, OrderEvaluationHeader.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(OrderEvaluationHeader entity) {
+        // 校验评分范围
+        validateScore(entity.getLogisticsPackScore(), "快递包装评分");
+        validateScore(entity.getDeliverSpeedScore(), "送货速度评分");
+        validateScore(entity.getCourierServiceScore(), "配送员服务评分");
+
+        // 校验评价类型
+        if (entity.getEvaluationType() != null && !List.of(1, 2).contains(entity.getEvaluationType())) {
+            throw new ServiceException("评价类型错误");
+        }
+    }
+
+    private void validateScore(Integer score, String fieldName) {
+        if (score != null && (score < 1 || score > 5)) {
+            throw new ServiceException(fieldName + "必须在1-5之间");
+        }
+    }
+
+    /**
+     * 校验并批量删除订单评价主信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 142 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/service/impl/OrderEvaluationItemServiceImpl.java

@@ -0,0 +1,142 @@
+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.OrderEvaluationItemBo;
+import org.dromara.order.domain.vo.OrderEvaluationItemVo;
+import org.dromara.order.domain.OrderEvaluationItem;
+import org.dromara.order.mapper.OrderEvaluationItemMapper;
+import org.dromara.order.service.IOrderEvaluationItemService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 订单评价明细Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-03-09
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class OrderEvaluationItemServiceImpl  extends ServiceImpl<OrderEvaluationItemMapper, OrderEvaluationItem> implements IOrderEvaluationItemService {
+
+    private final OrderEvaluationItemMapper baseMapper;
+
+    /**
+     * 查询订单评价明细
+     *
+     * @param id 主键
+     * @return 订单评价明细
+     */
+    @Override
+    public OrderEvaluationItemVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询订单评价明细列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 订单评价明细分页列表
+     */
+    @Override
+    public TableDataInfo<OrderEvaluationItemVo> queryPageList(OrderEvaluationItemBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<OrderEvaluationItem> lqw = buildQueryWrapper(bo);
+        Page<OrderEvaluationItemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的订单评价明细列表
+     *
+     * @param bo 查询条件
+     * @return 订单评价明细列表
+     */
+    @Override
+    public List<OrderEvaluationItemVo> queryList(OrderEvaluationItemBo bo) {
+        LambdaQueryWrapper<OrderEvaluationItem> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<OrderEvaluationItem> buildQueryWrapper(OrderEvaluationItemBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<OrderEvaluationItem> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(OrderEvaluationItem::getId);
+        lqw.eq(bo.getEvaluationId() != null, OrderEvaluationItem::getEvaluationId, bo.getEvaluationId());
+        lqw.eq(bo.getOrderId() != null, OrderEvaluationItem::getOrderId, bo.getOrderId());
+        lqw.eq(bo.getOrderItemId() != null, OrderEvaluationItem::getOrderItemId, bo.getOrderItemId());
+        lqw.eq(bo.getProductId() != null, OrderEvaluationItem::getProductId, bo.getProductId());
+        lqw.like(StringUtils.isNotBlank(bo.getProductName()), OrderEvaluationItem::getProductName, bo.getProductName());
+        lqw.eq(StringUtils.isNotBlank(bo.getProductImg()), OrderEvaluationItem::getProductImg, bo.getProductImg());
+        lqw.eq(bo.getProductScore() != null, OrderEvaluationItem::getProductScore, bo.getProductScore());
+        lqw.eq(StringUtils.isNotBlank(bo.getContent()), OrderEvaluationItem::getContent, bo.getContent());
+        lqw.eq(StringUtils.isNotBlank(bo.getImages()), OrderEvaluationItem::getImages, bo.getImages());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), OrderEvaluationItem::getPlatformCode, bo.getPlatformCode());
+        return lqw;
+    }
+
+    /**
+     * 新增订单评价明细
+     *
+     * @param bo 订单评价明细
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(OrderEvaluationItemBo bo) {
+        OrderEvaluationItem add = MapstructUtils.convert(bo, OrderEvaluationItem.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改订单评价明细
+     *
+     * @param bo 订单评价明细
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(OrderEvaluationItemBo bo) {
+        OrderEvaluationItem update = MapstructUtils.convert(bo, OrderEvaluationItem.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(OrderEvaluationItem entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除订单评价明细信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 48 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderEvaluationHeaderMapper.xml

@@ -0,0 +1,48 @@
+<?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.OrderEvaluationHeaderMapper">
+
+    <select id="selectEvaluationOrderListPage" resultType="org.dromara.order.domain.vo.OrderEvaluationListVo">
+        SELECT
+        o.id AS orderId,
+        o.order_no AS orderNo,
+        o.order_time AS orderTime,
+        o.total_amount AS totalAmount,
+        o.order_status as orderStatus,
+        CASE
+        WHEN oe.max_type IS NULL THEN '0'
+        WHEN oe.max_type = 1 THEN '1'
+        WHEN oe.max_type = 2 THEN '2'
+        ELSE '0'
+        END AS evaluationStatus
+        FROM order_main o
+        LEFT JOIN (
+        SELECT order_id, MAX(evaluation_type) AS max_type
+        FROM order_evaluation_header --
+        WHERE del_flag = '0'
+        GROUP BY order_id
+        ) oe ON o.id = oe.order_id
+        WHERE
+        o.customer_id = #{customerId}
+        AND o.order_status = '5'
+        AND o.del_flag = '0'
+
+        <choose>
+            <when test="evaluationStatus != null and evaluationStatus == '0'">
+                AND oe.max_type IS NULL
+            </when>
+            <when test="evaluationStatus != null and evaluationStatus == '1'">
+                AND oe.max_type = 1
+            </when>
+            <when test="evaluationStatus != null and evaluationStatus == '2'">
+                AND oe.max_type = 2
+            </when>
+            <!-- 如果 evaluationStatus 为空或为其他值,则不过滤评价状态,返回所有 -->
+        </choose>
+
+        ORDER BY o.order_time DESC
+    </select>
+
+</mapper>

+ 7 - 0
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderEvaluationItemMapper.xml

@@ -0,0 +1,7 @@
+<?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.OrderEvaluationItemMapper">
+
+</mapper>

+ 6 - 1
ruoyi-modules/ruoyi-order/src/main/resources/mapper/order/OrderMainMapper.xml

@@ -26,17 +26,20 @@
         WHEN oe.max_type IS NULL THEN '0'
         WHEN oe.max_type = 1 THEN '1'
         WHEN oe.max_type = 2 THEN '2'
+        ELSE '0'
         END AS evaluationStatus
         FROM order_main o
         LEFT JOIN (
         SELECT order_id, MAX(evaluation_type) AS max_type
-        FROM order_evaluation
+        FROM order_evaluation_header --
+        WHERE del_flag = '0'
         GROUP BY order_id
         ) oe ON o.id = oe.order_id
         WHERE
         o.customer_id = #{customerId}
         AND o.order_status = '5'
         AND o.del_flag = '0'
+
         <choose>
             <when test="evaluationStatus != null and evaluationStatus == '0'">
                 AND oe.max_type IS NULL
@@ -47,7 +50,9 @@
             <when test="evaluationStatus != null and evaluationStatus == '2'">
                 AND oe.max_type = 2
             </when>
+            <!-- 如果 evaluationStatus 为空或为其他值,则不过滤评价状态,返回所有 -->
         </choose>
+
         ORDER BY o.order_time DESC
     </select>
 </mapper>

+ 4 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/pc/PcSysUserController.java

@@ -35,6 +35,10 @@ public class PcSysUserController extends BaseController {
         user.setUserId(userId);
         //先校验验证码是否正确
         String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + user.getPhonenumber());
+        if (code == null) {
+            throw new ServiceException("验证码已过期");
+        }
+
         if (!code.equals(user.getCode())) {
             throw new ServiceException("验证码错误");
         }