CRM-线索:完善操作日志

This commit is contained in:
puhui999 2024-01-22 22:46:52 +08:00
parent 8675d13548
commit ca9f3c522d
3 changed files with 90 additions and 38 deletions

View File

@ -14,9 +14,13 @@ public interface LogRecordConstants {
String CRM_LEADS_CREATE_SUB_TYPE = "创建线索"; String CRM_LEADS_CREATE_SUB_TYPE = "创建线索";
String CRM_LEADS_CREATE_SUCCESS = "创建了线索{{#clue.name}}"; String CRM_LEADS_CREATE_SUCCESS = "创建了线索{{#clue.name}}";
String CRM_LEADS_UPDATE_SUB_TYPE = "更新线索"; String CRM_LEADS_UPDATE_SUB_TYPE = "更新线索";
String CRM_LEADS_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReqVO}}"; String CRM_LEADS_UPDATE_SUCCESS = "更新了线索【{{#clueName}}】: {_DIFF{#updateReq}}";
String CRM_LEADS_DELETE_SUB_TYPE = "删除线索"; String CRM_LEADS_DELETE_SUB_TYPE = "删除线索";
String CRM_LEADS_DELETE_SUCCESS = "删除了线索【{{#clueName}}】"; String CRM_LEADS_DELETE_SUCCESS = "删除了线索【{{#clueName}}】";
String CRM_LEADS_TRANSFER_SUB_TYPE = "转移线索";
String CRM_LEADS_TRANSFER_SUCCESS = "将线索【{{#clue.name}}】的负责人从【{getAdminUserById{#clue.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
String CRM_LEADS_TRANSLATE_SUB_TYPE = "线索转化为客户";
String CRM_LEADS_TRANSLATE_SUCCESS = "将线索【{{#clue.name}}】转化为客户";
// ======================= CRM_CUSTOMER 客户 ======================= // ======================= CRM_CUSTOMER 客户 =======================

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.clue.vo;
import cn.iocoder.yudao.framework.common.validation.Mobile; import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.framework.common.validation.Telephone; import cn.iocoder.yudao.framework.common.validation.Telephone;
import com.mzt.logapi.starter.annotation.DiffLogField;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import lombok.Data; import lombok.Data;
@ -19,32 +20,39 @@ public class CrmClueSaveReqVO {
private Long id; private Long id;
@Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx")
@DiffLogField(name = "线索名称")
@NotEmpty(message = "线索名称不能为空") @NotEmpty(message = "线索名称不能为空")
private String name; private String name;
@Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00")
@DiffLogField(name = "下次联系时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime contactNextTime; private LocalDateTime contactNextTime;
@Schema(description = "电话", example = "18000000000") @Schema(description = "电话", example = "18000000000")
@DiffLogField(name = "电话")
@Telephone @Telephone
private String telephone; private String telephone;
@Schema(description = "手机号", example = "18000000000") @Schema(description = "手机号", example = "18000000000")
@DiffLogField(name = "手机号")
@Mobile @Mobile
private String mobile; private String mobile;
@Schema(description = "地址", example = "北京市海淀区") @Schema(description = "地址", example = "北京市海淀区")
@DiffLogField(name = "地址")
private String address; private String address;
@Schema(description = "最后跟进时间") @Schema(description = "最后跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@DiffLogField(name = "最后跟进时间")
private LocalDateTime contactLastTime; private LocalDateTime contactLastTime;
@Schema(description = "负责人编号", example = "2048") @Schema(description = "负责人编号", example = "2048")
private Long ownerUserId; private Long ownerUserId;
@Schema(description = "备注", example = "随便") @Schema(description = "备注", example = "随便")
@DiffLogField(name = "备注")
private String remark; private String remark;
} }

View File

@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.CrmCluePageReqVO;
@ -76,7 +77,7 @@ public class CrmClueServiceImpl implements CrmClueService {
validateRelationDataExists(createReqVO); validateRelationDataExists(createReqVO);
// 2. 插入 // 2. 插入
CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class); CrmClueDO clue = BeanUtils.toBean(createReqVO, CrmClueDO.class).setId(null);
if (ObjUtil.isNull(createReqVO.getOwnerUserId())) { if (ObjUtil.isNull(createReqVO.getOwnerUserId())) {
clue.setOwnerUserId(userId); // 如果没有设置负责人那么默认操作人为负责人 clue.setOwnerUserId(userId); // 如果没有设置负责人那么默认操作人为负责人
} else { } else {
@ -99,16 +100,16 @@ public class CrmClueServiceImpl implements CrmClueService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
success = CRM_LEADS_UPDATE_SUCCESS) success = CRM_LEADS_UPDATE_SUCCESS)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) @CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#updateReq.id", level = CrmPermissionLevelEnum.OWNER)
public void updateClue(CrmClueSaveReqVO updateReqVO) { public void updateClue(CrmClueSaveReqVO updateReq) {
Assert.notNull(updateReqVO.getId(), "线索编号不能为空"); Assert.notNull(updateReq.getId(), "线索编号不能为空");
// 1. 校验线索是否存在 // 1. 校验线索是否存在
CrmClueDO oldClue = validateClueExists(updateReqVO.getId()); CrmClueDO oldClue = validateClueExists(updateReq.getId());
// 2. 校验关联数据 // 2. 校验关联数据
validateRelationDataExists(updateReqVO); validateRelationDataExists(updateReq);
// 3. 更新 // 3. 更新
CrmClueDO updateObj = BeanUtils.toBean(updateReqVO, CrmClueDO.class); CrmClueDO updateObj = BeanUtils.toBean(updateReq, CrmClueDO.class);
clueMapper.updateById(updateObj); clueMapper.updateById(updateObj);
// 3. 记录操作日志上下文 // 3. 记录操作日志上下文
@ -117,8 +118,19 @@ public class CrmClueServiceImpl implements CrmClueService {
} }
@Override @Override
public void updateClueFollowUp(CrmUpdateFollowUpReqBO clueUpdateFollowUpReqBO) { @LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_UPDATE_SUB_TYPE, bizNo = "{{#updateReq.bizId}",
clueMapper.updateById(BeanUtils.toBean(clueUpdateFollowUpReqBO, CrmClueDO.class).setId(clueUpdateFollowUpReqBO.getBizId())); success = CRM_LEADS_UPDATE_SUCCESS)
public void updateClueFollowUp(CrmUpdateFollowUpReqBO updateReq) {
// 校验线索是否存在
CrmClueDO oldClue = validateClueExists(updateReq.getBizId());
// 更新
clueMapper.updateById(BeanUtils.toBean(updateReq, CrmClueDO.class).setId(updateReq.getBizId()));
// 3. 记录操作日志上下文
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldClue, CrmUpdateFollowUpReqBO.class));
LogRecordContext.putVariable("clueName", oldClue.getName());
} }
@Override @Override
@ -143,48 +155,28 @@ public class CrmClueServiceImpl implements CrmClueService {
LogRecordContext.putVariable("clueName", clue.getName()); LogRecordContext.putVariable("clueName", clue.getName());
} }
private CrmClueDO validateClueExists(Long id) {
CrmClueDO crmClueDO = clueMapper.selectById(id);
if (crmClueDO == null) {
throw exception(CLUE_NOT_EXISTS);
}
return crmClueDO;
}
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.READ)
public CrmClueDO getClue(Long id) {
return clueMapper.selectById(id);
}
@Override
public List<CrmClueDO> getClueList(Collection<Long> ids, Long userId) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return clueMapper.selectBatchIds(ids, userId);
}
@Override
public PageResult<CrmClueDO> getCluePage(CrmCluePageReqVO pageReqVO, Long userId) {
return clueMapper.selectPage(pageReqVO, userId);
}
@Override @Override
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}",
success = CRM_LEADS_TRANSFER_SUCCESS)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
public void transferClue(CrmClueTransferReqVO reqVO, Long userId) { public void transferClue(CrmClueTransferReqVO reqVO, Long userId) {
// 1 校验线索是否存在 // 1 校验线索是否存在
validateClueExists(reqVO.getId()); CrmClueDO clue = validateClueExists(reqVO.getId());
// 2.1 数据权限转移 // 2.1 数据权限转移
crmPermissionService.transferPermission(CrmClueConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_LEADS.getType())); crmPermissionService.transferPermission(CrmClueConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_LEADS.getType()));
// 2.2 设置新的负责人 // 2.2 设置新的负责人
clueMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); clueMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
// 3. TODO 记录转移日志 // 3. 记录转移日志
LogRecordContext.putVariable("clue", clue);
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
public void translateCustomer(CrmClueTransformReqVO reqVO, Long userId) { public void translateCustomer(CrmClueTransformReqVO reqVO, Long userId) {
// 1.1 校验线索都存在 // 1.1 校验线索都存在
Set<Long> clueIds = reqVO.getIds(); Set<Long> clueIds = reqVO.getIds();
@ -214,6 +206,11 @@ public class CrmClueServiceImpl implements CrmClueService {
})); }));
// 2.3 复制跟进 // 2.3 复制跟进
updateFollowUpRecords(clueCustomerIdMap); updateFollowUpRecords(clueCustomerIdMap);
// 3. 记录操作日志
for (CrmClueDO clue : translateClues) {
getSelf().receiveClueLog(clue);
}
} }
private void updateFollowUpRecords(Map<Long, Long> clueCustomerIdMap) { private void updateFollowUpRecords(Map<Long, Long> clueCustomerIdMap) {
@ -229,6 +226,13 @@ public class CrmClueServiceImpl implements CrmClueService {
.setBizId(clueCustomerIdMap.get(followUpRecord.getBizId())))); .setBizId(clueCustomerIdMap.get(followUpRecord.getBizId()))));
} }
@LogRecord(type = CRM_LEADS_TYPE, subType = CRM_LEADS_TRANSLATE_SUB_TYPE, bizNo = "{{#clue.id}}",
success = CRM_LEADS_TRANSLATE_SUCCESS)
public void receiveClueLog(CrmClueDO clue) {
// 记录操作日志上下文
LogRecordContext.putVariable("clue", clue);
}
private void validateRelationDataExists(CrmClueSaveReqVO reqVO) { private void validateRelationDataExists(CrmClueSaveReqVO reqVO) {
// 校验负责人 // 校验负责人
if (Objects.nonNull(reqVO.getOwnerUserId()) && if (Objects.nonNull(reqVO.getOwnerUserId()) &&
@ -237,4 +241,40 @@ public class CrmClueServiceImpl implements CrmClueService {
} }
} }
private CrmClueDO validateClueExists(Long id) {
CrmClueDO crmClueDO = clueMapper.selectById(id);
if (crmClueDO == null) {
throw exception(CLUE_NOT_EXISTS);
}
return crmClueDO;
}
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_LEADS, bizId = "#id", level = CrmPermissionLevelEnum.READ)
public CrmClueDO getClue(Long id) {
return clueMapper.selectById(id);
}
@Override
public List<CrmClueDO> getClueList(Collection<Long> ids, Long userId) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return clueMapper.selectBatchIds(ids, userId);
}
@Override
public PageResult<CrmClueDO> getCluePage(CrmCluePageReqVO pageReqVO, Long userId) {
return clueMapper.selectPage(pageReqVO, userId);
}
/**
* 获得自身的代理对象解决 AOP 生效问题
*
* @return 自己
*/
private CrmClueServiceImpl getSelf() {
return SpringUtil.getBean(getClass());
}
} }