Browse Source

Merge branch 'mall_trade_aftersalelog' of https://gitee.com/chen934298133/ruoyi-vue-pro into feature/mall_product

 Conflicts:
	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java
YunaiV 2 năm trước cách đây
mục cha
commit
07884ef423
21 tập tin đã thay đổi với 212 bổ sung299 xóa
  1. 5 0
      yudao-dependencies/pom.xml
  2. 0 1
      yudao-framework/pom.xml
  3. 0 82
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spel/SpelUtil.java
  4. 52 2
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java
  5. 0 54
      yudao-framework/yudao-spring-boot-starter-biz-trade/pom.xml
  6. 0 16
      yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/config/YudaoAfterSaleLogAutoConfiguration.java
  7. 0 73
      yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/aop/AfterSaleLogAspect.java
  8. 0 18
      yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/service/AfterSaleLogService.java
  9. 0 1
      yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  10. 7 6
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleOperateTypeEnum.java
  11. 0 5
      yudao-module-mall/yudao-module-trade-biz/pom.xml
  12. 0 18
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
  13. 3 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java
  14. 0 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java
  15. 21 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/config/AfterSaleLogConfiguration.java
  16. 5 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/annotations/AfterSaleLog.java
  17. 85 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/aop/AfterSaleLogAspect.java
  18. 5 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/dto/TradeAfterSaleLogCreateReqDTO.java
  19. 23 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/service/AfterSaleLogService.java
  20. 6 5
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
  21. 0 3
      yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java

+ 5 - 0
yudao-dependencies/pom.xml

@@ -96,6 +96,11 @@
                 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
                 <version>${revision}</version>
             </dependency>
+            <dependency>
+                <groupId>cn.iocoder.boot</groupId>
+                <artifactId>yudao-spring-boot-starter-biz-trade</artifactId>
+                <version>${revision}</version>
+            </dependency>
             <dependency>
                 <groupId>cn.iocoder.boot</groupId>
                 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>

+ 0 - 1
yudao-framework/pom.xml

@@ -31,7 +31,6 @@
         <module>yudao-spring-boot-starter-biz-sms</module>
 
         <module>yudao-spring-boot-starter-biz-pay</module>
-        <module>yudao-spring-boot-starter-biz-trade</module>
         <module>yudao-spring-boot-starter-biz-weixin</module>
         <module>yudao-spring-boot-starter-biz-social</module>
         <module>yudao-spring-boot-starter-biz-tenant</module>

+ 0 - 82
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spel/SpelUtil.java

@@ -1,82 +0,0 @@
-package cn.iocoder.yudao.framework.common.util.spel;
-
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.springframework.core.DefaultParameterNameDiscoverer;
-import org.springframework.expression.EvaluationContext;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
-import org.springframework.expression.spel.support.StandardEvaluationContext;
-
-// TODO @Chopper:和 SpringExpressionUtils 合并下
-/**
- * SpelUtil
- *
- * @author Chopper
- * @version v1.0
- * @since 2021-01-11 10:45
- */
-public class SpelUtil {
-
-
-    /**
-     * spel表达式解析器
-     */
-    private static SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
-    /**
-     * 参数名发现器
-     */
-    private static DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
-
-    /**
-     * 转换 jspl参数
-     *
-     * @param joinPoint
-     * @param spel
-     * @return
-     */
-    public static String compileParams(JoinPoint joinPoint, String spel) { //Spel表达式解析日志信息
-        //获得方法参数名数组
-        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
-
-        String[] parameterNames = parameterNameDiscoverer.getParameterNames(signature.getMethod());
-        if (parameterNames != null && parameterNames.length > 0) {
-            EvaluationContext context = new StandardEvaluationContext();
-
-            //获取方法参数值
-            Object[] args = joinPoint.getArgs();
-            for (int i = 0; i < args.length; i++) {
-                //替换spel里的变量值为实际值, 比如 #user -->  user对象
-                context.setVariable(parameterNames[i], args[i]);
-            }
-            return spelExpressionParser.parseExpression(spel).getValue(context).toString();
-        }
-        return "";
-    }
-
-    /**
-     * 转换 jspl参数
-     *
-     * @param joinPoint
-     * @param spel
-     * @return
-     */
-    public static String compileParams(JoinPoint joinPoint, Object rvt, String spel) { //Spel表达式解析日志信息
-        //获得方法参数名数组
-        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
-
-        String[] parameterNames = parameterNameDiscoverer.getParameterNames(signature.getMethod());
-        if (parameterNames != null && parameterNames.length > 0) {
-            EvaluationContext context = new StandardEvaluationContext();
-
-            //获取方法参数值
-            Object[] args = joinPoint.getArgs();
-            for (int i = 0; i < args.length; i++) {
-                //替换spel里的变量值为实际值, 比如 #user -->  user对象
-                context.setVariable(parameterNames[i], args[i]);
-            }
-            context.setVariable("rvt", rvt);
-            return spelExpressionParser.parseExpression(spel).getValue(context).toString();
-        }
-        return "";
-    }
-}

+ 52 - 2
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.spring;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ArrayUtil;
+import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.springframework.core.DefaultParameterNameDiscoverer;
@@ -24,7 +25,13 @@ import java.util.Map;
  */
 public class SpringExpressionUtils {
 
+    /**
+     * spel表达式解析器
+     */
     private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
+    /**
+     * 参数名发现器
+     */
     private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
 
     private SpringExpressionUtils() {
@@ -33,7 +40,7 @@ public class SpringExpressionUtils {
     /**
      * 从切面中,单个解析 EL 表达式的结果
      *
-     * @param joinPoint  切面点
+     * @param joinPoint        切面点
      * @param expressionString EL 表达式数组
      * @return 执行界面
      */
@@ -45,7 +52,7 @@ public class SpringExpressionUtils {
     /**
      * 从切面中,批量解析 EL 表达式的结果
      *
-     * @param joinPoint   切面点
+     * @param joinPoint         切面点
      * @param expressionStrings EL 表达式数组
      * @return 结果,key 为表达式,value 为对应值
      */
@@ -79,4 +86,47 @@ public class SpringExpressionUtils {
         });
         return result;
     }
+
+    /**
+     * JoinPoint 切面 批量解析 EL 表达式,转换 jspl参数
+     *
+     * @param joinPoint         切面点
+     * @param info              返回值
+     * @param expressionStrings EL 表达式数组
+     * @return Map<String, Object> 结果
+     * @author 陈賝
+     * @since 2023/6/18 11:20
+     */
+    public static Map<String, Object> parseExpression(JoinPoint joinPoint, Object info, List<String> expressionStrings) {
+        // 如果为空,则不进行解析
+        if (CollUtil.isEmpty(expressionStrings)) {
+            return MapUtil.newHashMap();
+        }
+
+        // 第一步,构建解析的上下文 EvaluationContext
+        // 通过 joinPoint 获取被注解方法
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        Method method = signature.getMethod();
+        // 使用 spring 的 ParameterNameDiscoverer 获取方法形参名数组
+        String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
+        // Spring 的表达式上下文对象
+        EvaluationContext context = new StandardEvaluationContext();
+        if (ArrayUtil.isNotEmpty(parameterNames)) {
+            //获取方法参数值
+            Object[] args = joinPoint.getArgs();
+            for (int i = 0; i < args.length; i++) {
+                //替换spel里的变量值为实际值, 比如 #user -->  user对象
+                context.setVariable(parameterNames[i], args[i]);
+            }
+            context.setVariable("info", info);
+        }
+        // 第二步,逐个参数解析
+        Map<String, Object> result = MapUtil.newHashMap(expressionStrings.size(), true);
+        expressionStrings.forEach(key -> {
+            Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context);
+            result.put(key, value);
+        });
+        return result;
+    }
+
 }

+ 0 - 54
yudao-framework/yudao-spring-boot-starter-biz-trade/pom.xml

@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>cn.iocoder.boot</groupId>
-        <artifactId>yudao-framework</artifactId>
-        <version>${revision}</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>yudao-spring-boot-starter-biz-trade</artifactId>
-    <packaging>jar</packaging>
-
-    <name>${project.artifactId}</name>
-    <description>交易模块</description>
-    <url>https://github.com/YunaiV/ruoyi-vue-pro</url>
-
-    <dependencies>
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-common</artifactId>
-        </dependency>
-
-        <!-- Spring 核心 -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-aop</artifactId>
-        </dependency>
-
-        <!-- Web 相关 -->
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-web</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <!-- 业务组件 -->
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行操作日志的记录 -->
-            <version>${revision}</version>
-        </dependency>
-
-        <!-- 工具类相关 -->
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-security</artifactId>
-        </dependency>
-    </dependencies>
-</project>

+ 0 - 16
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/config/YudaoAfterSaleLogAutoConfiguration.java

@@ -1,16 +0,0 @@
-package cn.iocoder.yudao.framework.trade.config;
-
-import cn.iocoder.yudao.framework.trade.core.aop.AfterSaleLogAspect;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.context.annotation.Bean;
-
-// TODO @Chopper:和 yudao-module-trade-biz 的 framework 里
-@AutoConfiguration
-public class YudaoAfterSaleLogAutoConfiguration {
-
-    @Bean
-    public AfterSaleLogAspect afterSaleLogAspect() {
-        return new AfterSaleLogAspect();
-    }
-
-}

+ 0 - 73
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/aop/AfterSaleLogAspect.java

@@ -1,73 +0,0 @@
-package cn.iocoder.yudao.framework.trade.core.aop;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.spring.SpringUtil;
-import cn.iocoder.yudao.framework.common.util.spel.SpelUtil;
-import cn.iocoder.yudao.framework.trade.core.annotations.AfterSaleLog;
-import cn.iocoder.yudao.framework.trade.core.dto.TradeAfterSaleLogCreateReqDTO;
-import cn.iocoder.yudao.framework.trade.core.enums.AfterSaleStatusEnum;
-import cn.iocoder.yudao.framework.trade.core.service.AfterSaleLogService;
-import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.AfterReturning;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.reflect.MethodSignature;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 记录售后日志的 AOP 切面
- *
- * @author 陈賝
- * @since 2023/6/13 13:54
- */
-@Slf4j
-@Aspect
-public class AfterSaleLogAspect {
-
-    @AfterReturning(pointcut = "@annotation(afterSaleLog)", returning = "info")
-    public void doAfterReturning(JoinPoint joinPoint, AfterSaleLog afterSaleLog, Object info) {
-        try {
-            // 日志对象拼接
-            Integer userType = WebFrameworkUtils.getLoginUserType();
-            Long id = WebFrameworkUtils.getLoginUserId();
-            Map<String, String> formatObj = spelFormat(joinPoint, info);
-            TradeAfterSaleLogCreateReqDTO dto = new TradeAfterSaleLogCreateReqDTO()
-                    .setUserId(id).setUserType(userType)
-//            MapUtil.getLong() TODO @陈賝:试试这个方法
-                    .setAfterSaleId(Long.valueOf(formatObj.get("id")))
-                    .setContent(formatObj.get("content"))
-                    .setOperateType(formatObj.get("operateType"));
-            // 异步存入数据库 TODO 可以注入哈;
-            SpringUtil.getBean(AfterSaleLogService.class).insert(dto);
-        } catch (Exception exception) {
-            // TODO @陈賝:日志要记录下参数哈,不然排查问题不好搞;
-            log.error("日志记录错误", exception);
-        }
-    }
-
-    /**
-     * 获取描述信息
-     */
-    public static Map<String, String> spelFormat(JoinPoint joinPoint, Object info) {
-        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
-        AfterSaleLog afterSaleLogPoint = signature.getMethod().getAnnotation(AfterSaleLog.class);
-        Map<String, String> result = new HashMap<>(2); // TODO @陈賝:Maps.newExpectedXXX(3)
-        // 售后ID
-        String id = SpelUtil.compileParams(joinPoint, info, afterSaleLogPoint.id());
-        result.put("id", id);
-        // 操作类型
-        String operateType = SpelUtil.compileParams(joinPoint, info, afterSaleLogPoint.operateType());
-        result.put("operateType", operateType);
-        // 日志内容
-        String content = SpelUtil.compileParams(joinPoint, info, afterSaleLogPoint.content());
-        if (StrUtil.isNotEmpty(afterSaleLogPoint.operateType())) {
-            content += AfterSaleStatusEnum.valueOf(SpelUtil.compileParams(joinPoint, info, afterSaleLogPoint.operateType())).description();
-        }
-        result.put("content", content);
-        return result;
-    }
-
-}

+ 0 - 18
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/service/AfterSaleLogService.java

@@ -1,18 +0,0 @@
-package cn.iocoder.yudao.framework.trade.core.service;
-
-import cn.iocoder.yudao.framework.trade.core.dto.TradeAfterSaleLogCreateReqDTO;
-
-// TODO @陈賝:类注释
-public interface AfterSaleLogService {
-
-    /**
-     * 创建售后日志
-     *
-     * @param logDTO 日志记录
-     * @author 陈賝
-     * @since 2023/6/12 14:18
-     */
-    // TODO @陈賝:createLog 方法名
-    void insert(TradeAfterSaleLogCreateReqDTO logDTO);
-
-}

+ 0 - 1
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1 +0,0 @@
-cn.iocoder.yudao.framework.trade.config.YudaoAfterSaleLogAutoConfiguration

+ 7 - 6
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/enums/AfterSaleStatusEnum.java → yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/AfterSaleOperateTypeEnum.java

@@ -1,21 +1,22 @@
-package cn.iocoder.yudao.framework.trade.core.enums;
+package cn.iocoder.yudao.module.trade.enums.aftersale;
 
 /**
- * 售后状态的枚举
+ * 售后操作类型的枚举
  *
  * @author 陈賝
  * @since 2023/6/13 13:53
  */
-public enum AfterSaleStatusEnum {
+public enum AfterSaleOperateTypeEnum {
 
     /**
-     * 申请
+     * 用户申请
      */
-    APPLY("申请中");
+    APPLY("用户申请"),
+    ;
 
     private final String description;
 
-    AfterSaleStatusEnum(String description) {
+    AfterSaleOperateTypeEnum(String description) {
         this.description = description;
     }
 

+ 0 - 5
yudao-module-mall/yudao-module-trade-biz/pom.xml

@@ -58,11 +58,6 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
         </dependency>
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-biz-trade</artifactId>
-            <version>${revision}</version>
-        </dependency>
 
         <!-- Web 相关 -->
         <dependency>

+ 0 - 18
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.admin.aftersale;
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.trade.core.annotations.AfterSaleLog;
 import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
@@ -12,7 +11,6 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSal
 import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSalePageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRespPageItemVO;
-import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
 import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert;
 import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
 import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
@@ -112,20 +110,4 @@ public class TradeAfterSaleController {
         return success(true);
     }
 
-    // TODO @陈賝:后续要删除下
-    /**
-     * 售后日志测试
-     *
-     * @param createReqVO
-     * @return cn.iocoder.yudao.framework.common.pojo.CommonResult<java.lang.Long>
-     * @author 陈賝
-     * @date 2023/6/14 21:39
-     */
-    @PostMapping(value = "/create")
-    @AfterSaleLog(id = "#createReqVO.orderItemId", content = "'申请售后:售后编号['+#createReqVO.orderItemId+'] , '", operateType = "#createReqVO.operateType")
-    public CommonResult<Long> createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) {
-        return success(1L);
-//        return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO));
-    }
-
 }

+ 3 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java

@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSa
 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSalePageItemRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog;
 import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -78,6 +80,7 @@ public class AppTradeAfterSaleController {
 
     @PostMapping(value = "/create")
     @Operation(summary = "申请售后")
+    @AfterSaleLog(id = "#info.data", content = "'申请售后:售后编号['+#info.data+'],订单编号['+#createReqVO.orderItemId+'], '", operateType = AfterSaleOperateTypeEnum.APPLY)
     public CommonResult<Long> createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) {
         return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO));
     }

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

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo;
 
 import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.framework.trade.core.enums.AfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
@@ -32,14 +31,6 @@ public class AppTradeAfterSaleCreateReqVO {
     @NotNull(message = "申请原因不能为空")
     private String applyReason;
 
-    // TODO @陈賝:这个参数不应该有呀。
-    /**
-     * @see AfterSaleStatusEnum
-     */
-    @Schema(description = "操作类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "操作类型不能为空")
-    private String operateType;
-
     @Schema(description = "补充描述", example = "商品质量不好")
     private String applyDescription;
 

+ 21 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/config/AfterSaleLogConfiguration.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.trade.framework.aftersalelog.config;
+
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.aop.AfterSaleLogAspect;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * trade 模块的 afterSaleLog 组件的 Configuration
+ *
+ * @author 陈賝
+ * @since 2023/6/18 11:09
+ */
+@Configuration(proxyBeanMethods = false)
+public class AfterSaleLogConfiguration {
+
+    @Bean
+    public AfterSaleLogAspect afterSaleLogAspect() {
+        return new AfterSaleLogAspect();
+    }
+
+}

+ 5 - 4
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/annotations/AfterSaleLog.java → yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/annotations/AfterSaleLog.java

@@ -1,4 +1,6 @@
-package cn.iocoder.yudao.framework.trade.core.annotations;
+package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations;
+
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleOperateTypeEnum;
 
 import java.lang.annotation.*;
 
@@ -8,7 +10,7 @@ import java.lang.annotation.*;
  * @author 陈賝
  * @since 2023/6/8 17:04
  */
-@Target({ElementType.METHOD,ElementType.TYPE})
+@Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface AfterSaleLog {
@@ -18,11 +20,10 @@ public @interface AfterSaleLog {
      */
     String id();
 
-    // TODO @陈賝:是不是改成一个操作的枚举?
     /**
      * 操作类型
      */
-    String operateType() default "";
+    AfterSaleOperateTypeEnum operateType();
 
     /**
      * 日志内容

+ 85 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/aop/AfterSaleLogAspect.java

@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.aop;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
+import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog;
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
+import static java.util.Arrays.asList;
+
+/**
+ * 记录售后日志的 AOP 切面
+ *
+ * @author 陈賝
+ * @since 2023/6/13 13:54
+ */
+@Slf4j
+@Aspect
+public class AfterSaleLogAspect {
+    @Resource
+    private AfterSaleLogService saleLogService;
+
+    private final static String OPERATE_TYPE = "operateType", ID = "id", CONTENT = "content";
+
+    /**
+     * 切面存入日志
+     */
+    @AfterReturning(pointcut = "@annotation(afterSaleLog)", returning = "info")
+    public void doAfterReturning(JoinPoint joinPoint, AfterSaleLog afterSaleLog, Object info) {
+        try {
+            // 日志对象拼接
+            Integer userType = WebFrameworkUtils.getLoginUserType();
+            Long id = WebFrameworkUtils.getLoginUserId();
+            Map<String, String> formatObj = spelFormat(joinPoint, info);
+            TradeAfterSaleLogCreateReqDTO dto = new TradeAfterSaleLogCreateReqDTO()
+                    .setUserId(id)
+                    .setUserType(userType)
+                    .setAfterSaleId(MapUtil.getLong(formatObj, ID))
+                    .setOperateType(MapUtil.getStr(formatObj, OPERATE_TYPE))
+                    .setContent(MapUtil.getStr(formatObj, CONTENT));
+            // 异步存入数据库
+            saleLogService.createLog(dto);
+        } catch (Exception exception) {
+            log.error("[afterSaleLog({}) 日志记录错误]", toJsonString(afterSaleLog), exception);
+        }
+    }
+
+    /**
+     * 获取描述信息
+     */
+    public static Map<String, String> spelFormat(JoinPoint joinPoint, Object info) {
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        AfterSaleLog afterSaleLogPoint = signature.getMethod().getAnnotation(AfterSaleLog.class);
+        HashMap<String, String> result = Maps.newHashMapWithExpectedSize(2);
+        Map<String, Object> spelMap = SpringExpressionUtils.parseExpression(joinPoint, info,
+                asList(afterSaleLogPoint.id(), afterSaleLogPoint.content()));
+        // 售后ID
+        String id = MapUtil.getStr(spelMap, afterSaleLogPoint.id());
+        result.put(ID, id);
+        // 操作类型
+        String operateType = afterSaleLogPoint.operateType().description();
+        result.put(OPERATE_TYPE, operateType);
+        // 日志内容
+        String content = MapUtil.getStr(spelMap, afterSaleLogPoint.content());
+        if (ObjectUtil.isNotNull(afterSaleLogPoint.operateType())) {
+            content += operateType;
+        }
+        result.put(CONTENT, content);
+        return result;
+    }
+
+}

+ 5 - 2
yudao-framework/yudao-spring-boot-starter-biz-trade/src/main/java/cn/iocoder/yudao/framework/trade/core/dto/TradeAfterSaleLogCreateReqDTO.java → yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/dto/TradeAfterSaleLogCreateReqDTO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.framework.trade.core.dto;
+package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -6,6 +6,9 @@ import lombok.NoArgsConstructor;
 
 /**
  * 售后日志的创建 Request DTO
+ *
+ * @author 陈賝
+ * @since 2023/6/19 09:54
  */
 @Data
 @NoArgsConstructor
@@ -18,7 +21,7 @@ public class TradeAfterSaleLogCreateReqDTO {
     private Long id;
     /**
      * 用户编号
-     *
+     * <p>
      * 关联 1:AdminUserDO 的 id 字段
      * 关联 2:MemberUserDO 的 id 字段
      */

+ 23 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/aftersalelog/core/service/AfterSaleLogService.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service;
+
+
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
+
+/**
+ * 交易售后日志 Service 接口
+ *
+ * @author 陈賝
+ * @since 2023/6/12 14:18
+ */
+public interface AfterSaleLogService {
+
+    /**
+     * 创建售后日志
+     *
+     * @param logDTO 日志记录
+     * @author 陈賝
+     * @since 2023/6/12 14:18
+     */
+    void createLog(TradeAfterSaleLogCreateReqDTO logDTO);
+
+}

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

@@ -5,8 +5,6 @@ import cn.hutool.core.util.RandomUtil;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
-import cn.iocoder.yudao.framework.trade.core.dto.TradeAfterSaleLogCreateReqDTO;
-import cn.iocoder.yudao.framework.trade.core.service.AfterSaleLogService;
 import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
@@ -26,6 +24,8 @@ 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.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
+import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
 import lombok.extern.slf4j.Slf4j;
@@ -40,6 +40,7 @@ import javax.annotation.Resource;
 import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
 /**
@@ -394,7 +395,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
                 .setAfterSaleId(afterSale.getId())
                 .setOperateType(afterStatus.toString());
         // TODO 废弃,待删除
-        this.insert(logDTO);
+        this.createLog(logDTO);
     }
 
     /**
@@ -406,7 +407,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
      */
     @Override
     @Async
-    public void insert(TradeAfterSaleLogCreateReqDTO logDTO) {
+    public void createLog(TradeAfterSaleLogCreateReqDTO logDTO) {
         try {
             TradeAfterSaleLogDO afterSaleLog = new TradeAfterSaleLogDO()
                     .setUserId(logDTO.getUserId())
@@ -416,7 +417,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
                     .setContent(logDTO.getContent());
             tradeAfterSaleLogMapper.insert(afterSaleLog);
         }catch (Exception exception){
-            log.error("日志记录错误", exception);
+            log.error("[request({}) 日志记录错误]", toJsonString(logDTO), exception);
         }
     }
 }

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

@@ -66,7 +66,6 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         AppTradeAfterSaleCreateReqVO createReqVO = new AppTradeAfterSaleCreateReqVO()
                 .setOrderItemId(1L).setRefundPrice(100).setWay(TradeAfterSaleWayEnum.RETURN_AND_REFUND.getWay())
                 .setApplyReason("退钱").setApplyDescription("快退")
-                .setOperateType("APPLY")
                 .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png"));
         // mock 方法(交易订单项)
         TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> {
@@ -103,8 +102,6 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest {
         assertEquals(afterSaleLog.getUserType(), UserTypeEnum.MEMBER.getValue());
         assertEquals(afterSaleLog.getAfterSaleId(), afterSaleId);
         assertPojoEquals(afterSale, orderItem, "id", "creator", "createTime", "updater", "updateTime");
-//        assertNull(afterSaleLog.getBeforeStatus());
-//        assertEquals(afterSaleLog.getAfterStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus());
         assertEquals(afterSaleLog.getContent(), TradeAfterSaleStatusEnum.APPLY.getContent());
     }