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 909a0d34a..a3a9b6db4 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 @@ -7,12 +7,21 @@ package cn.iocoder.yudao.module.crm.enums; */ public interface LogRecordConstants { - String WHO = "【{getAdminUserById{#userId}}】"; + //======================= 客户模块类型 ======================= + // TODO puhui999: 确保模块命名方式为 module + 子模块名称的方式。统一定义模块名称是为了方便查询各自记录的操作日志,列如说:查询客户【张三的操作日志】就可以 module + bizId + String CRM_LEADS = "CRM-线索"; + String CRM_CUSTOMER = "CRM-客户"; + String CRM_CONTACT = "CRM-联系人"; + String CRM_BUSINESS = "CRM-商机"; + String CRM_CONTRACT = "CRM-合同"; + String CRM_PRODUCT = "CRM-产品"; + String CRM_RECEIVABLE = "CRM-回款"; + String CRM_RECEIVABLE_PLAN = "CRM-回款计划"; //======================= 客户转移操作日志 ======================= - String TRANSFER_CUSTOMER_LOG_TYPE = "客户转移"; - String TRANSFER_CUSTOMER_LOG_SUCCESS = WHO + "把客户【{{#crmCustomer.name}}】负责人【{getAdminUserById{#crmCustomer.ownerUserId}}】转移给了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; + String TRANSFER_CUSTOMER_LOG_SUCCESS = "把客户【{{#crmCustomer == null ? '' : #crmCustomer.name}}】负责人从" + + "【{getAdminUserById{#crmCustomer == null ? '' : #crmCustomer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; String TRANSFER_CUSTOMER_LOG_FAIL = ""; } 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 770171d57..25e16366c 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 @@ -5,9 +5,8 @@ Authorization: Bearer {{token}} tenant-id: {{adminTenentId}} { - "id": 11, - "newOwnerUserId": 127, - "oldOwnerPermissionLevel": 2 + "id": 10, + "newOwnerUserId": 127 } 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 e29da139e..854c9538a 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 @@ -123,7 +123,6 @@ public class CrmCustomerController { } @PutMapping("/transfer") - @Operation(summary = "客户转移") @PreAuthorize("@ss.hasPermission('crm:customer:update')") public CommonResult transfer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) { customerService.transferCustomer(reqVO, getLoginUserId()); 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 141852584..52725a675 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 @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerUpdat import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert; 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.LogRecordConstants; 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; @@ -27,6 +26,8 @@ import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CUSTOMER; +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.TRANSFER_CUSTOMER_LOG_SUCCESS; import static java.util.Collections.singletonList; /** @@ -129,8 +130,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @Override @Transactional(rollbackFor = Exception.class) - @LogRecord(success = LogRecordConstants.TRANSFER_CUSTOMER_LOG_SUCCESS, - type = LogRecordConstants.TRANSFER_CUSTOMER_LOG_TYPE, bizNo = "{{#reqVO.id}}") + @LogRecord(success = TRANSFER_CUSTOMER_LOG_SUCCESS, type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}") @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { // 1. 校验客户是否存在 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 3473954a7..246f45612 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,22 +1,15 @@ 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 cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum; 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 * * @author 芋道源码 */ @@ -26,16 +19,6 @@ import java.util.Map; @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; - /** * 日志主键 */ @@ -68,22 +51,14 @@ public class OperateLogV2DO extends BaseDO { */ private String name; /** - * 操作分类 - * - * 枚举 {@link OperateTypeEnum} + * 操作模块业务编号 */ - private Integer type; + private Long bizId; /** * 操作内容,记录整个操作的明细 * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 */ private String content; - /** - * 拓展字段,有些复杂的业务,需要记录一些字段 - * 例如说,记录订单编号,则可以添加 key 为 "orderId",value 为订单编号 - */ - @TableField(typeHandler = JacksonTypeHandler.class) - private Map exts; /** * 请求方法名 @@ -102,43 +77,4 @@ public class OperateLogV2DO extends BaseDO { */ private String userAgent; - /** - * 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 e778320a7..e08686914 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 @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.system.dal.mysql.logger; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; 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; @@ -16,14 +15,7 @@ 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) - .eqIfPresent(OperateLogV2DO::getType, reqVO.getType()) - .betweenIfPresent(OperateLogV2DO::getStartTime, reqVO.getStartTime()); - if (Boolean.TRUE.equals(reqVO.getSuccess())) { - query.eq(OperateLogV2DO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode()); - } else if (Boolean.FALSE.equals(reqVO.getSuccess())) { - query.gt(OperateLogV2DO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode()); - } + .inIfPresent(OperateLogV2DO::getUserId, userIds); query.orderByDesc(OperateLogV2DO::getId); // 降序 return selectPage(reqVO, query); } 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 index a74dc343f..9e6a9dd85 100644 --- 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 @@ -3,14 +3,13 @@ package cn.iocoder.yudao.module.system.framework.bizlog.config; import com.mzt.logapi.starter.annotation.EnableLogRecord; import org.springframework.context.annotation.Configuration; - /** - * + * mzt-biz-log 配置类 * * @author HUIHUI */ @Configuration(proxyBeanMethods = false) -@EnableLogRecord(tenant = "${yudao.info.base-package}") +@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/function/AdminUserParseFunction.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/bizlog/function/AdminUserParseFunction.java index 5e4d4f254..21459be6b 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/bizlog/function/AdminUserParseFunction.java @@ -34,11 +34,11 @@ public class AdminUserParseFunction implements IParseFunction { @Override public String apply(Object value) { if (value == null) { - log.warn("(getAdminUserById) 解析异常参数为 null"); + //log.warn("(getAdminUserById) 解析异常参数为 null"); return ""; } if (StrUtil.isEmpty(value.toString())) { - log.warn("(getAdminUserById) 解析异常参数为空"); + //log.warn("(getAdminUserById) 解析异常参数为空"); return ""; } 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 index 23584d247..161d4eca6 100644 --- 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 @@ -1,9 +1,14 @@ 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.api.logger.OperateLogApi; +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; @@ -26,7 +31,42 @@ public class ILogRecordServiceImpl implements ILogRecordService { @Override public void record(LogRecord logRecord) { - log.info("【logRecord】log={}", logRecord); + OperateLogV2CreateReqBO reqBO = new OperateLogV2CreateReqBO(); + // 补全通用字段 + reqBO.setTraceId(TracerUtils.getTraceId()); + // 补充用户信息 + fillUserFields(reqBO); + // 补全模块信息 + fillModuleFields(reqBO, logRecord); + // 补全请求信息 + fillRequestFields(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 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + } + + 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 @@ -38,4 +78,5 @@ public class ILogRecordServiceImpl implements ILogRecordService { 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/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 32f68a3b1..840913f62 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 @@ -53,8 +53,6 @@ public class OperateLogServiceImpl implements OperateLogService { @Override public void createOperateLogV2(OperateLogCreateReqDTO createReqDTO) { OperateLogV2DO log = BeanUtils.toBean(createReqDTO, 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); } 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-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java new file mode 100644 index 000000000..8c1675879 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/logger/bo/OperateLogV2CreateReqBO.java @@ -0,0 +1,78 @@ +package cn.iocoder.yudao.module.system.service.logger.bo; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +/** + * 系统操作日志 Create Req BO + * + * @author HUIHUI + */ +@Data +public class OperateLogV2CreateReqBO { + + /** + * 链路追踪编号 + * + * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 + */ + private String traceId; + /** + * 用户编号 + * + * 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性 + */ + @NotEmpty(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + * + * 关联 {@link UserTypeEnum} + */ + @NotEmpty(message = "用户类型不能为空") + private Integer userType; + /** + * 操作模块 + */ + @NotEmpty(message = "操作模块不能为空") + private String module; + /** + * 操作名 + */ + @NotEmpty(message = "操作名不能为空") + private String name; + /** + * 操作模块业务编号 + */ + @NotEmpty(message = "操作模块业务编号不能为空") + private Long bizId; + /** + * 操作内容,记录整个操作的明细 + * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 + */ + @NotEmpty(message = "操作内容不能为空") + private String content; + + /** + * 请求方法名 + */ + @NotEmpty(message = "请求方法名不能为空") + private String requestMethod; + /** + * 请求地址 + */ + @NotEmpty(message = "请求地址不能为空") + private String requestUrl; + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + /** + * 浏览器 UA + */ + @NotEmpty(message = "浏览器 UA 不能为空") + private String userAgent; + +}