diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index da0c4e735..4c1e671a3 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -26,7 +26,7 @@ 3.5.4.1 3.5.4.1 4.2.0 - 1.4.7.2 + 1.4.8.1 3.25.0 8.1.3.62 diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml index 5792b4cb4..51ea2e04f 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml @@ -46,6 +46,13 @@ com.google.guava guava + + + + io.github.mouzt + bizlog-sdk + + diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogAutoConfiguration.java index 441ec6bbd..0f4f48eeb 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogAutoConfiguration.java @@ -1,23 +1,18 @@ package cn.iocoder.yudao.framework.operatelog.config; -import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect; -import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService; -import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkServiceImpl; -import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.context.annotation.Bean; @AutoConfiguration public class YudaoOperateLogAutoConfiguration { - @Bean - public OperateLogAspect operateLogAspect() { - return new OperateLogAspect(); - } - - @Bean - public OperateLogFrameworkService operateLogFrameworkService(OperateLogApi operateLogApi) { - return new OperateLogFrameworkServiceImpl(operateLogApi); - } + //@Bean + //public OperateLogAspect operateLogAspect() { + // return new OperateLogAspect(); + //} + // + //@Bean + //public OperateLogFrameworkService operateLogFrameworkService(OperateLogApi operateLogApi) { + // return new OperateLogFrameworkServiceImpl(operateLogApi); + //} } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/config/YudaoOperateLogV2Configuration.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/config/YudaoOperateLogV2Configuration.java new file mode 100644 index 000000000..a7aa3a379 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/config/YudaoOperateLogV2Configuration.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.framework.operatelogv2.config; + +import cn.iocoder.yudao.framework.operatelogv2.core.aop.OperateLogV2Aspect; +import cn.iocoder.yudao.framework.operatelogv2.core.service.ILogRecordServiceImpl; +import com.mzt.logapi.service.ILogRecordService; +import com.mzt.logapi.starter.annotation.EnableLogRecord; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +/** + * mzt-biz-log 配置类 + * + * @author HUIHUI + */ +@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦 +@AutoConfiguration +@Slf4j +public class YudaoOperateLogV2Configuration { + + @Bean + @Primary + public ILogRecordService iLogRecordServiceImpl() { + return new ILogRecordServiceImpl(); + } + + @Bean + public OperateLogV2Aspect operateLogV2Aspect() { + return new OperateLogV2Aspect(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/aop/OperateLogV2Aspect.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/aop/OperateLogV2Aspect.java new file mode 100644 index 000000000..a4129c37c --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/aop/OperateLogV2Aspect.java @@ -0,0 +1,329 @@ +package cn.iocoder.yudao.framework.operatelogv2.core.aop; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; +import com.google.common.collect.Maps; +import com.mzt.logapi.beans.LogRecord; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.multipart.MultipartFile; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.IntStream; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS; +import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*; + +/** + * 拦截使用 @Operation 注解, 获取操作类型、开始时间、持续时间、方法相关信息、执行结果等信息 + * 对 mzt-biz-log 日志信息进行增强 + * + * @author HUIHUI + */ +@Aspect +@Slf4j +public class OperateLogV2Aspect { + + /** + * 用于记录操作内容的上下文 + * + * @see OperateLogV2CreateReqDTO#getContent() + */ + private static final ThreadLocal CONTENT = new ThreadLocal<>(); + /** + * 用于记录拓展字段的上下文 + * + * @see OperateLogV2CreateReqDTO#getExtra() + */ + private static final ThreadLocal> EXTRA = new ThreadLocal<>(); + + @Resource + private OperateLogApi operateLogApi; + + @Around("@annotation(operation)") + public Object around(ProceedingJoinPoint joinPoint, Operation operation) throws Throwable { + RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint)); + if (requestMethod == RequestMethod.GET) { // 跳过 get 方法 + return joinPoint.proceed(); + } + + // 目前,只有管理员,才记录操作日志!所以非管理员,直接调用,不进行记录 + Integer userType = WebFrameworkUtils.getLoginUserType(); + if (ObjUtil.notEqual(userType, UserTypeEnum.ADMIN.getValue())) { + return joinPoint.proceed(); + } + + // 记录开始时间 + LocalDateTime startTime = LocalDateTime.now(); + try { + // 执行原有方法 + Object result = joinPoint.proceed(); + // 记录正常执行时的操作日志 + this.log(joinPoint, operation, startTime, result, null); + return result; + } catch (Throwable exception) { + this.log(joinPoint, operation, startTime, null, exception); + throw exception; + } finally { + clearThreadLocal(); + } + } + + public static void setContent(LogRecord content) { + CONTENT.set(content); + } + + public static void addExtra(String key, Object value) { + if (EXTRA.get() == null) { + EXTRA.set(new HashMap<>()); + } + EXTRA.get().put(key, value); + } + + public static void addExtra(Map extra) { + if (EXTRA.get() == null) { + EXTRA.set(new HashMap<>()); + } + EXTRA.get().putAll(extra); + } + + private static void clearThreadLocal() { + CONTENT.remove(); + EXTRA.remove(); + } + + private void log(ProceedingJoinPoint joinPoint, Operation operation, + LocalDateTime startTime, Object result, Throwable exception) { + try { + // 判断不记录的情况(默认没有值就是记录) + if (EXTRA.get() != null && EXTRA.get().get(ENABLE) != null) { + return; + } + if (CONTENT.get() == null) { // 没有值说明没有日志需要记录 + return; + } + + // 真正记录操作日志 + this.log0(joinPoint, operation, startTime, result, exception); + } catch (Throwable ex) { + log.error("[log][记录操作日志时,发生异常,其中参数是 joinPoint({}) apiOperation({}) result({}) exception({}) ]", + joinPoint, operation, result, exception, ex); + } + } + + private void log0(ProceedingJoinPoint joinPoint, Operation operation, + LocalDateTime startTime, Object result, Throwable exception) { + OperateLogV2CreateReqDTO reqDTO = new OperateLogV2CreateReqDTO(); + // 补全通用字段 + reqDTO.setTraceId(TracerUtils.getTraceId()); + reqDTO.setStartTime(startTime); + // 补充用户信息 + fillUserFields(reqDTO); + // 补全模块信息 + fillModuleFields(reqDTO, operation); + // 补全请求信息 + fillRequestFields(reqDTO); + // 补全方法信息 + fillMethodFields(reqDTO, joinPoint, startTime, result, exception); + + // 异步记录日志 + operateLogApi.createOperateLogV2(reqDTO); + } + + private static void fillUserFields(OperateLogV2CreateReqDTO reqDTO) { + reqDTO.setUserId(WebFrameworkUtils.getLoginUserId()); + reqDTO.setUserType(WebFrameworkUtils.getLoginUserType()); + } + + private static void fillModuleFields(OperateLogV2CreateReqDTO reqDTO, Operation operation) { + LogRecord logRecord = CONTENT.get(); + reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号 + reqDTO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + + // type 属性 + reqDTO.setType(logRecord.getType()); // 大模块类型如 crm 客户 + // subType 属性 + if (logRecord.getSubType() != null) { + reqDTO.setSubType(logRecord.getSubType());// 操作名称如 转移客户 + } + if (StrUtil.isEmpty(reqDTO.getSubType()) && operation != null) { + reqDTO.setSubType(operation.summary()); + } + + // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"} + Map objectMap = EXTRA.get(); + if (objectMap != null) { + Object object = objectMap.get(EXTRA_KEY); + if (object instanceof Map extraMap) { + if (extraMap.keySet().stream().allMatch(String.class::isInstance)) { + @SuppressWarnings("unchecked") + Map extra = (Map) extraMap; + reqDTO.setExtra(extra); + return; + } + } + // 激进一点不是 map 直接当 value 处理 + Map extra = Maps.newHashMapWithExpectedSize(1); + extra.put(EXTRA_KEY, object); + reqDTO.setExtra(extra); + } + + } + + private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) { + // 获得 Request 对象 + HttpServletRequest request = ServletUtils.getRequest(); + if (request == null) { + return; + } + // 补全请求信息 + reqDTO.setRequestMethod(request.getMethod()); + reqDTO.setRequestUrl(request.getRequestURI()); + reqDTO.setUserIp(ServletUtils.getClientIP(request)); + reqDTO.setUserAgent(ServletUtils.getUserAgent(request)); + } + + private static void fillMethodFields(OperateLogV2CreateReqDTO reqDTO, ProceedingJoinPoint joinPoint, LocalDateTime startTime, + Object result, Throwable exception) { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + reqDTO.setJavaMethod(methodSignature.toString()); + if (EXTRA.get().get(IS_LOG_ARGS) == null) { + reqDTO.setJavaMethodArgs(obtainMethodArgs(joinPoint)); + } + if (EXTRA.get().get(IS_LOG_RESULT_DATA) == null) { + reqDTO.setResultData(obtainResultData(result)); + } + reqDTO.setDuration((int) (LocalDateTimeUtil.between(startTime, LocalDateTime.now()).toMillis())); + // (正常)处理 resultCode 和 resultMsg 字段 + if (result instanceof CommonResult) { + CommonResult commonResult = (CommonResult) result; + reqDTO.setResultCode(commonResult.getCode()); + reqDTO.setResultMsg(commonResult.getMsg()); + } else { + reqDTO.setResultCode(SUCCESS.getCode()); + } + // (异常)处理 resultCode 和 resultMsg 字段 + if (exception != null) { + reqDTO.setResultCode(INTERNAL_SERVER_ERROR.getCode()); + reqDTO.setResultMsg(ExceptionUtil.getRootCauseMessage(exception)); + } + } + + @SuppressWarnings("SameParameterValue") + private static T getClassAnnotation(ProceedingJoinPoint joinPoint, Class annotationClass) { + return ((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaringClass().getAnnotation(annotationClass); + } + + private static String obtainMethodArgs(ProceedingJoinPoint joinPoint) { + // TODO 提升:参数脱敏和忽略 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + String[] argNames = methodSignature.getParameterNames(); + Object[] argValues = joinPoint.getArgs(); + // 拼接参数 + Map args = Maps.newHashMapWithExpectedSize(argValues.length); + for (int i = 0; i < argNames.length; i++) { + String argName = argNames[i]; + Object argValue = argValues[i]; + // 被忽略时,标记为 ignore 字符串,避免和 null 混在一起 + args.put(argName, !isIgnoreArgs(argValue) ? argValue : "[ignore]"); + } + return JsonUtils.toJsonString(args); + } + + private static String obtainResultData(Object result) { + // TODO 提升:结果脱敏和忽略 + if (result instanceof CommonResult) { + result = ((CommonResult) result).getData(); + } + return JsonUtils.toJsonString(result); + } + + private static boolean isIgnoreArgs(Object object) { + Class clazz = object.getClass(); + // 处理数组的情况 + if (clazz.isArray()) { + return IntStream.range(0, Array.getLength(object)) + .anyMatch(index -> isIgnoreArgs(Array.get(object, index))); + } + // 递归,处理数组、Collection、Map 的情况 + if (Collection.class.isAssignableFrom(clazz)) { + return ((Collection) object).stream() + .anyMatch((Predicate) OperateLogV2Aspect::isIgnoreArgs); + } + if (Map.class.isAssignableFrom(clazz)) { + return isIgnoreArgs(((Map) object).values()); + } + // obj + return object instanceof MultipartFile + || object instanceof HttpServletRequest + || object instanceof HttpServletResponse + || object instanceof BindingResult; + } + + private static RequestMethod obtainFirstMatchRequestMethod(RequestMethod[] requestMethods) { + if (ArrayUtil.isEmpty(requestMethods)) { + return null; + } + // 优先,匹配最优的 POST、PUT、DELETE + RequestMethod result = obtainFirstLogRequestMethod(requestMethods); + if (result != null) { + return result; + } + // 然后,匹配次优的 GET + result = Arrays.stream(requestMethods).filter(requestMethod -> requestMethod == RequestMethod.GET) + .findFirst().orElse(null); + if (result != null) { + return result; + } + // 兜底,获得第一个 + return requestMethods[0]; + } + + private static RequestMethod[] obtainRequestMethod(ProceedingJoinPoint joinPoint) { + RequestMapping requestMapping = AnnotationUtils.getAnnotation( // 使用 Spring 的工具类,可以处理 @RequestMapping 别名注解 + ((MethodSignature) joinPoint.getSignature()).getMethod(), RequestMapping.class); + return requestMapping != null ? requestMapping.method() : new RequestMethod[]{}; + } + + private static RequestMethod obtainFirstLogRequestMethod(RequestMethod[] requestMethods) { + if (ArrayUtil.isEmpty(requestMethods)) { + return null; + } + return Arrays.stream(requestMethods).filter(requestMethod -> + requestMethod == RequestMethod.POST + || requestMethod == RequestMethod.PUT + || requestMethod == RequestMethod.DELETE) + .findFirst().orElse(null); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/enums/OperateLogV2Constants.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/enums/OperateLogV2Constants.java new file mode 100644 index 000000000..b0cfe43b3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/enums/OperateLogV2Constants.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.framework.operatelogv2.core.enums; + +/** + * 操作日志常量接口 + * + * @author HUIHUI + */ +public interface OperateLogV2Constants { + + // ========== 开关字段-如果没有值默认就是记录 ========== + + /** + * 是否记录日志 + */ + String ENABLE = "enable"; + + /** + * 是否记录方法参数 + */ + String IS_LOG_ARGS = "isLogArgs"; + + /** + * 是否记录方法结果的数据 + */ + String IS_LOG_RESULT_DATA = "isLogResultData"; + + // ========== 扩展 ========== + + /** + * 扩展信息 + */ + String EXTRA_KEY = "extra"; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/package-info.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/package-info.java new file mode 100644 index 000000000..2cc0c2835 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.framework.operatelogv2.core; \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/service/ILogRecordServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/service/ILogRecordServiceImpl.java new file mode 100644 index 000000000..b54e0b4f1 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/service/ILogRecordServiceImpl.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.framework.operatelogv2.core.service; + +import cn.iocoder.yudao.framework.operatelogv2.core.aop.OperateLogV2Aspect; +import com.mzt.logapi.beans.LogRecord; +import com.mzt.logapi.context.LogRecordContext; +import com.mzt.logapi.service.ILogRecordService; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collections; +import java.util.List; + +/** + * 操作日志 ILogRecordService 实现类 + * + * 基于 {@link OperateLogV2Aspect} 实现,记录操作日志 + * + * @author HUIHUI + */ +@Slf4j +public class ILogRecordServiceImpl implements ILogRecordService { + + @Override + public void record(LogRecord logRecord) { + OperateLogV2Aspect.setContent(logRecord); // 操作日志 + OperateLogV2Aspect.addExtra(LogRecordContext.getVariables()); // 扩展信息 + } + + @Override + public List queryLog(String bizNo, String type) { + return Collections.emptyList(); + } + + @Override + public List queryLogByBizNo(String bizNo, String type, String subType) { + return Collections.emptyList(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/vo/OperateLogV2PageReqVO.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/vo/OperateLogV2PageReqVO.java new file mode 100644 index 000000000..8d7a535ad --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/core/vo/OperateLogV2PageReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.framework.operatelogv2.core.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 操作日志分页 Request VO") +@Data +public class OperateLogV2PageReqVO extends PageParam { + + @Schema(description = "模块数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long bizId; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long userId; + + @Schema(description = "模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String bizType; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/package-info.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/package-info.java new file mode 100644 index 000000000..439ddc3de --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelogv2/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.framework.operatelogv2; \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 04ccab1cd..3fb6d2cc9 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1,2 @@ -cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogAutoConfiguration \ No newline at end of file +cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogAutoConfiguration +cn.iocoder.yudao.framework.operatelogv2.config.YudaoOperateLogV2Configuration \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java index ae8c795ab..9435ec27d 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java @@ -22,6 +22,5 @@ public interface LogRecordConstants { //======================= 客户转移操作日志 ======================= String TRANSFER_CUSTOMER_LOG_SUCCESS = "把客户【{{#crmCustomer.name}}】的负责人从【{getAdminUserById{#crmCustomer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; - String TRANSFER_CUSTOMER_LOG_FAIL = ""; // TODO @puhui999:这个可以删除哈,一般不搞失败的日志 } diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionRoleCodeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionRoleCodeEnum.java new file mode 100644 index 000000000..c9a51057b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionRoleCodeEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.enums.permission; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Crm 数据权限角色枚举 + * + * @author HUIHUI + */ +@Getter +@AllArgsConstructor +public enum CrmPermissionRoleCodeEnum { + + CRM_ADMIN("crm_admin", "CRM 管理员"); + + /** + * 角色标识 + */ + private String code; + /** + * 角色名称 + */ + private String name; + +} + diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http index 6a5c6774c..9a6cb93a8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.http @@ -1,8 +1,8 @@ ### 请求 /transfer PUT {{baseUrl}}/crm/customer/transfer -Content-Type: application/json +Content-Type: application/-id: {{adminTenentId}}json Authorization: Bearer {{token}} -tenant-id: {{adminTenentId}} +tenant { "id": 10, diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index 0882ea72c..2580f9584 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -3,8 +3,10 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer; 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.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.framework.operatelogv2.core.vo.OperateLogV2PageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*; import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; @@ -12,6 +14,7 @@ import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -64,7 +67,7 @@ public class CrmCustomerController { } @PutMapping("/update") - //@Operation(summary = "更新客户") + @Operation(summary = "更新客户") @PreAuthorize("@ss.hasPermission('crm:customer:update')") public CommonResult updateCustomer(@Valid @RequestBody CrmCustomerUpdateReqVO updateReqVO) { customerService.updateCustomer(updateReqVO); @@ -128,30 +131,21 @@ public class CrmCustomerController { } @PutMapping("/transfer") - //@Operation(summary = "客户转移") + @Operation(summary = "客户转移") @PreAuthorize("@ss.hasPermission('crm:customer:update')") public CommonResult transfer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) { customerService.transferCustomer(reqVO, getLoginUserId()); return success(true); } - // TODO @puhui999:operate-log-list 或者 operate-log-page 如果分页 - @GetMapping("/operate-log") + @GetMapping("/operate-log-page") @Operation(summary = "获得客户操作日志") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('crm:customer:query')") - // TODO @puhui999:最好有读权限;方法名改成 getCustomerOperateLog - public CommonResult> getOperateLog(@RequestParam("id") Long id) { - // 1. 获取客户 - // TODO @puhui999:这个校验可以去掉哈; - CrmCustomerDO customer = customerService.getCustomer(id); - if (customer == null) { - return success(null); - } - - // 2. 获取操作日志 - // TODO @puhui999:操作日志,返回可能要分页哈; - return success(operateLogApi.getOperateLogByModuleAndBizId(CRM_CUSTOMER, id)); + public CommonResult> getCustomerOperateLog(OperateLogV2PageReqVO reqVO) { + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 + reqVO.setBizType(CRM_CUSTOMER); + return success(operateLogApi.getOperateLogPage(BeanUtils.toBean(reqVO, OperateLogV2PageReqDTO.class))); } // TODO @Joey:单独建一个属于自己业务的 ReqVO;因为前端如果模拟请求,是不是可以更新其它字段了; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java index 32d4a1ab7..5dc3807f5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java @@ -8,8 +8,8 @@ import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionR import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO; import cn.iocoder.yudao.module.crm.convert.permission.CrmPermissionConvert; import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.PostApi; @@ -21,12 +21,12 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java index 6dfdf8fad..eb9d50a64 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -38,11 +38,8 @@ public interface CrmBusinessMapper extends BaseMapperX { default PageResult selectPage(CrmBusinessPageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), CrmBusinessDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 query.selectAll(CrmBusinessDO.class) .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java index cd558dce4..2253e69f6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java @@ -30,11 +30,8 @@ public interface CrmClueMapper extends BaseMapperX { default PageResult selectPage(CrmCluePageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_LEADS.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_LEADS.getType(), CrmClueDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool()); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 query.selectAll(CrmClueDO.class) .likeIfPresent(CrmClueDO::getName, pageReqVO.getName()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java index adc4ced87..1d387149c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java @@ -43,11 +43,8 @@ public interface CrmContactMapper extends BaseMapperX { default PageResult selectPage(CrmContactPageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTACT.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTACT.getType(), CrmContactDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 query.selectAll(CrmContactDO.class) .likeIfPresent(CrmContactDO::getName, pageReqVO.getName()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java index 60a5ab785..dfb3e6236 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java @@ -41,11 +41,8 @@ public interface CrmContractMapper extends BaseMapperX { default PageResult selectPage(CrmContractPageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX mpjLambdaWrapperX = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CONTACT.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CONTACT.getType(), CrmContractDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 mpjLambdaWrapperX.selectAll(CrmContractDO.class) .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java index b399ca7df..77304575c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java @@ -30,11 +30,8 @@ public interface CrmCustomerMapper extends BaseMapperX { default PageResult selectPage(CrmCustomerPageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), CrmCustomerDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool()); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 query.selectAll(CrmCustomerDO.class) .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java index fca4e30e2..a20da86a6 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java @@ -39,11 +39,8 @@ public interface CrmReceivableMapper extends BaseMapperX { default PageResult selectPage(CrmReceivablePageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), CrmReceivableDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 query.selectAll(CrmReceivableDO.class) .eqIfPresent(CrmReceivableDO::getNo, pageReqVO.getNo()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java index e22c920b9..ed578f1fd 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java @@ -38,11 +38,8 @@ public interface CrmReceivablePlanMapper extends BaseMapperX selectPage(CrmReceivablePlanPageReqVO pageReqVO, Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - boolean condition = CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), + CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), CrmReceivablePlanDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); - if (!condition) { - return PageResult.empty(); - } // 拼接自身的查询条件 query.selectAll(CrmReceivablePlanDO.class) .eqIfPresent(CrmReceivablePlanDO::getCustomerId, pageReqVO.getCustomerId()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/package-info.java deleted file mode 100644 index b756f540d..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.bizlog; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/package-info.java deleted file mode 100644 index 4a3e65722..000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.crm.framework.core; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java new file mode 100644 index 000000000..975a2eb51 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.crm.framework.operatelog; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmIndustryParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmIndustryParseFunction.java similarity index 89% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmIndustryParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmIndustryParseFunction.java index f963b533a..45c98918b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmIndustryParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmIndustryParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.bizlog.function; +package cn.iocoder.yudao.module.crm.framework.operatelog.parse; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; @@ -8,7 +8,6 @@ import org.springframework.stereotype.Component; import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; -// TODO @puhui999:包名使用 operatelog 更合适哈; /** * 自定义函数-通过行业编号获取行业信息 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmLevelParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmLevelParseFunction.java similarity index 94% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmLevelParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmLevelParseFunction.java index 15af42d5e..bb0e23205 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmLevelParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmLevelParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.bizlog.function; +package cn.iocoder.yudao.module.crm.framework.operatelog.parse; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmSourceParseFunction.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmSourceParseFunction.java similarity index 94% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmSourceParseFunction.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmSourceParseFunction.java index 0a630dfe6..eeb5a5674 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/bizlog/function/CrmSourceParseFunction.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/parse/CrmSourceParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.bizlog.function; +package cn.iocoder.yudao.module.crm.framework.operatelog.parse; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/annotations/CrmPermission.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/annotations/CrmPermission.java similarity index 93% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/annotations/CrmPermission.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/annotations/CrmPermission.java index f92371f2b..9ef6d4d02 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/annotations/CrmPermission.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/annotations/CrmPermission.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.core.annotations; +package cn.iocoder.yudao.module.crm.framework.permission.core.annotations; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/aop/CrmPermissionAspect.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java similarity index 77% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/aop/CrmPermissionAspect.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java index 3e1cf87b2..40bae7b98 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/aop/CrmPermissionAspect.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.crm.framework.core.aop; +package cn.iocoder.yudao.module.crm.framework.permission.core.aop; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; @@ -6,27 +6,27 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; -import jakarta.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED; -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_MODEL_NOT_EXISTS; -// TODO 这个包,改成 permission,然后搞 config 和 core 包,这个类在 core 包里;目的是:framework 最好分类下 /** * Crm 数据权限校验 AOP 切面 * @@ -42,10 +42,6 @@ public class CrmPermissionAspect { @Before("@annotation(crmPermission)") public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) { - // TODO 芋艿:临时,方便大家调试 - //if (true) { - // return; - //} // 获取相关属性值 Map expressionValues = parseExpressions(joinPoint, crmPermission); Integer bizType = StrUtil.isEmpty(crmPermission.bizTypeValue()) ? @@ -53,16 +49,28 @@ public class CrmPermissionAspect { Long bizId = (Long) expressionValues.get(crmPermission.bizId()); // 模块数据编号 Integer permissionLevel = crmPermission.level().getLevel(); // 需要的权限级别 - // TODO 如果是超级管理员则直接通过 - //if (superAdmin){ - // return; - //} - - // 1. 获取数据权限 - List bizPermissions = crmPermissionService.getPermissionListByBiz(bizType, bizId); - if (CollUtil.isEmpty(bizPermissions)) { // 数据权限不存存那么数据也不存在 - throw exception(CRM_PERMISSION_MODEL_NOT_EXISTS, CrmBizTypeEnum.getNameByType(bizType)); + // 1.1 如果是超级管理员则直接通过 + if (CrmPermissionUtils.validateAdminUser()) { + return; } + // 1.2 获取数据权限 + List bizPermissions = crmPermissionService.getPermissionListByBiz(bizType, bizId); + if (CollUtil.isEmpty(bizPermissions)) { // 没有数据权限的情况 + // 公海数据如果没有团队成员大家也因该有读权限才对 + if (CrmPermissionLevelEnum.isRead(permissionLevel)) { + return; + } + + // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针 + throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); + } else { // 有数据权限但是没有负责人的情况 + if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) { + if (CrmPermissionLevelEnum.isRead(permissionLevel)) { + return; + } + } + } + // 2.1 情况一:如果自己是负责人,则默认有所有权限 CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), getUserId())); if (userPermission != null) { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/package-info.java new file mode 100644 index 000000000..d895fe969 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.crm.framework.permission.core; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/util/CrmPermissionUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/util/CrmPermissionUtils.java new file mode 100644 index 000000000..80a1654a8 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/util/CrmPermissionUtils.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.crm.framework.permission.core.util; + +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionRoleCodeEnum; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; + +/** + * 数据权限工具类 + * + * @author HUIHUI + */ +public class CrmPermissionUtils { + + /** + * 校验用户是否是 CRM 管理员 + * + * @return 是/否 + */ + public static boolean validateAdminUser() { + return SingletonManager.getPermissionApi().hasAnyRoles(getUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode()); + } + + /** + * 获得用户编号 + * + * @return 用户编号 + */ + private static Long getUserId() { + return WebFrameworkUtils.getLoginUserId(); + } + + /** + * 静态内部类实现单例获取 + * + * @author HUIHUI + */ + private static class SingletonManager { + + private static final PermissionApi PERMISSION_API = SpringUtil.getBean(PermissionApi.class); + + public static PermissionApi getPermissionApi() { + return PERMISSION_API; + } + + } + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java new file mode 100644 index 000000000..44f408016 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.crm.framework.permission; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java index f2db01b83..5281084b9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java index 414a52d17..c3af9e414 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import cn.iocoder.yudao.module.crm.dal.mysql.clue.CrmClueMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import jakarta.annotation.Resource; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java index 50b1bd4be..5edf22a2e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java @@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; import cn.iocoder.yudao.module.crm.dal.mysql.contact.CrmContactMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java index 0a9512ffb..94de4d7be 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java @@ -14,7 +14,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContact import cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink.CrmContactBusinessLinkMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index 6f2fc16ab..00d6c5e4c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import jakarta.annotation.Resource; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java index e53dc1a46..5d8dd36b2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.service.customer; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO; @@ -12,7 +13,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -52,6 +53,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#customerId}}", success = "创建了客户") public Long createCustomer(CrmCustomerCreateReqVO createReqVO, Long userId) { // 插入 CrmCustomerDO customer = CrmCustomerConvert.INSTANCE.convert(createReqVO); @@ -60,26 +62,34 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { // 创建数据权限 crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 + + // 添加日志上下文所需 + LogRecordContext.putVariable("customerId", customer.getId()); return customer.getId(); } @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(success = "更新了客户{_DIFF{#updateReqVO}}", type = CRM_CUSTOMER, subType = "更新客户", bizNo = "{{#updateReqVO.id}}") + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}") @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) { // 校验存在 CrmCustomerDO oldCustomerDO = validateCustomerExists(updateReqVO.getId()); - // __DIFF 函数传递了一个参数,传递的参数是修改之后的对象,这种方式需要在方法内部向 LogRecordContext 中 put 一个变量,代表是之前的对象,这个对象可以是null - LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class)); // 更新 CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO); customerMapper.updateById(updateObj); + + // __DIFF 函数传递了一个参数,传递的参数是修改之后的对象,这种方式需要在方法内部向 LogRecordContext 中 put 一个变量,代表是之前的对象,这个对象可以是null + LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomerDO, CrmCustomerUpdateReqVO.class)); + HashMap extra = new HashMap<>(); + extra.put("tips", "随便记录一点啦"); + LogRecordContext.putVariable(OperateLogV2Constants.EXTRA_KEY, extra); } @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#id}}", success = "删除了客户") @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void deleteCustomer(Long id) { // 校验存在 @@ -125,27 +135,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { */ @Override public void validateCustomer(Long customerId) { - // 校验客户是否存在 - if (customerId == null) { - throw exception(CUSTOMER_NOT_EXISTS); - } - CrmCustomerDO customer = customerMapper.selectById(customerId); - if (Objects.isNull(customer)) { - throw exception(CUSTOMER_NOT_EXISTS); - } + validateCustomerExists(customerId); } @Override @Transactional(rollbackFor = Exception.class) - // TODO @puhui999:@LogRecord(type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS) - @LogRecord(success = TRANSFER_CUSTOMER_LOG_SUCCESS, type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}") + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS) @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { // 1. 校验客户是否存在 - validateCustomer(reqVO.getId()); - // 添加 crmCustomer 到日志上下文 TODO 日志记录放在 service 里是因为已经过了权限校验查询时不用走两次校验 - // TODO @puhui999:customer 不用查询,从 1. 拿到哈;然后 put这个动作,可以放到 3.;这样逻辑结构就是,校验、逻辑、日志,更加清晰 - LogRecordContext.putVariable("crmCustomer", customerMapper.selectById(reqVO.getId())); + CrmCustomerDO customerDO = validateCustomerExists(reqVO.getId()); + // 2.1 数据权限转移 crmPermissionService.transferPermission( CrmCustomerConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())); @@ -153,9 +153,11 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); // 3. TODO 记录转移日志 + LogRecordContext.putVariable("crmCustomer", customerDO); } @Override + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "锁定了客户") public void lockCustomer(CrmCustomerUpdateReqVO updateReqVO) { // 校验存在 validateCustomerExists(updateReqVO.getId()); @@ -169,6 +171,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @Override @Transactional(rollbackFor = Exception.class) + @LogRecord(type = CRM_CUSTOMER, bizNo = "{{#id}}", success = "将客户放入了公海") @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) public void putCustomerPool(Long id) { // 1. 校验存在 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java index 14fb966c5..e3cc4a24b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; import cn.iocoder.yudao.module.crm.dal.mysql.permission.CrmPermissionMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -89,8 +90,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { CrmPermissionDO oldPermission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId( transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId()); String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType()); - // TODO 校验是否为超级管理员 || 1 - if (oldPermission == null || !isOwner(oldPermission.getLevel())) { + if (oldPermission == null || !isOwner(oldPermission.getLevel()) || !CrmPermissionUtils.validateAdminUser()) { throw exception(CRM_PERMISSION_DENIED, bizTypeName); } // 1.1 校验转移对象是否已经是该负责人 @@ -138,7 +138,6 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { } @Override - @Transactional(rollbackFor = Exception.class) // TODO @puhui999:这里不用加的,就一个操作哈; public void deletePermission(Integer bizType, Long bizId) { int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId); if (deletedCount == 0) { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java index edfb6c70a..e6940e793 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivablePlanMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 38bf5266e..6071c2615 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -18,7 +18,7 @@ import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper; import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; -import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission; +import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmQueryWrapperUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmQueryWrapperUtils.java index 161bff845..0e1ba5471 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmQueryWrapperUtils.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmQueryWrapperUtils.java @@ -7,9 +7,11 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; +import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.github.yulichang.autoconfigure.MybatisPlusJoinProperties; import com.github.yulichang.wrapper.MPJLambdaWrapper; import java.util.Collection; @@ -33,46 +35,41 @@ public class CrmQueryWrapperUtils { * @param userId 用户编号 * @param sceneType 场景类型 * @param pool 公海 - * @return 是否 (是:需要执行查询,否:不需要查询调用方法直接返回空) */ - // TODO @puhui999:bizId 直接传递会不会简单点 回复:还是需要 SFunction 因为分页连表时不知道 bizId 是多少;是不是把 bizId 传入就好啦? - public static , S> boolean appendPermissionCondition(T query, Integer bizType, SFunction bizId, - Long userId, Integer sceneType, Boolean pool) { + public static , S> void appendPermissionCondition(T query, Integer bizType, SFunction bizId, + Long userId, Integer sceneType, Boolean pool) { + final String ownerUserIdField = SingletonManager.getMybatisPlusJoinProperties().getTableAlias() + ".owner_user_id"; // 1. 构建数据权限连表条件 - if (ObjUtil.notEqual(validateAdminUser(userId), Boolean.TRUE)) { // 管理员不需要数据权限 + if (ObjUtil.notEqual(CrmPermissionUtils.validateAdminUser(), Boolean.TRUE) && ObjUtil.notEqual(pool, Boolean.TRUE)) { // 管理员,公海不需要数据权限 query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) - .eq(CrmPermissionDO::getBizId, bizId) + .eq(CrmPermissionDO::getBizId, bizId) // 只能使用 SFunction 如果传 id 解析出来的 sql 不对 .eq(CrmPermissionDO::getUserId, userId)); } // 2.1 场景一:我负责的数据 if (CrmSceneTypeEnum.isOwner(sceneType)) { - query.eq("owner_user_id", userId); + query.eq(ownerUserIdField, userId); } // 2.2 场景二:我参与的数据 if (CrmSceneTypeEnum.isInvolved(sceneType)) { - query.ne("owner_user_id", userId) - // TODO @puhui999:IN 是不是更合适哈; - .and(q -> q.eq(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel()) - .or() - .eq(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.WRITE.getLevel())); + query.ne(ownerUserIdField, userId) + .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel()); } // 2.3 场景三:下属负责的数据 if (CrmSceneTypeEnum.isSubordinate(sceneType)) { - // TODO @puhui999:要不如果没有下属,拼一个 owner_user_id in null,不返回结果就好啦; - List subordinateUsers = getAdminUserApi().getUserListBySubordinate(userId); + List subordinateUsers = SingletonManager.getAdminUserApi().getUserListBySubordinate(userId); if (CollUtil.isEmpty(subordinateUsers)) { - return false; + query.eq(ownerUserIdField, -1); // 不返回任何结果 + } else { + query.in(ownerUserIdField, convertSet(subordinateUsers, AdminUserRespDTO::getId)); } - query.in("owner_user_id", convertSet(subordinateUsers, AdminUserRespDTO::getId)); } // 3. 拼接公海的查询条件 if (ObjUtil.equal(pool, Boolean.TRUE)) { // 情况一:公海 - query.isNull("owner_user_id"); + query.isNull(ownerUserIdField); } else { // 情况二:不是公海 - query.isNotNull("owner_user_id"); + query.isNotNull(ownerUserIdField); } - return true; } /** @@ -84,7 +81,7 @@ public class CrmQueryWrapperUtils { * @param userId 用户编号 */ public static > void appendPermissionCondition(T query, Integer bizType, Collection bizIds, Long userId) { - if (ObjUtil.equal(validateAdminUser(userId), Boolean.TRUE)) {// 管理员不需要数据权限 + if (ObjUtil.equal(CrmPermissionUtils.validateAdminUser(), Boolean.TRUE)) {// 管理员不需要数据权限 return; } @@ -93,38 +90,23 @@ public class CrmQueryWrapperUtils { .in(CollUtil.isNotEmpty(bizIds), CrmPermissionDO::getUserId, userId)); } - private static AdminUserApi getAdminUserApi() { - return AdminUserApiHolder.ADMIN_USER_API; - } - /** - * 校验用户是否是管理员 - * - * @param userId 用户编号 - * @return 是/否 - */ - private static boolean validateAdminUser(Long userId) { - // TODO 查询权限配置表用户的角色信息 - // TODO @puhui999:查询用户的角色;CRM_ADMIN("crm_admin", "CRM 管理员"), - //CrmPermissionConfig permissionConfig = crmPermissionConfigService.getPermissionConfigByUserId(userId); - //if (permissionConfig == null) { - // return false; - //} - //// 校验是否为管理员 - //if (permissionConfig.getIsAdmin()){ - // return true; - //} - return false; - } - - /** - * 静态内部类实现 AdminUserApi 单例获取 + * 静态内部类实现单例获取 * * @author HUIHUI */ - private static class AdminUserApiHolder { + private static class SingletonManager { private static final AdminUserApi ADMIN_USER_API = SpringUtil.getBean(AdminUserApi.class); + private static final MybatisPlusJoinProperties MYBATIS_PLUS_JOIN_PROPERTIES = SpringUtil.getBean(MybatisPlusJoinProperties.class); + + public static AdminUserApi getAdminUserApi() { + return ADMIN_USER_API; + } + + public static MybatisPlusJoinProperties getMybatisPlusJoinProperties() { + return MYBATIS_PLUS_JOIN_PROPERTIES; + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java index 16233bef3..6c5cec14a 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java @@ -7,26 +7,33 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import jakarta.annotation.Resource; import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; @Tag(name = "用户 APP - 营销活动") // 用于提供跨多个活动的 HTTP 接口 @RestController @@ -40,6 +47,10 @@ public class AppActivityController { private SeckillActivityService seckillActivityService; @Resource private BargainActivityService bargainActivityService; + @Resource + private DiscountActivityService discountActivityService; + @Resource + private RewardActivityService rewardActivityService; @GetMapping("/list-by-spu-id") @Operation(summary = "获得单个商品,近期参与的每个活动") @@ -64,45 +75,105 @@ public class AppActivityController { if (CollUtil.isEmpty(spuIds)) { return new ArrayList<>(); } + LocalDateTime now = LocalDateTime.now(); + // 获取开启的且开始的且没有结束的活动 List activityList = new ArrayList<>(); - - // 1. 拼团活动 - 获取开启的且开始的且没有结束的活动 - List combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt( - spuIds, CommonStatusEnum.ENABLE.getStatus(), now); - if (CollUtil.isNotEmpty(combinationActivities)) { - combinationActivities.forEach(item -> { - activityList.add(new AppActivityRespVO().setId(item.getId()) - .setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType()).setName(item.getName()) - .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); - }); - } - - // 2. 秒杀活动 - 获取开启的且开始的且没有结束的活动 - List seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt( - spuIds, CommonStatusEnum.ENABLE.getStatus(), now); - if (CollUtil.isNotEmpty(seckillActivities)) { - seckillActivities.forEach(item -> { - activityList.add(new AppActivityRespVO().setId(item.getId()) - .setType(PromotionTypeEnum.SECKILL_ACTIVITY.getType()).setName(item.getName()) - .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); - }); - } - - // 3. 砍价活动 - 获取开启的且开始的且没有结束的活动 - List bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt( - spuIds, CommonStatusEnum.ENABLE.getStatus(), now); - if (CollUtil.isNotEmpty(bargainActivities)) { - bargainActivities.forEach(item -> { - activityList.add(new AppActivityRespVO().setId(item.getId()) - .setType(PromotionTypeEnum.BARGAIN_ACTIVITY.getType()).setName(item.getName()) - .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); - }); - } - - // TODO 芋艿:满减送活动 - // TODO 芋艿:限时折扣活动 + // 1. 拼团活动 + getCombinationActivities(spuIds, now, activityList); + // 2. 秒杀活动 + getSeckillActivities(spuIds, now, activityList); + // 3. 砍价活动 + getBargainActivities(spuIds, now, activityList); + // 4. 限时折扣活动 + getDiscountActivities(spuIds, now, activityList); + // 5. 满减送活动 + getRewardActivities(spuIds, now, activityList); return activityList; } + private void getCombinationActivities(Collection spuIds, LocalDateTime now, List activityList) { + List combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isEmpty(combinationActivities)) { + return; + } + + combinationActivities.forEach(item -> { + activityList.add(new AppActivityRespVO().setId(item.getId()) + .setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType()).setName(item.getName()) + .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); + }); + } + + private void getSeckillActivities(Collection spuIds, LocalDateTime now, List activityList) { + List seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isEmpty(seckillActivities)) { + return; + } + + seckillActivities.forEach(item -> { + activityList.add(new AppActivityRespVO().setId(item.getId()) + .setType(PromotionTypeEnum.SECKILL_ACTIVITY.getType()).setName(item.getName()) + .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); + }); + } + + private void getBargainActivities(Collection spuIds, LocalDateTime now, List activityList) { + List bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isNotEmpty(bargainActivities)) { + return; + } + + bargainActivities.forEach(item -> { + activityList.add(new AppActivityRespVO().setId(item.getId()) + .setType(PromotionTypeEnum.BARGAIN_ACTIVITY.getType()).setName(item.getName()) + .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); + }); + } + + private void getDiscountActivities(Collection spuIds, LocalDateTime now, List activityList) { + List discountActivities = discountActivityService.getDiscountActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, CommonStatusEnum.ENABLE.getStatus(), now); + if (CollUtil.isEmpty(discountActivities)) { + return; + } + + List products = discountActivityService.getDiscountProductsByActivityId( + convertSet(discountActivities, DiscountActivityDO::getId)); + Map productMap = convertMap(products, DiscountProductDO::getActivityId, DiscountProductDO::getSpuId); + discountActivities.forEach(item -> { + activityList.add(new AppActivityRespVO().setId(item.getId()) + .setType(PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()).setName(item.getName()) + .setSpuId(productMap.get(item.getId())).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())); + }); + } + + private void getRewardActivities(Collection spuIds, LocalDateTime now, List activityList) { + List rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt( + spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now); + if (CollUtil.isEmpty(rewardActivityList)) { + return; + } + + Map> spuIdAndActivityMap = spuIds.stream() + .collect(Collectors.toMap( + spuId -> spuId, + spuId -> rewardActivityList.stream() + .filter(activity -> activity.getProductSpuIds().contains(spuId)) + .max(Comparator.comparing(RewardActivityDO::getCreateTime)))); + for (Long supId : spuIdAndActivityMap.keySet()) { + if (spuIdAndActivityMap.get(supId).isEmpty()) { + continue; + } + + RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get(); + activityList.add(new AppActivityRespVO().setId(rewardActivityDO.getId()) + .setType(PromotionTypeEnum.REWARD_ACTIVITY.getType()).setName(rewardActivityDO.getName()) + .setSpuId(supId).setStartTime(rewardActivityDO.getStartTime()).setEndTime(rewardActivityDO.getEndTime())); + } + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java index 534ce627a..efd4e4d25 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java @@ -7,9 +7,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; -import java.util.Set; /** * 限时折扣活动 Mapper @@ -27,4 +27,20 @@ public interface DiscountActivityMapper extends BaseMapperX .orderByDesc(DiscountActivityDO::getId)); } + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(DiscountActivityDO::getId, ids) + .lt(DiscountActivityDO::getStartTime, dateTime) + .gt(DiscountActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(DiscountActivityDO::getCreateTime)); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java index 10df2ce3a..5257b836d 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java @@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.Collection; import java.util.List; +import java.util.Map; /** * 限时折扣商城 Mapper @@ -30,4 +32,20 @@ public interface DiscountProductMapper extends BaseMapperX { // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的 List getMatchDiscountProductList(@Param("skuIds") Collection skuIds); + + /** + * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + * + * @param spuIds spu 编号 + * @param status 状态 + * @return 包含 spuId 和 activityId 的 map 对象列表 + */ + default List> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection spuIds, Integer status) { + return selectMaps(new QueryWrapper() + .select("spu_id AS spuId, MAX(DISTINCT(activity_id)) AS activityId") + .in("spu_id", spuIds) + .eq("activity_status", status) + .groupBy("spu_id")); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java index 2ee879823..ca9e9668f 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java @@ -1,14 +1,19 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.reward; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.ibatis.annotations.Mapper; +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; /** * 满减送活动 Mapper @@ -35,4 +40,30 @@ public interface RewardActivityMapper extends BaseMapperX { .eq(RewardActivityDO::getStatus, status)); } + default List selectListBySpuIdsAndStatus(Collection spuIds, Integer status) { + Function, String> productScopeValuesFindInSetFunc = ids -> ids.stream() + .map(id -> StrUtil.format("FIND_IN_SET({}, product_spu_ids) ", id)) + .collect(Collectors.joining(" OR ")); + return selectList(new QueryWrapper() + .eq("status", status) + .apply(productScopeValuesFindInSetFunc.apply(spuIds))); + } + + /** + * 获取指定活动编号的活动列表且 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表 + * + * @param ids 活动编号 + * @param dateTime 指定日期 + * @return 活动列表 + */ + default List selectListByIdsAndDateTimeLt(Collection ids, LocalDateTime dateTime) { + return selectList(new LambdaQueryWrapperX() + .in(RewardActivityDO::getId, ids) + .lt(RewardActivityDO::getStartTime, dateTime) + .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动 + .orderByDesc(RewardActivityDO::getCreateTime) + ); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java index 05ad13eed..d754d0d9f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java @@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; - import jakarta.validation.Valid; + +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -89,4 +90,14 @@ public interface DiscountActivityService { */ List getDiscountProductsByActivityId(Collection activityIds); + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 当前日期时间 + * @return 折扣活动列表 + */ + List getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java index b8b496fdb..f103cf553 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.discount; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; @@ -15,16 +16,20 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapp import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; import cn.iocoder.yudao.module.promotion.util.PromotionUtils; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; +import java.time.LocalDateTime; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; /** @@ -109,7 +114,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { /** * 校验商品是否冲突 * - * @param id 编号 + * @param id 编号 * @param products 商品列表 */ private void validateDiscountActivityProductConflicts(Long id, List products) { @@ -184,4 +189,17 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { return discountProductMapper.selectList("activity_id", activityIds); } + @Override + public List getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号 + List> spuIdAndActivityIdMaps = discountProductMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) { + return Collections.emptyList(); + } + + // 2. 查询活动详情 + return discountActivityMapper.selectListByIdsAndDateTimeLt( + convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java index 7176e980b..e2e225608 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java @@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; - import jakarta.validation.Valid; + +import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -71,4 +72,14 @@ public interface RewardActivityService { */ List getMatchRewardActivityList(Collection spuIds); + /** + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录 + * + * @param spuIds spu 编号 + * @param status 状态 + * @param dateTime 当前日期时间 + * @return 满减送活动列表 + */ + List getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java index 723dda933..e896eab92 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java @@ -11,14 +11,17 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; import cn.iocoder.yudao.module.promotion.util.PromotionUtils; +import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import jakarta.annotation.Resource; +import java.time.LocalDateTime; import java.util.Collection; +import java.util.Collections; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static java.util.Arrays.asList; @@ -100,10 +103,11 @@ public class RewardActivityServiceImpl implements RewardActivityService { } // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验; + /** * 校验商品参加的活动是否冲突 * - * @param id 活动编号 + * @param id 活动编号 * @param spuIds 商品 SPU 编号数组 */ private void validateRewardActivitySpuConflicts(Long id, Collection spuIds) { @@ -125,7 +129,7 @@ public class RewardActivityServiceImpl implements RewardActivityService { /** * 获得商品参加的满减送活动的数组 * - * @param spuIds 商品 SPU 编号数组 + * @param spuIds 商品 SPU 编号数组 * @param statuses 活动状态数组 * @return 商品参加的满减送活动的数组 */ @@ -163,4 +167,16 @@ public class RewardActivityServiceImpl implements RewardActivityService { return null; } + @Override + public List getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection spuIds, Integer status, LocalDateTime dateTime) { + // 1. 查询出指定 spuId 的 spu 参加的活动 + List rewardActivityList = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, status); + if (CollUtil.isEmpty(rewardActivityList)) { + return Collections.emptyList(); + } + + // 2. 查询活动详情 + return rewardActivityMapper.selectListByIdsAndDateTimeLt(convertSet(rewardActivityList, RewardActivityDO::getId), dateTime); + } + } diff --git a/yudao-module-system/yudao-module-system-api/pom.xml b/yudao-module-system/yudao-module-system-api/pom.xml index 2a60b20b8..c98baf3dd 100644 --- a/yudao-module-system/yudao-module-system-api/pom.xml +++ b/yudao-module-system/yudao-module-system-api/pom.xml @@ -22,32 +22,12 @@ yudao-common - - - - - io.github.mouzt - bizlog-sdk - - - - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.core - jackson-core - - org.springframework.boot spring-boot-starter-validation true - diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java index ad42c87f7..509d3f0a1 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApi.java @@ -1,11 +1,12 @@ package cn.iocoder.yudao.module.system.api.logger; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO; import jakarta.validation.Valid; -import java.util.List; - /** * 操作日志 API 接口 * @@ -21,12 +22,18 @@ public interface OperateLogApi { void createOperateLog(@Valid OperateLogCreateReqDTO createReqDTO); /** - * 获取指定模块的指定数据的操作日志 + * 创建操作日志 * - * @param module 操作模块 - * @param bizId 操作模块编号 - * @return 操作日志 + * @param createReqDTO 请求 */ - List getOperateLogByModuleAndBizId(String module, Long bizId); + void createOperateLogV2(@Valid OperateLogV2CreateReqDTO createReqDTO); + + /** + * 获取指定模块的指定数据的操作日志分页 + * + * @param pageReqVO 请求 + * @return 操作日志分页 + */ + PageResult getOperateLogPage(OperateLogV2PageReqDTO pageReqVO); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2CreateReqDTO.java similarity index 62% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java rename to yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2CreateReqDTO.java index d6c44604c..bab21a0dc 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2CreateReqDTO.java @@ -1,16 +1,20 @@ -package cn.iocoder.yudao.module.system.service.logger.bo; +package cn.iocoder.yudao.module.system.api.logger.dto; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; +import java.time.LocalDateTime; +import java.util.Map; + /** * 系统操作日志 Create Req BO * * @author HUIHUI */ @Data -public class OperateLogV2CreateReqBO { +public class OperateLogV2CreateReqDTO { /** * 链路追踪编号 @@ -23,29 +27,29 @@ public class OperateLogV2CreateReqBO { * * 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性 */ - @NotEmpty(message = "用户编号不能为空") + @NotNull(message = "用户编号不能为空") private Long userId; /** * 用户类型 * * 关联 {@link UserTypeEnum} */ - @NotEmpty(message = "用户类型不能为空") + @NotNull(message = "用户类型不能为空") private Integer userType; /** - * 操作模块 + * 操作模块类型 */ - @NotEmpty(message = "操作模块不能为空") - private String module; + @NotEmpty(message = "操作模块类型不能为空") + private String type; /** * 操作名 */ @NotEmpty(message = "操作名不能为空") - private String name; + private String subType; /** * 操作模块业务编号 */ - @NotEmpty(message = "操作模块业务编号不能为空") + @NotNull(message = "操作模块业务编号不能为空") private Long bizId; /** * 操作内容,记录整个操作的明细 @@ -57,7 +61,7 @@ public class OperateLogV2CreateReqBO { * 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ) * 例如说,记录订单编号,{ orderId: "1"} */ - private String extra; + private Map extra; /** * 请求方法名 @@ -80,4 +84,38 @@ public class OperateLogV2CreateReqBO { @NotEmpty(message = "浏览器 UA 不能为空") private String userAgent; + /** + * Java 方法名 + */ + private String javaMethod; + /** + * Java 方法的参数 + */ + private String javaMethodArgs; + + /** + * 开始时间 + */ + private LocalDateTime startTime; + + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + + /** + * 结果码 + */ + private Integer resultCode; + + /** + * 结果提示 + */ + private String resultMsg; + + /** + * 结果数据 + */ + private String resultData; + } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2PageReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2PageReqDTO.java new file mode 100644 index 000000000..aa54c3f5c --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2PageReqDTO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.api.logger.dto; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import lombok.Data; + +/** + * 操作日志分页 Request DTO + * + * @author HUIHUI + */ +@Data +public class OperateLogV2PageReqDTO extends PageParam { + + /** + * 模块类型 + */ + private String bizType; + /** + * 模块数据编号 + */ + private Long bizId; + + /** + * 用户编号 + */ + private Long userId; + +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java index a7670541d..17dfeb491 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/logger/dto/OperateLogV2RespDTO.java @@ -1,13 +1,9 @@ package cn.iocoder.yudao.module.system.api.logger.dto; -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; +import java.util.Map; /** * 系统操作日志 Resp DTO @@ -25,18 +21,22 @@ public class OperateLogV2RespDTO { * 用户编号 */ private Long userId; + /** + * 用户名称 + */ + private String userName; /** * 用户类型 */ private Integer userType; /** - * 操作模块 + * 操作模块类型 */ - private String module; + private String type; /** * 操作名 */ - private String name; + private String subType; /** * 操作模块业务编号 */ @@ -48,7 +48,7 @@ public class OperateLogV2RespDTO { /** * 拓展字段 */ - private String extra; + private Map extra; /** * 请求方法名 @@ -67,21 +67,43 @@ public class OperateLogV2RespDTO { */ private String userAgent; + /** + * Java 方法名 + */ + private String javaMethod; + /** + * Java 方法的参数 + */ + private String javaMethodArgs; + + /** + * 开始时间 + */ + private LocalDateTime startTime; + + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + + /** + * 结果码 + */ + private Integer resultCode; + + /** + * 结果提示 + */ + private String resultMsg; + + /** + * 结果数据 + */ + private String resultData; + /** * 创建时间 */ - // TODO puhui999: 木得效果怎么肥事 - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) private LocalDateTime createTime; - // TODO @puhui999:下面 2 个字段不用返回;用 userId 哈;返回一个 userName - /** - * 创建者 - */ - private String creator; - /** - * 创建者名称 - */ - private String creatorName; - } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java index d748bcc23..ffe10b9c8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/logger/OperateLogApiImpl.java @@ -1,18 +1,21 @@ package cn.iocoder.yudao.module.system.api.logger; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.service.logger.OperateLogService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import jakarta.annotation.Resource; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -39,21 +42,31 @@ public class OperateLogApiImpl implements OperateLogApi { } @Override - public List getOperateLogByModuleAndBizId(String module, Long bizId) { - List logList = operateLogService.getOperateLogByModuleAndBizId(module, bizId); - if (CollUtil.isEmpty(logList)) { - return Collections.emptyList(); + @Async + public void createOperateLogV2(OperateLogV2CreateReqDTO createReqDTO) { + operateLogService.createOperateLogV2(createReqDTO); + } + + @Override + public PageResult getOperateLogPage(OperateLogV2PageReqDTO pageReqVO) { + PageResult operateLogPage = operateLogService.getOperateLogPage(pageReqVO); + if (CollUtil.isEmpty(operateLogPage.getList())) { + return PageResult.empty(); } // 获取用户 - List userList = adminUserService.getUserList(convertSet(logList, item -> Long.parseLong(item.getCreator()))); + List userList = adminUserService.getUserList(convertSet(operateLogPage.getList(), OperateLogV2DO::getUserId)); + return BeanUtils.toBean(operateLogPage, OperateLogV2RespDTO.class).setList(setUserInfo(operateLogPage.getList(), userList)); + } + + private static List setUserInfo(List logList, List userList) { Map userMap = convertMap(userList, AdminUserDO::getId); return convertList(logList, item -> { - OperateLogV2RespDTO bean = BeanUtils.toBean(item, OperateLogV2RespDTO.class); - findAndThen(userMap, Long.parseLong(item.getCreator()), user -> { - bean.setCreatorName(user.getNickname()); + OperateLogV2RespDTO respDTO = BeanUtils.toBean(item, OperateLogV2RespDTO.class); + findAndThen(userMap, item.getUserId(), user -> { + respDTO.setUserName(user.getNickname()); }); - return bean; + return respDTO; }); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java index 10035c8e9..656331c52 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/logger/OperateLogV2DO.java @@ -1,13 +1,19 @@ package cn.iocoder.yudao.module.system.dal.dataobject.logger; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; +import java.time.LocalDateTime; +import java.util.Map; + /** * 操作日志表 V2 * @@ -19,6 +25,16 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) public class OperateLogV2DO extends BaseDO { + /** + * {@link #javaMethodArgs} 的最大长度 + */ + public static final Integer JAVA_METHOD_ARGS_MAX_LENGTH = 8000; + + /** + * {@link #resultData} 的最大长度 + */ + public static final Integer RESULT_MAX_LENGTH = 4000; + /** * 日志主键 */ @@ -42,15 +58,14 @@ public class OperateLogV2DO extends BaseDO { * 关联 {@link UserTypeEnum} */ private Integer userType; - // TODO @puhui999:module 改成 type,name 改成 subType; /** - * 操作模块 + * 操作模块类型 */ - private String module; + private String type; /** * 操作名 */ - private String name; + private String subType; /** * 操作模块业务编号 */ @@ -66,8 +81,8 @@ public class OperateLogV2DO extends BaseDO { * * 例如说,记录订单编号,{ orderId: "1"} */ - // TODO @puhui999:看看能不能类似 exts 搞 json 格式; - private String extra; + @TableField(typeHandler = JacksonTypeHandler.class) + private Map extra; /** * 请求方法名 */ @@ -85,9 +100,43 @@ public class OperateLogV2DO extends BaseDO { */ private String userAgent; - // TODO @芋艿:requestUrl、requestMethod - // TODO @芋艿:javaMethod、javaMethodArgs - // TODO @芋艿:startTime、duration - // TODO @芋艿:resultMsg、resultData + /** + * Java 方法名 + */ + private String javaMethod; + /** + * Java 方法的参数 + * + * 实际格式为 Map + * 不使用 @TableField(typeHandler = FastjsonTypeHandler.class) 注解的原因是,数据库存储有长度限制,会进行裁剪,会导致 JSON 反序列化失败 + * 其中,key 为参数名,value 为参数值 + */ + private String javaMethodArgs; + /** + * 开始时间 + */ + private LocalDateTime startTime; + /** + * 执行时长,单位:毫秒 + */ + private Integer duration; + /** + * 结果码 + * + * 目前使用的 {@link CommonResult#getCode()} 属性 + */ + private Integer resultCode; + /** + * 结果提示 + * + * 目前使用的 {@link CommonResult#getMsg()} 属性 + */ + private String resultMsg; + /** + * 结果数据 + * + * 如果是对象,则使用 JSON 格式化 + */ + private String resultData; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogV2Mapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogV2Mapper.java index 362f0d2c4..acf14478f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogV2Mapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/logger/OperateLogV2Mapper.java @@ -3,28 +3,18 @@ package cn.iocoder.yudao.module.system.dal.mysql.logger; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO; import org.apache.ibatis.annotations.Mapper; -import java.util.Collection; -import java.util.List; - @Mapper public interface OperateLogV2Mapper extends BaseMapperX { - default PageResult selectPage(OperateLogPageReqVO reqVO, Collection userIds) { - LambdaQueryWrapperX query = new LambdaQueryWrapperX() - .likeIfPresent(OperateLogV2DO::getModule, reqVO.getModule()) - .inIfPresent(OperateLogV2DO::getUserId, userIds); - query.orderByDesc(OperateLogV2DO::getId); // 降序 - return selectPage(reqVO, query); - } - - default List selectListByModuleAndBizId(String module, Long bizId) { - return selectList(new LambdaQueryWrapperX() - .eq(OperateLogV2DO::getModule, module) - .eq(OperateLogV2DO::getBizId, bizId) + default PageResult selectPage(OperateLogV2PageReqDTO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(OperateLogV2DO::getType, pageReqVO.getBizType()) + .eqIfPresent(OperateLogV2DO::getBizId, pageReqVO.getBizId()) + .eqIfPresent(OperateLogV2DO::getUserId, pageReqVO.getUserId()) .orderByDesc(OperateLogV2DO::getCreateTime)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/config/YudaoOperateLogV2Configuration.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/config/YudaoOperateLogV2Configuration.java deleted file mode 100644 index a5f3a9eaa..000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/config/YudaoOperateLogV2Configuration.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.yudao.module.system.framework.bizlog.config; - -import com.mzt.logapi.starter.annotation.EnableLogRecord; -import org.springframework.context.annotation.Configuration; - -// TODO @puhui999:挪到 yudao-spring-boot-starter-biz-operatelog 下,搞个 cn.iocoder.yudao.framework.operatelogv2;跑通后,我们直接就删除老的实现了; -/** - * mzt-biz-log 配置类 - * - * @author HUIHUI - */ -@Configuration(proxyBeanMethods = false) -@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦 -public class YudaoOperateLogV2Configuration { - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/package-info.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/package-info.java deleted file mode 100644 index c96f3a0c1..000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.system.framework.bizlog; \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/service/ILogRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/service/ILogRecordServiceImpl.java deleted file mode 100644 index 07b25343e..000000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/service/ILogRecordServiceImpl.java +++ /dev/null @@ -1,85 +0,0 @@ -package cn.iocoder.yudao.module.system.framework.bizlog.service; - -import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; -import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; -import cn.iocoder.yudao.module.system.service.logger.OperateLogService; -import cn.iocoder.yudao.module.system.service.logger.bo.OperateLogV2CreateReqBO; -import com.mzt.logapi.beans.LogRecord; -import com.mzt.logapi.service.ILogRecordService; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.List; - -// TODO @puhui999:这个应该搞到 operatelog 组件里哈; -/** - * 操作日志 ILogRecordService 实现类 - * - * 基于 {@link OperateLogService} 实现,记录操作日志 - * - * @author HUIHUI - */ -@Slf4j -@Service -public class ILogRecordServiceImpl implements ILogRecordService { - - @Resource - private OperateLogService operateLogService; - - @Override - public void record(LogRecord logRecord) { - OperateLogV2CreateReqBO reqBO = new OperateLogV2CreateReqBO(); - // 补全通用字段 - reqBO.setTraceId(TracerUtils.getTraceId()); - // 补充用户信息 - fillUserFields(reqBO); - // 补全模块信息 - fillModuleFields(reqBO, logRecord); - // 补全请求信息 - fillRequestFields(reqBO); - // 异步记录日志 - operateLogService.createOperateLogV2(reqBO); - log.info("操作日志 ===> {}", reqBO); - } - - private static void fillUserFields(OperateLogV2CreateReqBO reqBO) { - reqBO.setUserId(WebFrameworkUtils.getLoginUserId()); - reqBO.setUserType(WebFrameworkUtils.getLoginUserType()); - } - - public static void fillModuleFields(OperateLogV2CreateReqBO reqBO, LogRecord logRecord) { - reqBO.setModule(logRecord.getType()); // 大模块类型如 crm-客户 - reqBO.setName(logRecord.getSubType());// 操作名称如 转移客户 - reqBO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号 - reqBO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 - reqBO.setExtra(logRecord.getExtra()); // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"} - } - - private static void fillRequestFields(OperateLogV2CreateReqBO reqBO) { - // 获得 Request 对象 - HttpServletRequest request = ServletUtils.getRequest(); - if (request == null) { - return; - } - // 补全请求信息 - reqBO.setRequestMethod(request.getMethod()); - reqBO.setRequestUrl(request.getRequestURI()); - reqBO.setUserIp(ServletUtils.getClientIP(request)); - reqBO.setUserAgent(ServletUtils.getUserAgent(request)); - } - - @Override - public List queryLog(String bizNo, String type) { - return Collections.emptyList(); - } - - @Override - public List queryLogByBizNo(String bizNo, String type, String subType) { - return Collections.emptyList(); - } - -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java new file mode 100644 index 000000000..978444e17 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.system.framework.operatelog; \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AdminUserParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AdminUserParseFunction.java similarity index 96% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AdminUserParseFunction.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AdminUserParseFunction.java index a88073d4e..5685dda75 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AdminUserParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AdminUserParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.system.framework.bizlog.function; +package cn.iocoder.yudao.module.system.framework.operatelog.parse; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AreaParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AreaParseFunction.java similarity index 92% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AreaParseFunction.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AreaParseFunction.java index f486a49fa..b63083a38 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AreaParseFunction.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/operatelog/parse/AreaParseFunction.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.system.framework.bizlog.function; +package cn.iocoder.yudao.module.system.framework.operatelog.parse; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java index 971685857..27ced45a0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogService.java @@ -2,12 +2,11 @@ package cn.iocoder.yudao.module.system.service.logger; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO; -import cn.iocoder.yudao.module.system.service.logger.bo.OperateLogV2CreateReqBO; - -import java.util.List; /** * 操作日志 Service 接口 @@ -38,16 +37,14 @@ public interface OperateLogService { * * @param createReqBO 创建请求 */ - void createOperateLogV2(OperateLogV2CreateReqBO createReqBO); + void createOperateLogV2(OperateLogV2CreateReqDTO createReqBO); - // TODO @puhui999:module 改成 type /** - * 获取指定模块的指定数据的操作日志 + * 获得操作日志分页列表 * - * @param module 操作模块 - * @param bizId 操作模块编号 - * @return 操作日志 + * @param pageReqVO 分页条件 + * @return 操作日志分页列表 */ - List getOperateLogByModuleAndBizId(String module, Long bizId); + PageResult getOperateLogPage(OperateLogV2PageReqDTO pageReqVO); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java index 39c84ed33..76532af87 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java @@ -6,13 +6,14 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogV2DO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogV2Mapper; -import cn.iocoder.yudao.module.system.service.logger.bo.OperateLogV2CreateReqBO; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -20,7 +21,6 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.util.Collection; -import java.util.List; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH; @@ -69,14 +69,17 @@ public class OperateLogServiceImpl implements OperateLogService { // ======================= LOG V2 ======================= @Override - public void createOperateLogV2(OperateLogV2CreateReqBO createReqBO) { + public void createOperateLogV2(OperateLogV2CreateReqDTO createReqBO) { OperateLogV2DO log = BeanUtils.toBean(createReqBO, OperateLogV2DO.class); + log.setJavaMethodArgs(StrUtils.maxLength(log.getJavaMethodArgs(), JAVA_METHOD_ARGS_MAX_LENGTH)); + log.setResultData(StrUtils.maxLength(log.getResultData(), RESULT_MAX_LENGTH)); operateLogV2Mapper.insert(log); } + @Override - public List getOperateLogByModuleAndBizId(String module, Long bizId) { - return operateLogV2Mapper.selectListByModuleAndBizId(module, bizId); + public PageResult getOperateLogPage(OperateLogV2PageReqDTO pageReqVO) { + return operateLogV2Mapper.selectPage(pageReqVO); } } diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 900656ecf..3e2a7ed6a 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -188,6 +188,7 @@ logging: cn.iocoder.yudao.module.trade.dal.mysql: debug cn.iocoder.yudao.module.promotion.dal.mysql: debug cn.iocoder.yudao.module.statistics.dal.mysql: debug + cn.iocoder.yudao.module.crm.dal.mysql: debug debug: false diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 627028bdd..21b2d48c3 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -79,7 +79,17 @@ mybatis-plus: password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成 mybatis-plus-join: - banner: false # 关闭控制台的 Banner 打印 + #是否打印 mybatis plus join banner 默认true + banner: false + #全局启用副表逻辑删除(默认true) 关闭后关联查询不会加副表逻辑删除 + sub-table-logic: true + #拦截器MappedStatement缓存(默认true) + ms-cache: true + #表别名(默认 t) + table-alias: t + #副表逻辑删除条件的位置,支持where、on + #默认ON (1.4.7.2及之前版本默认为where) + logic-del-type: on # Spring Data Redis 配置 spring: