Эх сурвалжийг харах

trade:【交易售后】查询分页列表的前端

YunaiV 2 жил өмнө
parent
commit
00e66216c5
19 өөрчлөгдсөн 371 нэмэгдсэн , 181 устгасан
  1. 9 9
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java
  2. 5 5
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java
  3. 37 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleWayEnum.java
  4. 10 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java
  5. 6 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleBaseVO.java
  6. 7 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSalePageReqVO.java
  7. 5 5
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java
  8. 7 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java
  9. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java
  10. 12 6
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
  11. 13 5
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java
  12. 1 0
      yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql
  13. 18 0
      yudao-ui-admin/src/api/mall/trade/afterSale.js
  14. 0 6
      yudao-ui-admin/src/router/index.js
  15. 31 0
      yudao-ui-admin/src/utils/constants.js
  16. 8 0
      yudao-ui-admin/src/utils/dateUtils.js
  17. 5 0
      yudao-ui-admin/src/utils/dict.js
  18. 1 141
      yudao-ui-admin/src/views/mall/trade/afterSale/bak.vue
  19. 195 0
      yudao-ui-admin/src/views/mall/trade/afterSale/index.vue

+ 9 - 9
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java

@@ -17,15 +17,15 @@ import java.util.Arrays;
 @Getter
 public enum TradeAfterSaleStatusEnum implements IntArrayValuable {
 
-    APPLY(10,"申请中"),
-    SELLER_AGREE(20, "卖家通过"), // 卖家通过售后
-    BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货
-    WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款
-    COMPLETE(50, "完成"), // 完成退款
-
-    BUYER_CANCEL(61, "买家取消售后"),
-    SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后
-    SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后
+    APPLY(10,"申请中"), // 【申请售后】
+    SELLER_AGREE(20, "卖家通过"), // 卖家通过售后;【商品待退货】
+    BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货;【商家待收货】
+    WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款;等待退款【等待退款】
+    COMPLETE(50, "完成"), // 完成退款【退款成功】
+
+    BUYER_CANCEL(61, "买家取消售后"), // 【买家取消】
+    SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后;商家拒绝【商家拒绝】
+    SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后;【商家拒收货】
     ;
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleStatusEnum::getStatus).toArray();

+ 5 - 5
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleTypeEnum.java

@@ -9,23 +9,23 @@ import java.util.Arrays;
 /**
  * 交易售后 - 类型
  *
- * @author Sin
+ * @author 芋道源码
  */
 @RequiredArgsConstructor
 @Getter
 public enum TradeAfterSaleTypeEnum implements IntArrayValuable {
 
-    REFUND(10, "退款"),
-    RETURN_AND_REFUND(20, "退货退款");
+    IN_SALE(10, "售中退款"), // 交易完成前买家申请退款
+    AFTER_SALE(20, "售后退款"); // 交易完成后买家申请退款
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleTypeEnum::getType).toArray();
 
     /**
-     * 状态值
+     * 类型
      */
     private final Integer type;
     /**
-     * 状态
+     * 类型
      */
     private final String name;
 

+ 37 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleWayEnum.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.trade.enums.aftersale;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 交易售后 - 方式
+ *
+ * @author Sin
+ */
+@RequiredArgsConstructor
+@Getter
+public enum TradeAfterSaleWayEnum implements IntArrayValuable {
+
+    REFUND(10, "仅退款"),
+    RETURN_AND_REFUND(20, "退货退款");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeAfterSaleWayEnum::getWay).toArray();
+
+    /**
+     * 方式
+     */
+    private final Integer way;
+    /**
+     * 方式名
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 10 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderStatusEnum.java

@@ -52,6 +52,16 @@ public enum TradeOrderStatusEnum implements IntArrayValuable {
         return ObjectUtil.equals(status, CANCELED.getStatus());
     }
 
+    /**
+     * 判断指定状态,是否正处于【已完成】状态
+     *
+     * @param status 指定状态
+     * @return 是否
+     */
+    public static boolean isCompleted(Integer status) {
+        return ObjectUtil.equals(status, COMPLETED.getStatus());
+    }
+
     /**
      * 判断指定状态,是否有过【已付款】状态
      *

+ 6 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleBaseVO.java

@@ -22,14 +22,18 @@ public class TradeAfterSaleBaseVO {
     @NotNull(message = "售后流水号不能为空")
     private String no;
 
-    @ApiModelProperty(value = "售后状态", required = true, example = "2", notes = "参见 TradeAfterSaleStatusEnum 枚举")
+    @ApiModelProperty(value = "售后状态", required = true, example = "10", notes = "参见 TradeAfterSaleStatusEnum 枚举")
     @NotNull(message = "售后状态不能为空")
     private Integer status;
 
-    @ApiModelProperty(value = "售后类型", required = true, example = "2", notes = "参见 TradeAfterSaleTypeEnum 枚举")
+    @ApiModelProperty(value = "售后类型", required = true, example = "20", notes = "参见 TradeAfterSaleTypeEnum 枚举")
     @NotNull(message = "售后类型不能为空")
     private Integer type;
 
+    @ApiModelProperty(value = "售后方式", required = true, example = "10", notes = "参见 TradeAfterSaleWayEnum 枚举")
+    @NotNull(message = "售后方式不能为空")
+    private Integer way;
+
     @ApiModelProperty(value = "用户编号", required = true, example = "30337")
     @NotNull(message = "用户编号不能为空")
     private Long userId;

+ 7 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSalePageReqVO.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -24,14 +25,18 @@ public class TradeAfterSalePageReqVO extends PageParam {
     @ApiModelProperty(value = "售后流水号", example = "202211190847450020500077", notes = "模糊匹配")
     private String no;
 
-    @ApiModelProperty(value = "售后状态", example = "2", notes = "参见 TradeAfterSaleStatusEnum 枚举")
+    @ApiModelProperty(value = "售后状态", example = "10", notes = "参见 TradeAfterSaleStatusEnum 枚举")
     @InEnum(value = TradeAfterSaleStatusEnum.class, message = "售后状态必须是 {value}")
     private Integer status;
 
-    @ApiModelProperty(value = "售后类型", example = "2", notes = "参见 TradeAfterSaleTypeEnum 枚举")
+    @ApiModelProperty(value = "售后类型", example = "20", notes = "参见 TradeAfterSaleTypeEnum 枚举")
     @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
     private Integer type;
 
+    @ApiModelProperty(value = "售后方式", example = "10", notes = "参见 TradeAfterSaleWayEnum 枚举")
+    @InEnum(value = TradeAfterSaleWayEnum.class, message = "售后方式必须是 {value}")
+    private Integer way;
+
     @ApiModelProperty(value = "订单编号", example = "18078", notes = "模糊匹配")
     private String orderNo;
 

+ 5 - 5
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo;
 
 import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -18,10 +18,10 @@ public class AppTradeAfterSaleCreateReqVO {
     @NotNull(message = "订单项编号不能为空")
     private Long orderItemId;
 
-    @ApiModelProperty(name = "售后类型", required = true, example = "1", notes = "对应 TradeAfterSaleTypeEnum 枚举")
-    @NotNull(message = "售后类型不能为空")
-    @InEnum(value = TradeAfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
-    private Integer type;
+    @ApiModelProperty(name = "售后方式", required = true, example = "1", notes = "对应 TradeAfterSaleWayEnum 枚举")
+    @NotNull(message = "售后方式不能为空")
+    @InEnum(value = TradeAfterSaleWayEnum.class, message = "售后方式必须是 {value}")
+    private Integer way;
 
     @ApiModelProperty(name = "退款金额", required = true, example = "100", notes = "单位:分")
     @NotNull(message = "退款金额不能为空")

+ 7 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java

@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
@@ -42,6 +43,12 @@ public class TradeAfterSaleDO extends BaseDO {
      * 枚举 {@link TradeAfterSaleStatusEnum}
      */
     private Integer status;
+    /**
+     * 售后方式
+     *
+     * 枚举 {@link TradeAfterSaleWayEnum}
+     */
+    private Integer way;
     /**
      * 售后类型
      *

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java

@@ -16,6 +16,7 @@ public interface TradeAfterSaleMapper extends BaseMapperX<TradeAfterSaleDO> {
                 .likeIfPresent(TradeAfterSaleDO::getNo, reqVO.getNo())
                 .eqIfPresent(TradeAfterSaleDO::getStatus, reqVO.getStatus())
                 .eqIfPresent(TradeAfterSaleDO::getType, reqVO.getType())
+                .eqIfPresent(TradeAfterSaleDO::getWay, reqVO.getWay())
                 .likeIfPresent(TradeAfterSaleDO::getOrderNo, reqVO.getOrderNo())
                 .likeIfPresent(TradeAfterSaleDO::getSpuName, reqVO.getSpuName())
                 .betweenIfPresent(TradeAfterSaleDO::getCreateTime, reqVO.getCreateTime())

+ 12 - 6
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java

@@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@@ -88,7 +89,6 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         if (!TradeOrderItemAfterSaleStatusEnum.isNone(orderItem.getAfterSaleStatus())) {
             throw exception(AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED);
         }
-        // TODO 芋艿:超过一定时间,不允许售后
 
         // 申请的退款金额,不能超过商品的价格
         if (createReqVO.getRefundPrice() > orderItem.getOrderDividePrice()) {
@@ -100,6 +100,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         if (order == null) {
             throw exception(ORDER_NOT_FOUND);
         }
+        // TODO 芋艿:超过一定时间,不允许售后
         // 已取消,无法发起售后
         if (TradeOrderStatusEnum.isCanceled(order.getStatus())) {
             throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_CANCELED);
@@ -109,7 +110,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
             throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID);
         }
         // 如果是【退货退款】的情况,需要额外校验是否发货
-        if (createReqVO.getType().equals(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType())
+        if (createReqVO.getWay().equals(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay())
             && !TradeOrderStatusEnum.haveDelivered(order.getStatus())) {
             throw exception(AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED);
         }
@@ -117,16 +118,21 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
     }
 
     private TradeAfterSaleDO createAfterSale(AppTradeAfterSaleCreateReqVO createReqVO,
-                                             TradeOrderItemDO tradeOrderItem) {
+                                             TradeOrderItemDO orderItem) {
         // 创建售后单
-        TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, tradeOrderItem);
+        TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, orderItem);
         afterSale.setNo(RandomUtil.randomString(10)); // TODO 芋艿:优化 no 生成逻辑
         afterSale.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus());
+        // 标记是售中还是售后
+        TradeOrderDO order = tradeOrderService.getOrder(orderItem.getUserId(), orderItem.getOrderId());
+        afterSale.setOrderNo(order.getNo()); // 记录 orderNo 订单流水,方便后续检索
+        afterSale.setType(TradeOrderStatusEnum.isCompleted(order.getStatus())
+            ? TradeAfterSaleTypeEnum.AFTER_SALE.getType() : TradeAfterSaleTypeEnum.IN_SALE.getType());
         // TODO 退还积分
         tradeAfterSaleMapper.insert(afterSale);
 
         // 更新交易订单项的售后状态
-        tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(),
+        tradeOrderService.updateOrderItemAfterSaleStatus(orderItem.getId(),
                 TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(),
                 TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null);
 
@@ -145,7 +151,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
         // 更新售后单的状态
         // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态
         // 情况二:退货退款:需要等用户退货后,才能发起退款
-        Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ?
+        Integer newStatus = afterSale.getType().equals(TradeAfterSaleWayEnum.REFUND.getWay()) ?
                 TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus();
         updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
                 .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()));

+ 13 - 5
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java

@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.aftersale.TradeAfterSaleMapper;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
@@ -58,7 +59,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         // 准备参数
         Long userId = 1024L;
         AppTradeAfterSaleCreateReqVO createReqVO = new AppTradeAfterSaleCreateReqVO()
-                .setOrderItemId(1L).setRefundPrice(100).setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType())
+                .setOrderItemId(1L).setRefundPrice(100).setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay())
                 .setApplyReason("退钱").setApplyDescription("快退")
                 .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png"));
         // mock 方法(交易订单项)
@@ -69,7 +70,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         when(tradeOrderService.getOrderItem(eq(1024L), eq(1L)))
                 .thenReturn(orderItem);
         // mock 方法(交易订单)
-        TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus()));
+        TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> o.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
+                .setNo("202211301234"));
         when(tradeOrderService.getOrder(eq(1024L), eq(111L))).thenReturn(order);
 
         // 调用
@@ -78,9 +80,11 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(afterSaleId);
         assertNotNull(afterSale.getNo());
         assertEquals(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus());
+        assertEquals(afterSale.getType(), TradeAfterSaleTypeEnum.IN_SALE.getType());
         assertPojoEquals(afterSale, createReqVO);
         assertEquals(afterSale.getUserId(), 1024L);
         assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
+        assertEquals(afterSale.getOrderNo(), "202211301234");
         assertNull(afterSale.getPayRefundId());
         assertNull(afterSale.getRefundTime());
         assertNull(afterSale.getLogisticsId());
@@ -95,7 +99,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         TradeAfterSaleDO dbAfterSale = randomPojo(TradeAfterSaleDO.class, o -> { // 等会查询到
             o.setNo("202211190847450020500077");
             o.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus());
-            o.setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType());
+            o.setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay());
+            o.setType(TradeAfterSaleTypeEnum.IN_SALE.getType());
             o.setOrderNo("202211190847450020500011");
             o.setSpuName("芋艿");
             o.setCreateTime(buildTime(2022, 1, 15));
@@ -105,8 +110,10 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setNo("202211190847450020500066")));
         // 测试 status 不匹配
         tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus())));
+        // 测试 way 不匹配
+        tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setWay(TradeAfterSaleWayEnum.REFUND.getWay())));
         // 测试 type 不匹配
-        tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(TradeAfterSaleTypeEnum.REFUND.getType())));
+        tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setType(TradeAfterSaleTypeEnum.AFTER_SALE.getType())));
         // 测试 orderNo 不匹配
         tradeAfterSaleMapper.insert(cloneIgnoreId(dbAfterSale, o -> o.setOrderNo("202211190847450020500022")));
         // 测试 spuName 不匹配
@@ -117,7 +124,8 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         TradeAfterSalePageReqVO reqVO = new TradeAfterSalePageReqVO();
         reqVO.setNo("20221119084745002050007");
         reqVO.setStatus(TradeAfterSaleStatusEnum.APPLY.getStatus());
-        reqVO.setType(TradeAfterSaleTypeEnum.RETURN_AND_REFUND.getType());
+        reqVO.setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay());
+        reqVO.setType(TradeAfterSaleTypeEnum.IN_SALE.getType());
         reqVO.setOrderNo("20221119084745002050001");
         reqVO.setSpuName("芋");
         reqVO.setCreateTime(new LocalDateTime[]{buildTime(2022, 1, 1), buildTime(2022, 1, 16)});

+ 1 - 0
yudao-module-mall/yudao-module-trade-biz/src/test/resources/sql/create_tables.sql

@@ -75,6 +75,7 @@ CREATE TABLE IF NOT EXISTS "trade_after_sale" (
     "no" varchar NOT NULL,
     "status" int NOT NULL,
     "type" int NOT NULL,
+    "way" int NOT NULL,
     "user_id" bigint NOT NULL,
     "apply_reason" varchar NOT NULL,
     "apply_description" varchar,

+ 18 - 0
yudao-ui-admin/src/api/mall/trade/afterSale.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 获得交易售后
+export function getAfterSale(id) {
+  return request({
+    url: '/trade/after-sale/get?id=' + id,
+    method: 'get'
+  })
+}
+
+// 获得交易售后分页
+export function getAfterSalePage(query) {
+  return request({
+    url: '/trade/after-sale/page',
+    method: 'get',
+    params: query
+  })
+}

+ 0 - 6
yudao-ui-admin/src/router/index.js

@@ -216,12 +216,6 @@ export const constantRoutes = [
         hidden: true,
         meta: { title: '订单详情' },
         component: (resolve) => require(['@/views/mall/trade/order/detail'], resolve)
-      },
-      {
-        path: '/mall/trade/orderrefund',
-        name: '退款维权',
-        meta: { title: '退款维权' },
-        component: (resolve) => require(['@/views/mall/trade/orderrefund'], resolve)
       }
     ]
   }

+ 31 - 0
yudao-ui-admin/src/utils/constants.js

@@ -3,6 +3,37 @@
  *
  * 枚举类
  */
+import {beginOfDay, endOfDay} from "@/utils/dateUtils";
+
+export const datePickerOptions = {
+  shortcuts: [{
+    text: '最近一周',
+    onClick(picker) {
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+      const end = new Date();
+      picker.$emit('pick', [beginOfDay(start), endOfDay(end)]);
+    }
+  }, {
+    text: '最近一个月',
+    onClick(picker) {
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+      const end = new Date();
+      picker.$emit('pick', [beginOfDay(start), endOfDay(end)]);
+    }
+  }, {
+    text: '最近三个月',
+    onClick(picker) {
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+      const end = new Date();
+      picker.$emit('pick', [beginOfDay(start), endOfDay(end)]);
+    }
+  }]
+}
+
+// ========== 静态变量 ==========
 
 /**
  * 全局通用状态枚举

+ 8 - 0
yudao-ui-admin/src/utils/dateUtils.js

@@ -24,3 +24,11 @@ export function getDate(ms) {
     return 0 + "秒";
   }
 }
+
+export function beginOfDay(date) {
+  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
+}
+
+export function endOfDay(date) {
+  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
+}

+ 5 - 0
yudao-ui-admin/src/utils/dict.js

@@ -60,6 +60,11 @@ export const DICT_TYPE = {
   // ========== MALL - PRODUCT 模块 ==========
   PRODUCT_SPU_STATUS: 'product_spu_status', // 商品 SPU 状态
 
+  // ========== MALL - ORDER 模块 ==========
+  TRADE_AFTER_SALE_STATUS: 'trade_after_sale_status', // 售后 - 状态
+  TRADE_AFTER_SALE_WAY: 'trade_after_sale_way', // 售后 - 方式
+  TRADE_AFTER_SALE_TYPE: 'trade_after_sale_type', // 售后 - 类型
+
   // ========== MALL - PROMOTION 模块 ==========
   PROMOTION_DISCOUNT_TYPE: 'promotion_discount_type', // 优惠类型
   PROMOTION_PRODUCT_SCOPE: 'promotion_product_scope', // 营销的商品范围

+ 1 - 141
yudao-ui-admin/src/views/mall/trade/orderrefund/index.vue → yudao-ui-admin/src/views/mall/trade/afterSale/bak.vue

@@ -3,42 +3,6 @@
     <!-- 搜索工作栏 -->
     <el-row :gutter="20">
       <el-form :model="queryParams" label-width="68px" size="small">
-        <el-col :span="6" :xs="24">
-          <el-form-item label="商品名称">
-            <el-input v-model="queryParams.name" style="width: 240px"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="6" :xs="24">
-          <el-form-item label="订单编号">
-            <el-input v-model="queryParams.No" style="width: 240px"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="6" :xs="24">
-          <el-form-item label="退款编号">
-            <el-input v-model="queryParams.refundNo" style="width: 240px"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="6" :xs="24">
-          <el-form-item label="退款状态">
-            <el-select v-model="queryParams.refundStatus" clearable style="width: 240px">
-              <el-option v-for="dict in dicData.refundStatus" v-bind="dict" :key="dict.value"/>
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="6" :xs="24">
-          <el-form-item label="退款方式">
-            <el-select v-model="queryParams.refundWay" clearable style="width: 240px">
-              <el-option v-for="dict in dicData.refundWay" v-bind="dict" :key="dict.value"/>
-            </el-select>
-          </el-form-item>
-        </el-col>
-        <el-col :span="6" :xs="24">
-          <el-form-item label="维权类型">
-            <el-select v-model="queryParams.refundType" clearable style="width: 240px">
-              <el-option v-for="dict in dicData.refundType" v-bind="dict" :key="dict.value"/>
-            </el-select>
-          </el-form-item>
-        </el-col>
         <el-col :span="6" :xs="24">
           <el-form-item label="下单时间">
             <el-date-picker v-model="queryParams.date" type="daterange" range-separator="至"
@@ -60,12 +24,6 @@
         <el-table :data="tableData" :show-header="false" class="table-wrapper">
           <el-table-column>
             <template slot-scope="{ row }">
-              <div class="table-header">
-                退款编号:{{row.tkbh}}
-                <el-button type="text" style="margin-left: 10px">
-                  订单编号:{{row.ddbh}}
-                </el-button>
-              </div>
               <!-- 订单下的商品 -->
               <el-table :data="row.goods" border>
                 <el-table-column label="商品信息" prop="spxx" header-align="center" width="auto" min-width="300">
@@ -114,33 +72,7 @@ const dicData = {
     { label: '售后退款', value: 'shtk' }
   ]
 }
-const rangePickerOptions = {
-  shortcuts: [{
-    text: '最近一周',
-    onClick(picker) {
-      const end = new Date();
-      const start = new Date();
-      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
-      picker.$emit('pick', [start, end]);
-    }
-  }, {
-    text: '最近一个月',
-    onClick(picker) {
-      const end = new Date();
-      const start = new Date();
-      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
-      picker.$emit('pick', [start, end]);
-    }
-  }, {
-    text: '最近三个月',
-    onClick(picker) {
-      const end = new Date();
-      const start = new Date();
-      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
-      picker.$emit('pick', [start, end]);
-    }
-  }]
-}
+
 export default {
     name: "index",
     data () {
@@ -164,15 +96,6 @@ export default {
             tkbh: '20221026220424001',
             ddbh: '20221026220424001',
             goods: [
-              {
-                name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
-                img: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
-                ddje: '199',
-                mj: '张三',
-                tkje: 460,
-                sqsj: '2022-11-19',
-                tkzt: '申请维权(仅退款)'
-              },
               {
                 name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
                 img: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
@@ -188,15 +111,6 @@ export default {
             tkbh: '20221026220424001',
             ddbh: '20221026220424001',
             goods: [
-              {
-                name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
-                img: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
-                ddje: '199',
-                mj: '张三',
-                tkje: 460,
-                sqsj: '2022-11-19',
-                tkzt: '申请维权(仅退款)'
-              },
               {
                 name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
                 img: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
@@ -212,15 +126,6 @@ export default {
             tkbh: '20221026220424001',
             ddbh: '20221026220424001',
             goods: [
-              {
-                name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
-                img: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
-                ddje: '199',
-                mj: '张三',
-                tkje: 460,
-                sqsj: '2022-11-19',
-                tkzt: '申请维权(仅退款)'
-              },
               {
                 name: '颜衫短袖男polo衫夏季翻领衣服潮牌休闲上衣夏天翻领半袖男士t恤',
                 img: 'https://b2c-v5-yanshi.oss-cn-hangzhou.aliyuncs.com/upload/1/common/images/20220723/20220723115621165854858145027_SMALL.webp',
@@ -242,48 +147,3 @@ export default {
     }
   }
 </script>
-
-<style lang="scss" scoped>
-  ::v-deep .table-wrapper{
-    border-bottom: none;
-    &::before{
-      height: 0;
-    }
-    .table-header{
-      line-height: 36px;
-    }
-    .el-table__row{
-      .el-table__cell{
-        border-bottom: none;
-        .cell{
-          .el-table {
-            .el-table__row{
-              >.el-table__cell{
-                .goods-info{
-                  display: flex;
-                  img{
-                    margin-right: 10px;
-                    width: 60px;
-                    height: 60px;
-                    border: 1px solid #e2e2e2;
-                  }
-                }
-                .ellipsis-2{
-                  display: -webkit-box;
-                  overflow: hidden;
-                  text-overflow: ellipsis;
-                  white-space: normal;
-                  -webkit-line-clamp: 2; /* 要显示的行数 */
-                  -webkit-box-orient: vertical;
-                  word-break: break-all;
-                  line-height: 22px !important;
-                  max-height: 44px !important;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-</style>

+ 195 - 0
yudao-ui-admin/src/views/mall/trade/afterSale/index.vue

@@ -0,0 +1,195 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品名称" prop="spuName">
+        <el-input v-model="queryParams.spuName" placeholder="请输入商品 SPU 名称" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="退款编号" prop="no">
+        <el-input v-model="queryParams.no" placeholder="请输入退款编号" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="订单编号" prop="orderNo">
+        <el-input v-model="queryParams.orderNo" placeholder="请输入订单编号" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="售后状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择售后状态" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.TRADE_AFTER_SALE_STATUS)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="售后方式" prop="way">
+        <el-select v-model="queryParams.way" placeholder="请选择售后方式" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.TRADE_AFTER_SALE_WAY)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="售后类型" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择售后类型" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.TRADE_AFTER_SALE_TYPE)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
+                        range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                        :picker-options="datePickerOptions" :default-time="['00:00:00', '23:59:59']" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="退款编号" align="center" prop="no" />
+      <el-table-column label="订单编号" align="center" prop="orderNo" />
+      <el-table-column label="订单编号" align="center" prop="orderNo" />
+      <el-table-column label="商品信息" align="center" prop="status" width="auto" min-width="300">
+        <!-- TODO @小红:样式不太对,辛苦改改 -->
+<!--        <div slot-scope="{ row }" class="goods-info">-->
+<!--          <img :src="row.picUrl"/>-->
+<!--          <span class="ellipsis-2" :title="row.name">{{row.name}}</span>-->
+<!--        </div>-->
+      </el-table-column>
+      <el-table-column label="订单金额" align="center" prop="refundPrice" />
+      <el-table-column label="买家" align="center" prop="userId" />
+      <el-table-column label="申请时间" align="center" prop="createTime" width="180">
+        <template v-slot="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="售后状态" align="center">
+        <template v-slot="scope">
+          <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column label="售后方式" align="center">
+        <template v-slot="scope">
+          <dict-tag :type="DICT_TYPE.TRADE_AFTER_SALE_WAY" :value="scope.row.way" />
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template v-slot="scope">
+<!--          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"-->
+<!--                     v-hasPermi="['trade:after-sale:update']">修改</el-button>-->
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+  </div>
+</template>
+
+<script>
+import { getAfterSalePage } from "@/api/mall/trade/afterSale";
+import { datePickerOptions } from "@/utils/constants";
+
+export default {
+  name: "AfterSale",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 交易售后列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        no: null,
+        status: null,
+        orderNo: null,
+        spuName: null,
+        createTime: [],
+        way: null,
+        type: null,
+      },
+      // 静态变量
+      datePickerOptions: datePickerOptions
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 执行查询
+      getAfterSalePage(this.queryParams).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+::v-deep .table-wrapper {
+  .el-table__row{
+    .el-table__cell {
+      border-bottom: none;
+      .cell{
+        .el-table {
+          .el-table__row {
+            >.el-table__cell {
+              .goods-info{
+                display: flex;
+                img{
+                  margin-right: 10px;
+                  width: 60px;
+                  height: 60px;
+                  border: 1px solid #e2e2e2;
+                }
+              }
+              .ellipsis-2 {
+                display: -webkit-box;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                white-space: normal;
+                -webkit-line-clamp: 2; /* 要显示的行数 */
+                -webkit-box-orient: vertical;
+                word-break: break-all;
+                line-height: 22px !important;
+                max-height: 44px !important;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>