mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	售后日志优化
This commit is contained in:
		| @ -96,11 +96,6 @@ | |||||||
|                 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId> |                 <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId> | ||||||
|                 <version>${revision}</version> |                 <version>${revision}</version> | ||||||
|             </dependency> |             </dependency> | ||||||
|             <dependency> |  | ||||||
|                 <groupId>cn.iocoder.boot</groupId> |  | ||||||
|                 <artifactId>yudao-spring-boot-starter-biz-trade</artifactId> |  | ||||||
|                 <version>${revision}</version> |  | ||||||
|             </dependency> |  | ||||||
|             <dependency> |             <dependency> | ||||||
|                 <groupId>cn.iocoder.boot</groupId> |                 <groupId>cn.iocoder.boot</groupId> | ||||||
|                 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> |                 <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> | ||||||
|  | |||||||
| @ -31,7 +31,6 @@ | |||||||
|         <module>yudao-spring-boot-starter-biz-sms</module> |         <module>yudao-spring-boot-starter-biz-sms</module> | ||||||
|  |  | ||||||
|         <module>yudao-spring-boot-starter-biz-pay</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-weixin</module> | ||||||
|         <module>yudao-spring-boot-starter-biz-social</module> |         <module>yudao-spring-boot-starter-biz-social</module> | ||||||
|         <module>yudao-spring-boot-starter-biz-tenant</module> |         <module>yudao-spring-boot-starter-biz-tenant</module> | ||||||
|  | |||||||
| @ -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 ""; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.spring; | |||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.map.MapUtil; | import cn.hutool.core.map.MapUtil; | ||||||
| import cn.hutool.core.util.ArrayUtil; | import cn.hutool.core.util.ArrayUtil; | ||||||
|  | import org.aspectj.lang.JoinPoint; | ||||||
| import org.aspectj.lang.ProceedingJoinPoint; | import org.aspectj.lang.ProceedingJoinPoint; | ||||||
| import org.aspectj.lang.reflect.MethodSignature; | import org.aspectj.lang.reflect.MethodSignature; | ||||||
| import org.springframework.core.DefaultParameterNameDiscoverer; | import org.springframework.core.DefaultParameterNameDiscoverer; | ||||||
| @ -24,7 +25,15 @@ import java.util.Map; | |||||||
|  */ |  */ | ||||||
| public class SpringExpressionUtils { | public class SpringExpressionUtils { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * spel表达式解析器 | ||||||
|  |      */ | ||||||
|     private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); |     private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); | ||||||
|  |     /** | ||||||
|  |      * 参数名发现器 | ||||||
|  |      */ | ||||||
|     private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer(); |     private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer(); | ||||||
|  |  | ||||||
|     private SpringExpressionUtils() { |     private SpringExpressionUtils() { | ||||||
| @ -33,7 +42,7 @@ public class SpringExpressionUtils { | |||||||
|     /** |     /** | ||||||
|      * 从切面中,单个解析 EL 表达式的结果 |      * 从切面中,单个解析 EL 表达式的结果 | ||||||
|      * |      * | ||||||
|      * @param joinPoint  切面点 |      * @param joinPoint        切面点 | ||||||
|      * @param expressionString EL 表达式数组 |      * @param expressionString EL 表达式数组 | ||||||
|      * @return 执行界面 |      * @return 执行界面 | ||||||
|      */ |      */ | ||||||
| @ -45,7 +54,7 @@ public class SpringExpressionUtils { | |||||||
|     /** |     /** | ||||||
|      * 从切面中,批量解析 EL 表达式的结果 |      * 从切面中,批量解析 EL 表达式的结果 | ||||||
|      * |      * | ||||||
|      * @param joinPoint   切面点 |      * @param joinPoint         切面点 | ||||||
|      * @param expressionStrings EL 表达式数组 |      * @param expressionStrings EL 表达式数组 | ||||||
|      * @return 结果,key 为表达式,value 为对应值 |      * @return 结果,key 为表达式,value 为对应值 | ||||||
|      */ |      */ | ||||||
| @ -79,4 +88,47 @@ public class SpringExpressionUtils { | |||||||
|         }); |         }); | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * JoinPoint 切面 批量解析 EL 表达式,转换 jspl参数 | ||||||
|  |      * | ||||||
|  |      * @param joinPoint 切面点 | ||||||
|  |      * @param rvt       返回值 | ||||||
|  |      * @param expressionStrings      EL 表达式数组 | ||||||
|  |      * @return java.lang.String 结果 | ||||||
|  |      * @author 陈賝 | ||||||
|  |      * @since 2023/6/18 11:20 | ||||||
|  |      */ | ||||||
|  |     public static Map<String, Object> parseExpression(JoinPoint joinPoint, Object rvt, 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("rvt", rvt); | ||||||
|  |         } | ||||||
|  |         // 第二步,逐个参数解析 | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,50 +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> |  | ||||||
|     </dependencies> |  | ||||||
| </project> |  | ||||||
| @ -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(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @ -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; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @ -1 +0,0 @@ | |||||||
| cn.iocoder.yudao.framework.trade.config.YudaoAfterSaleLogAutoConfiguration |  | ||||||
| @ -58,10 +58,6 @@ | |||||||
|             <groupId>cn.iocoder.boot</groupId> |             <groupId>cn.iocoder.boot</groupId> | ||||||
|             <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> |             <artifactId>yudao-spring-boot-starter-biz-ip</artifactId> | ||||||
|         </dependency> |         </dependency> | ||||||
|         <dependency> |  | ||||||
|             <groupId>cn.iocoder.boot</groupId> |  | ||||||
|             <artifactId>yudao-spring-boot-starter-biz-trade</artifactId> |  | ||||||
|         </dependency> |  | ||||||
|  |  | ||||||
|         <!-- Web 相关 --> |         <!-- Web 相关 --> | ||||||
|         <dependency> |         <dependency> | ||||||
|  | |||||||
| @ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.admin.aftersale; | |||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | 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.MemberUserApi; | ||||||
| import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | ||||||
| import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; | import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; | ||||||
| @ -15,6 +14,8 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSal | |||||||
| import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; | 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.convert.aftersale.TradeAfterSaleConvert; | ||||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; | import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.enums.AfterSaleStatusEnum; | ||||||
| import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; | import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; | ||||||
| import io.swagger.v3.oas.annotations.Operation; | import io.swagger.v3.oas.annotations.Operation; | ||||||
| import io.swagger.v3.oas.annotations.Parameter; | import io.swagger.v3.oas.annotations.Parameter; | ||||||
| @ -122,7 +123,7 @@ public class TradeAfterSaleController { | |||||||
|      * @date 2023/6/14 21:39 |      * @date 2023/6/14 21:39 | ||||||
|      */ |      */ | ||||||
|     @PostMapping(value = "/create") |     @PostMapping(value = "/create") | ||||||
|     @AfterSaleLog(id = "#createReqVO.orderItemId", content = "'申请售后:售后编号['+#createReqVO.orderItemId+'] , '", operateType = "#createReqVO.operateType") |     @AfterSaleLog(id = "#createReqVO.orderItemId", content = "'申请售后:售后编号['+#createReqVO.orderItemId+'] , '", operateType = AfterSaleStatusEnum.APPLY) | ||||||
|     public CommonResult<Long> createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) { |     public CommonResult<Long> createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) { | ||||||
|         return success(1L); |         return success(1L); | ||||||
| //        return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); | //        return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); | ||||||
|  | |||||||
| @ -1,7 +1,6 @@ | |||||||
| package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; | package cn.iocoder.yudao.module.trade.controller.app.aftersale.vo; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | 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 cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum; | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| @ -32,14 +31,6 @@ public class AppTradeAfterSaleCreateReqVO { | |||||||
|     @NotNull(message = "申请原因不能为空") |     @NotNull(message = "申请原因不能为空") | ||||||
|     private String applyReason; |     private String applyReason; | ||||||
|  |  | ||||||
|     // TODO @陈賝:这个参数不应该有呀。 |  | ||||||
|     /** |  | ||||||
|      * @see AfterSaleStatusEnum |  | ||||||
|      */ |  | ||||||
|     @Schema(description = "操作类型", required = true, example = "1") |  | ||||||
|     @NotNull(message = "操作类型不能为空") |  | ||||||
|     private String operateType; |  | ||||||
|  |  | ||||||
|     @Schema(description = "补充描述", example = "商品质量不好") |     @Schema(description = "补充描述", example = "商品质量不好") | ||||||
|     private String applyDescription; |     private String applyDescription; | ||||||
|  |  | ||||||
|  | |||||||
| @ -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.boot.autoconfigure.AutoConfiguration; | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * trade 模块的 afterSaleLog 组件的 Configuration | ||||||
|  |  * | ||||||
|  |  * @author 陈賝 | ||||||
|  |  * @since 2023/6/18 11:09 | ||||||
|  |  */ | ||||||
|  | @AutoConfiguration | ||||||
|  | public class AfterSaleLogConfiguration { | ||||||
|  |  | ||||||
|  |     @Bean | ||||||
|  |     public AfterSaleLogAspect afterSaleLogAspect() { | ||||||
|  |         return new AfterSaleLogAspect(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -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.framework.aftersalelog.core.enums.AfterSaleStatusEnum; | ||||||
| 
 | 
 | ||||||
| import java.lang.annotation.*; | import java.lang.annotation.*; | ||||||
| 
 | 
 | ||||||
| @ -18,11 +20,10 @@ public @interface AfterSaleLog { | |||||||
|      */ |      */ | ||||||
|     String id(); |     String id(); | ||||||
| 
 | 
 | ||||||
|     // TODO @陈賝:是不是改成一个操作的枚举? |  | ||||||
|     /** |     /** | ||||||
|      * 操作类型 |      * 操作类型 | ||||||
|      */ |      */ | ||||||
|     String operateType() default ""; |     AfterSaleStatusEnum operateType() default AfterSaleStatusEnum.APPLY; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 日志内容 |      * 日志内容 | ||||||
| @ -0,0 +1,80 @@ | |||||||
|  | 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.dto.TradeAfterSaleLogCreateReqDTO; | ||||||
|  | import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.annotations.AfterSaleLog; | ||||||
|  | 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.ProceedingJoinPoint; | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  |     @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")) | ||||||
|  |                     .setContent(formatObj.get("content")) | ||||||
|  |                     .setOperateType(formatObj.get("operateType")); | ||||||
|  |             // 异步存入数据库 | ||||||
|  |             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(3); | ||||||
|  |         Map<String, Object> spelMap = SpringExpressionUtils.parseExpression(joinPoint, info, | ||||||
|  |                 asList(afterSaleLogPoint.id(), afterSaleLogPoint.operateType().description(), afterSaleLogPoint.content())); | ||||||
|  |         // 售后ID | ||||||
|  |         String id = MapUtil.getStr(spelMap, afterSaleLogPoint.id()); | ||||||
|  |         result.put("id", id); | ||||||
|  |         // 操作类型 | ||||||
|  |         String operateType = MapUtil.getStr(spelMap, afterSaleLogPoint.operateType().description()); | ||||||
|  |         result.put("operateType", operateType); | ||||||
|  |         // 日志内容 | ||||||
|  |         String content = MapUtil.getStr(spelMap, afterSaleLogPoint.content()); | ||||||
|  |         if (ObjectUtil.isNotNull(afterSaleLogPoint.operateType())) { | ||||||
|  |             content += MapUtil.getStr(spelMap, afterSaleLogPoint.operateType().description()); | ||||||
|  |         } | ||||||
|  |         result.put("content", content); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -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.AllArgsConstructor; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| @ -6,6 +6,9 @@ import lombok.NoArgsConstructor; | |||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 售后日志的创建 Request DTO |  * 售后日志的创建 Request DTO | ||||||
|  |  * | ||||||
|  |  * @author 陈賝 | ||||||
|  |  * @since 2023/6/19 09:54 | ||||||
|  */ |  */ | ||||||
| @Data | @Data | ||||||
| @NoArgsConstructor | @NoArgsConstructor | ||||||
| @ -18,7 +21,7 @@ public class TradeAfterSaleLogCreateReqDTO { | |||||||
|     private Long id; |     private Long id; | ||||||
|     /** |     /** | ||||||
|      * 用户编号 |      * 用户编号 | ||||||
|      * |      * <p> | ||||||
|      * 关联 1:AdminUserDO 的 id 字段 |      * 关联 1:AdminUserDO 的 id 字段 | ||||||
|      * 关联 2:MemberUserDO 的 id 字段 |      * 关联 2:MemberUserDO 的 id 字段 | ||||||
|      */ |      */ | ||||||
| @ -1,4 +1,4 @@ | |||||||
| package cn.iocoder.yudao.framework.trade.core.enums; | package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.enums; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * 售后状态的枚举 |  * 售后状态的枚举 | ||||||
| @ -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); | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -5,8 +5,6 @@ import cn.hutool.core.util.RandomUtil; | |||||||
| import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 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.PayRefundApi; | ||||||
| import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; | ||||||
| import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; | 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.aftersale.TradeAfterSaleWayEnum; | ||||||
| import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; | ||||||
| import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; | 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.framework.order.config.TradeOrderProperties; | ||||||
| import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; | import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| @ -40,6 +40,7 @@ import javax.annotation.Resource; | |||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 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.*; | import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -394,7 +395,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa | |||||||
|                 .setAfterSaleId(afterSale.getId()) |                 .setAfterSaleId(afterSale.getId()) | ||||||
|                 .setOperateType(afterStatus.toString()); |                 .setOperateType(afterStatus.toString()); | ||||||
|         // TODO 废弃,待删除 |         // TODO 废弃,待删除 | ||||||
|         this.insert(logDTO); |         this.createLog(logDTO); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -406,7 +407,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa | |||||||
|      */ |      */ | ||||||
|     @Override |     @Override | ||||||
|     @Async |     @Async | ||||||
|     public void insert(TradeAfterSaleLogCreateReqDTO logDTO) { |     public void createLog(TradeAfterSaleLogCreateReqDTO logDTO) { | ||||||
|         try { |         try { | ||||||
|             TradeAfterSaleLogDO afterSaleLog = new TradeAfterSaleLogDO() |             TradeAfterSaleLogDO afterSaleLog = new TradeAfterSaleLogDO() | ||||||
|                     .setUserId(logDTO.getUserId()) |                     .setUserId(logDTO.getUserId()) | ||||||
| @ -416,7 +417,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa | |||||||
|                     .setContent(logDTO.getContent()); |                     .setContent(logDTO.getContent()); | ||||||
|             tradeAfterSaleLogMapper.insert(afterSaleLog); |             tradeAfterSaleLogMapper.insert(afterSaleLog); | ||||||
|         }catch (Exception exception){ |         }catch (Exception exception){ | ||||||
|             log.error("日志记录错误", exception); |             log.error("[request({}) 日志记录错误]", toJsonString(logDTO), exception); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -84,11 +84,11 @@ | |||||||
| <!--            <version>${revision}</version>--> | <!--            <version>${revision}</version>--> | ||||||
| <!--        </dependency>--> | <!--        </dependency>--> | ||||||
|  |  | ||||||
|         <dependency> | <!--        <dependency>--> | ||||||
|             <groupId>cn.iocoder.boot</groupId> | <!--            <groupId>cn.iocoder.boot</groupId>--> | ||||||
|             <artifactId>yudao-module-point-biz</artifactId> | <!--            <artifactId>yudao-module-point-biz</artifactId>--> | ||||||
|             <version>${revision}</version> | <!--            <version>${revision}</version>--> | ||||||
|         </dependency> | <!--        </dependency>--> | ||||||
|  |  | ||||||
|         <!-- spring boot 配置所需依赖 --> |         <!-- spring boot 配置所需依赖 --> | ||||||
|         <dependency> |         <dependency> | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 chenchen
					chenchen