Commit d8bb55fc0bb955218c5d5c3029e82c0709074eaa

Authored by puhui999
1 parent ea4b4b89

CRM-客户:完善操作日志

yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
... ... @@ -40,7 +40,7 @@ public interface ErrorCodeConstants {
40 40 ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定");
41 41 ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常");
42 42 ErrorCode CUSTOMER_LOCK_FAIL_IS_LOCK = new ErrorCode(1_020_006_007, "锁定客户失败,它已经处于锁定状态");
43   - ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "锁定客户失败,它已经处于未锁定状态");
  43 + ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "解锁客户失败,它已经处于未锁定状态");
44 44 ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
45 45 ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限");
46 46  
... ...
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
... ... @@ -2,32 +2,56 @@ package cn.iocoder.yudao.module.crm.enums;
2 2  
3 3 /**
4 4 * CRM 操作日志枚举
  5 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串
5 6 *
6 7 * @author HUIHUI
7 8 */
8 9 public interface LogRecordConstants {
9 10  
10   - //======================= 客户模块类型 =======================
11   - // TODO puhui999: 确保模块命名方式为 module + 子模块名称的方式。统一定义模块名称是为了方便查询各自记录的操作日志,列如说:查询客户【张三的操作日志】就可以 module + bizId
12   - String CRM_LEADS = "CRM 线索";
13   - String CRM_CUSTOMER = "CRM 客户";
14   - String CRM_CONTACT = "CRM 联系人";
15   - String CRM_BUSINESS = "CRM 商机";
16   - String CRM_CONTRACT = "CRM 合同";
17   - String CRM_PRODUCT = "CRM 产品";
18   - String CRM_RECEIVABLE = "CRM 回款";
19   - String CRM_RECEIVABLE_PLAN = "CRM 回款计划";
  11 + // ======================= CRM_LEADS 线索 =======================
20 12  
21   - //======================= 客户转移操作日志 =======================
  13 + String CRM_LEADS_TYPE = "CRM 线索";
22 14  
23   - String TRANSFER_CUSTOMER_LOG_SUCCESS = "把客户【{{#crmCustomer.name}}】的负责人从【{getAdminUserById{#crmCustomer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
  15 + // ======================= CRM_CUSTOMER 客户 =======================
24 16  
25   - // TODO @puhui999:这里格式是不是可以这样;目的是:统一管理,也减少 Service 里各种“复杂”字符串
26   - // ======================= Customer 客户 =======================
27   - String CUSTOMER_TYPE = "CRM 客户";
28   - String CUSTOMER_CREATE_SUB_TYPE = "创建客户";
29   - String CUSTOMER_CREATE_SUCCESS = "更新了客户{_DIFF{#updateReqVO}}";
  17 + String CRM_CUSTOMER_TYPE = "CRM 客户";
  18 + String CRM_CUSTOMER_CREATE_SUB_TYPE = "创建客户";
  19 + String CRM_CUSTOMER_CREATE_SUCCESS = "创建了客户{{#customer.name}}";
  20 + String CRM_CUSTOMER_UPDATE_SUB_TYPE = "更新客户";
  21 + String CRM_CUSTOMER_UPDATE_SUCCESS = "更新了客户【{{#customerName}}】{_DIFF{#updateReqVO}}";
  22 + String CRM_CUSTOMER_DELETE_SUB_TYPE = "删除客户";
  23 + String CRM_CUSTOMER_DELETE_SUCCESS = "删除了客户【{{#customerName}}】";
  24 + String CRM_CUSTOMER_TRANSFER_SUB_TYPE = "转移客户";
  25 + String CRM_CUSTOMER_TRANSFER_SUCCESS = "将客户【{{#crmCustomer.name}}】的负责人从【{getAdminUserById{#crmCustomer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】";
  26 + String CRM_CUSTOMER_LOCK_SUB_TYPE = "{{#crmCustomer.lockStatus ? '锁定客户' : '解锁客户'}}";
  27 + String CRM_CUSTOMER_LOCK_SUCCESS = "{{#crmCustomer.lockStatus ? '将客户【#crmCustomer.name】锁定' : '将客户【#crmCustomer.name】解锁'}}";
  28 + String CRM_CUSTOMER_POOL_SUB_TYPE = "客户放入公海";
  29 + String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海";
  30 + String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}";
  31 + String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【#customer.name】分配给【#ownerUserName】' : '领取客户【#customer.name】'}}";
30 32  
31   - String CUSTOMER_UPDATE_SUB_TYPE = "更新客户";
  33 + // ======================= CRM_CONTACT 联系人 =======================
  34 +
  35 + String CRM_CONTACT_TYPE = "CRM 联系人";
  36 +
  37 + // ======================= CRM_BUSINESS 商机 =======================
  38 +
  39 + String CRM_BUSINESS_TYPE = "CRM 商机";
  40 +
  41 + // ======================= CRM_CONTRACT 合同 =======================
  42 +
  43 + String CRM_CONTRACT_TYPE = "CRM 合同";
  44 +
  45 + // ======================= CRM_PRODUCT 产品 =======================
  46 +
  47 + String CRM_PRODUCT_TYPE = "CRM 产品";
  48 +
  49 + // ======================= CRM_RECEIVABLE 回款 =======================
  50 +
  51 + String CRM_RECEIVABLE_TYPE = "CRM 回款";
  52 +
  53 + // ======================= CRM_RECEIVABLE_PLAN 回款计划 =======================
  54 +
  55 + String CRM_RECEIVABLE_PLAN_TYPE = "CRM 回款计划";
32 56  
33 57 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 7 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
7 8 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
8 9 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
... ... @@ -38,7 +39,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
38 39 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
39 40 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
40 41 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
41   -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CUSTOMER;
  42 +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CUSTOMER_TYPE;
42 43  
43 44 @Tag(name = "管理后台 - CRM 客户")
44 45 @RestController
... ... @@ -115,6 +116,15 @@ public class CrmCustomerController {
115 116 return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap));
116 117 }
117 118  
  119 + @GetMapping(value = {"/list-all-simple"})
  120 + @Operation(summary = "获取客户精简信息列表", description = "只包含有读权限的客户,主要用于前端的下拉选项")
  121 + public CommonResult<List<CrmCustomerSimpleRespVO>> getSimpleDeptList() {
  122 + CrmCustomerPageReqVO reqVO = new CrmCustomerPageReqVO();
  123 + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页
  124 + List<CrmCustomerDO> list = customerService.getCustomerPage(reqVO, getLoginUserId()).getList();
  125 + return success(BeanUtils.toBean(list, CrmCustomerSimpleRespVO.class));
  126 + }
  127 +
118 128 @GetMapping("/export-excel")
119 129 @Operation(summary = "导出客户 Excel")
120 130 @PreAuthorize("@ss.hasPermission('crm:customer:export')")
... ... @@ -143,7 +153,7 @@ public class CrmCustomerController {
143 153 public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(@RequestParam("id") Long id) {
144 154 OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO();
145 155 reqDTO.setPageSize(PAGE_SIZE_NONE); // 不分页
146   - reqDTO.setBizType(CRM_CUSTOMER);
  156 + reqDTO.setBizType(CRM_CUSTOMER_TYPE);
147 157 reqDTO.setBizId(id);
148 158 return success(operateLogApi.getOperateLogPage(reqDTO));
149 159 }
... ... @@ -172,7 +182,7 @@ public class CrmCustomerController {
172 182 @Parameter(name = "ids", description = "编号数组", required = true, example = "1,2,3")
173 183 @PreAuthorize("@ss.hasPermission('crm:customer:receive')")
174 184 public CommonResult<Boolean> receiveCustomer(@RequestParam(value = "ids") List<Long> ids) {
175   - customerService.receiveCustomer(ids, getLoginUserId());
  185 + customerService.receiveCustomer(ids, getLoginUserId(), Boolean.TRUE);
176 186 return success(true);
177 187 }
178 188  
... ... @@ -180,18 +190,8 @@ public class CrmCustomerController {
180 190 @Operation(summary = "分配公海给对应负责人")
181 191 @PreAuthorize("@ss.hasPermission('crm:customer:distribute')")
182 192 public CommonResult<Boolean> distributeCustomer(@Valid @RequestBody CrmCustomerDistributeReqVO distributeReqVO) {
183   - customerService.receiveCustomer(distributeReqVO.getIds(), distributeReqVO.getOwnerUserId());
  193 + customerService.receiveCustomer(distributeReqVO.getIds(), distributeReqVO.getOwnerUserId(), Boolean.FALSE);
184 194 return success(true);
185 195 }
186 196  
187   - // TODO 芋艿:这个接口要调整下
188   - //@GetMapping("/query-all-list")
189   - //@Operation(summary = "查询客户列表")
190   - //@PreAuthorize("@ss.hasPermission('crm:customer:all')")
191   - //public CommonResult<List<CrmCustomerQueryAllRespVO>> queryAll() {
192   - // List<CrmCustomerDO> crmCustomerDOList = customerService.getCustomerList();
193   - // List<CrmCustomerQueryAllRespVO> data = CrmCustomerConvert.INSTANCE.convertQueryAll(crmCustomerDOList);
194   - // return success(data);
195   - //}
196   -
197 197 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerSimpleRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +
  8 +@Schema(description = "管理后台 - 客户精简信息 Response VO")
  9 +@Data
  10 +@NoArgsConstructor
  11 +@AllArgsConstructor
  12 +public class CrmCustomerSimpleRespVO {
  13 +
  14 + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
  18 + private String name;
  19 +
  20 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java
... ... @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 5 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
6 6 import org.apache.ibatis.annotations.Mapper;
7 7  
  8 +import java.util.Collection;
8 9 import java.util.List;
9 10  
10 11 /**
... ... @@ -28,6 +29,12 @@ public interface CrmPermissionMapper extends BaseMapperX&lt;CrmPermissionDO&gt; {
28 29 .eq(CrmPermissionDO::getBizId, bizId));
29 30 }
30 31  
  32 + default List<CrmPermissionDO> selectByBizTypeAndBizIds(Integer bizType, Collection<Long> bizIds) {
  33 + return selectList(new LambdaQueryWrapperX<CrmPermissionDO>()
  34 + .eq(CrmPermissionDO::getBizType, bizType)
  35 + .in(CrmPermissionDO::getBizId, bizIds));
  36 + }
  37 +
31 38 default List<CrmPermissionDO> selectListByBizTypeAndUserId(Integer bizType, Long userId) {
32 39 return selectList(new LambdaQueryWrapperX<CrmPermissionDO>()
33 40 .eq(CrmPermissionDO::getBizType, bizType)
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
... ... @@ -18,12 +18,10 @@ import org.aspectj.lang.annotation.Aspect;
18 18 import org.aspectj.lang.annotation.Before;
19 19 import org.springframework.stereotype.Component;
20 20  
21   -import java.util.ArrayList;
22   -import java.util.List;
23   -import java.util.Map;
  21 +import java.util.*;
24 22  
25 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
27 25 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
28 26 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED;
29 27  
... ... @@ -46,16 +44,29 @@ public class CrmPermissionAspect {
46 44 Map<String, Object> expressionValues = parseExpressions(joinPoint, crmPermission);
47 45 Integer bizType = StrUtil.isEmpty(crmPermission.bizTypeValue()) ?
48 46 crmPermission.bizType()[0].getType() : (Integer) expressionValues.get(crmPermission.bizTypeValue()); // 模块类型
49   - Long bizId = (Long) expressionValues.get(crmPermission.bizId()); // 模块数据编号
  47 + // 处理兼容多个 bizId 的情况
  48 + Object object = expressionValues.get(crmPermission.bizId());// 模块数据编号
  49 + Set<Long> bizIds = new HashSet<>();
  50 + if (object instanceof Collection<?>) {
  51 + bizIds.addAll(convertSet((Collection<?>) object, item -> Long.parseLong(item.toString())));
  52 + } else {
  53 + bizIds.add(Long.parseLong(object.toString()));
  54 + }
50 55 Integer permissionLevel = crmPermission.level().getLevel(); // 需要的权限级别
  56 + List<CrmPermissionDO> permissionList = crmPermissionService.getPermissionListByBiz(bizType, bizIds);
  57 + Map<Long, List<CrmPermissionDO>> multiMap = convertMultiMap(permissionList, CrmPermissionDO::getBizId);
  58 + bizIds.forEach(bizId -> {
  59 + validatePermission(bizType, multiMap.get(bizId), permissionLevel);
  60 + });
  61 + }
51 62  
52   - // 1.1 如果是超级管理员则直接通过
  63 + private void validatePermission(Integer bizType, List<CrmPermissionDO> bizPermissions, Integer permissionLevel) {
  64 + // 1. 如果是超级管理员则直接通过
53 65 if (CrmPermissionUtils.isCrmAdmin()) {
54 66 return;
55 67 }
56   - // 1.2 获取数据权限
57   - List<CrmPermissionDO> bizPermissions = crmPermissionService.getPermissionListByBiz(bizType, bizId);
58   - if (CollUtil.isEmpty(bizPermissions)) { // 没有数据权限的情况
  68 + // 1.1 没有数据权限的情况
  69 + if (CollUtil.isEmpty(bizPermissions)) {
59 70 // 公海数据如果没有团队成员大家也因该有读权限才对
60 71 if (CrmPermissionLevelEnum.isRead(permissionLevel)) {
61 72 return;
... ... @@ -63,7 +74,7 @@ public class CrmPermissionAspect {
63 74  
64 75 // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针
65 76 throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType));
66   - } else { // 有数据权限但是没有负责人的情况
  77 + } else { // 1.2 有数据权限但是没有负责人的情况
67 78 if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) {
68 79 if (CrmPermissionLevelEnum.isRead(permissionLevel)) {
69 80 return;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
... ... @@ -86,7 +86,7 @@ public interface CrmCustomerService {
86 86 * 锁定/解锁客户
87 87 *
88 88 * @param lockReqVO 更新信息
89   - * @param userId 用户编号
  89 + * @param userId 用户编号
90 90 */
91 91 void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId);
92 92  
... ... @@ -104,15 +104,8 @@ public interface CrmCustomerService {
104 104 *
105 105 * @param ids 要领取的客户编号数组
106 106 * @param ownerUserId 负责人
  107 + * @param isReceive 是/否领取
107 108 */
108   - void receiveCustomer(List<Long> ids, Long ownerUserId);
109   -
110   - /**
111   - * 获取客户列表
112   - *
113   - * @return 客户列表
114   - * @author zyna
115   - */
116   - List<CrmCustomerDO> getCustomerList();
  109 + void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
117 110  
118 111 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
... ... @@ -16,9 +16,11 @@ import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
16 16 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
17 17 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
18 18 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
  19 +import cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils;
19 20 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
20 21 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
21 22 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  23 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
22 24 import com.mzt.logapi.context.LogRecordContext;
23 25 import com.mzt.logapi.service.impl.DiffParseFunction;
24 26 import com.mzt.logapi.starter.annotation.LogRecord;
... ... @@ -35,8 +37,7 @@ import java.util.List;
35 37  
36 38 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
37 39 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
38   -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CUSTOMER;
39   -import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.TRANSFER_CUSTOMER_LOG_SUCCESS;
  40 +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
40 41 import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
41 42 import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT;
42 43 import static java.util.Collections.singletonList;
... ... @@ -63,8 +64,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
63 64  
64 65 @Override
65 66 @Transactional(rollbackFor = Exception.class)
66   - @LogRecord(type = CRM_CUSTOMER, subType = "创建客户", bizNo = "{{#customerId}}", success = "创建了客户")
67   - // TODO @puhui999:创建了客户【客户名】,要记录进去;不然在展示操作日志的全列表,看不清楚是哪个客户哈;
  67 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_CREATE_SUB_TYPE, bizNo = "{{#customer.id}}", success = CRM_CUSTOMER_CREATE_SUCCESS)
68 68 public Long createCustomer(CrmCustomerSaveReqVO createReqVO, Long userId) {
69 69 createReqVO.setId(null);
70 70 // 1. 校验拥有客户是否到达上限
... ... @@ -81,14 +81,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
81 81 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
82 82 .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
83 83  
84   - // 4. 记录操作日志
85   - LogRecordContext.putVariable("customerId", customer.getId());
  84 + // 4. 记录操作日志上下文
  85 + LogRecordContext.putVariable("customer", customer);
86 86 return customer.getId();
87 87 }
88 88  
89 89 @Override
90 90 @Transactional(rollbackFor = Exception.class)
91   - @LogRecord(type = CRM_CUSTOMER, subType = "更新客户", bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}", extra = "{{#extra}}")
  91 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}", success = CRM_CUSTOMER_UPDATE_SUCCESS)
92 92 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
93 93 public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
94 94 Assert.notNull(updateReqVO.getId(), "客户编号不能为空");
... ... @@ -101,17 +101,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
101 101 CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
102 102 customerMapper.updateById(updateObj);
103 103  
104   - // 3. 记录操作日志
  104 + // 3. 记录操作日志上下文
105 105 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerSaveReqVO.class));
  106 + LogRecordContext.putVariable("customerName", oldCustomer.getName());
106 107 }
107 108  
108 109 @Override
109 110 @Transactional(rollbackFor = Exception.class)
110   - @LogRecord(type = CRM_CUSTOMER, subType = "删除客户", bizNo = "{{#id}}", success = "删除了客户")
  111 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_DELETE_SUB_TYPE, bizNo = "{{#id}}", success = CRM_CUSTOMER_DELETE_SUCCESS)
111 112 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
112 113 public void deleteCustomer(Long id) {
113 114 // 校验存在
114   - validateCustomerExists(id);
  115 + CrmCustomerDO customer = validateCustomerExists(id);
115 116 // TODO @puhui999:如果有联系人、商机,则不允许删除;
116 117  
117 118 // 删除
... ... @@ -119,48 +120,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
119 120 // 删除数据权限
120 121 permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id);
121 122 // TODO @puhui999:删除跟进记录
122   - }
123   -
124   - private CrmCustomerDO validateCustomerExists(Long id) {
125   - CrmCustomerDO customerDO = customerMapper.selectById(id);
126   - if (customerDO == null) {
127   - throw exception(CUSTOMER_NOT_EXISTS);
128   - }
129   - return customerDO;
130   - }
131   -
132   - @Override
133   - @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.READ)
134   - public CrmCustomerDO getCustomer(Long id) {
135   - return customerMapper.selectById(id);
136   - }
137   -
138   - @Override
139   - public List<CrmCustomerDO> getCustomerList(Collection<Long> ids) {
140   - if (CollUtil.isEmpty(ids)) {
141   - return Collections.emptyList();
142   - }
143   - return customerMapper.selectBatchIds(ids);
144   - }
145 123  
146   - @Override
147   - public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
148   - return customerMapper.selectPage(pageReqVO, userId);
149   - }
150   -
151   - /**
152   - * 校验客户是否存在
153   - *
154   - * @param customerId 客户 id
155   - */
156   - @Override
157   - public void validateCustomer(Long customerId) {
158   - validateCustomerExists(customerId);
  124 + // 记录操作日志上下文
  125 + LogRecordContext.putVariable("customerName", customer.getName());
159 126 }
160 127  
161 128 @Override
162 129 @Transactional(rollbackFor = Exception.class)
163   - @LogRecord(type = CRM_CUSTOMER, subType = "转移客户", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
  130 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_TRANSFER_SUB_TYPE, bizNo = "{{#reqVO.id}}", success = CRM_CUSTOMER_TRANSFER_SUCCESS)
164 131 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
165 132 public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
166 133 // 1.1 校验客户是否存在
... ... @@ -175,20 +142,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
175 142 customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
176 143  
177 144 // 3. TODO 记录转移日志
  145 + // 记录操作日志上下文
178 146 LogRecordContext.putVariable("crmCustomer", customer);
179 147 }
180 148  
181 149 @Override
182   - // TODO @puhui999:看看这个能不能根据条件,写操作日志;
183   - // TODO 如果是 锁定,则 subType 为 锁定客户;success 为 将客户【】锁定
184   - // TODO 如果是 解锁,则 subType 为 解锁客户;success 为 将客户【】解锁
185   - @LogRecord(type = CRM_CUSTOMER, subType = "锁定/解锁客户", bizNo = "{{#updateReqVO.id}}", success = "锁定了客户")
186   - // TODO @puhui999:数据权限
  150 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_LOCK_SUB_TYPE, bizNo = "{{#lockReqVO.id}}", success = CRM_CUSTOMER_LOCK_SUCCESS)
  151 + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#lockReqVO.id", level = CrmPermissionLevelEnum.OWNER)
187 152 public void lockCustomer(CrmCustomerLockReqVO lockReqVO, Long userId) {
188 153 // 1.1 校验当前客户是否存在
189   - validateCustomerExists(lockReqVO.getId());
  154 + CrmCustomerDO customer = validateCustomerExists(lockReqVO.getId());
190 155 // 1.2 校验当前是否重复操作锁定/解锁状态
191   - CrmCustomerDO customer = customerMapper.selectById(lockReqVO.getId());
192 156 if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) {
193 157 throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK);
194 158 }
... ... @@ -199,53 +163,16 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
199 163  
200 164 // 2. 更新锁定状态
201 165 customerMapper.updateById(BeanUtils.toBean(lockReqVO, CrmCustomerDO.class));
202   - }
203 166  
204   - /**
205   - * 校验用户拥有的客户数量,是否到达上限
206   - *
207   - * @param userId 用户编号
208   - * @param newCount 附加数量
209   - */
210   - private void validateCustomerExceedOwnerLimit(Long userId, int newCount) {
211   - List<CrmCustomerLimitConfigDO> limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId(
212   - CUSTOMER_OWNER_LIMIT.getType(), userId);
213   - if (CollUtil.isEmpty(limitConfigs)) {
214   - return;
215   - }
216   - Long ownerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(null, userId);
217   - Long dealOwnerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(true, userId);
218   - limitConfigs.forEach(limitConfig -> {
219   - long nowCount = limitConfig.getDealCountEnabled() ? ownerCount : ownerCount - dealOwnerCount;
220   - if (nowCount + newCount > limitConfig.getMaxCount()) {
221   - throw exception(CUSTOMER_OWNER_EXCEED_LIMIT);
222   - }
223   - });
  167 + // 3. 记录操作日志上下文
  168 + LogRecordContext.putVariable("crmCustomer", customer);
224 169 }
225 170  
226   - /**
227   - * 校验用户锁定的客户数量,是否到达上限
228   - *
229   - * @param userId 用户编号
230   - */
231   - private void validateCustomerExceedLockLimit(Long userId) {
232   - List<CrmCustomerLimitConfigDO> limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId(
233   - CUSTOMER_LOCK_LIMIT.getType(), userId);
234   - if (CollUtil.isEmpty(limitConfigs)) {
235   - return;
236   - }
237   - Long lockCount = customerMapper.selectCountByLockStatusAndOwnerUserId(true, userId);
238   - Integer maxCount = CollectionUtils.getMaxValue(limitConfigs, CrmCustomerLimitConfigDO::getMaxCount);
239   - assert maxCount != null;
240   - if (lockCount >= maxCount) {
241   - throw exception(CUSTOMER_LOCK_EXCEED_LIMIT);
242   - }
243   - }
  171 + // ==================== 公海相关操作 ====================
244 172  
245 173 @Override
246 174 @Transactional(rollbackFor = Exception.class)
247   - @LogRecord(type = CRM_CUSTOMER, subType = "客户放入公海", bizNo = "{{#id}}", success = "将客户放入了公海")
248   - // TODO @puhui999:将客户【】放入了公海
  175 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_POOL_SUB_TYPE, bizNo = "{{#id}}", success = CRM_CUSTOMER_POOL_SUCCESS)
249 176 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
250 177 public void putCustomerPool(Long id) {
251 178 // 1. 校验存在
... ... @@ -267,16 +194,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
267 194 permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(),
268 195 CrmPermissionLevelEnum.OWNER.getLevel());
269 196 // TODO @puhui999:联系人的负责人,也要设置为 null;这块和领取是对应的;因为领取后,负责人也要关联过来;
  197 +
  198 + // 记录操作日志上下文
  199 + LogRecordContext.putVariable("customerName", customer.getName());
270 200 }
271 201  
272 202 @Override
273 203 @Transactional(rollbackFor = Exception.class)
274   - // TODO @puhui999:权限校验
  204 + public void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive) {
  205 + if (!isReceive && !CrmPermissionUtils.isCrmAdmin()) { // 只有管理员可以分配
  206 + throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.CRM_CUSTOMER.getName());
  207 + }
275 208  
276   - // TODO @puhui999:如果是分配,操作日志是 “将客户【】分配给【】”
277   - // TODO @puhui999:如果是领取,操作日志是“领取客户【】”;
278   - // TODO @puhui999:如果是多条,则需要记录多条操作日志;不然 bizId 不好关联
279   - public void receiveCustomer(List<Long> ids, Long ownerUserId) {
280 209 // 1.1 校验存在
281 210 List<CrmCustomerDO> customers = customerMapper.selectBatchIds(ids);
282 211 if (customers.size() != ids.size()) {
... ... @@ -311,6 +240,53 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
311 240 // 2.3 创建负责人数据权限
312 241 permissionService.createPermissionBatch(createPermissions);
313 242 // TODO @芋艿:要不要处理关联的联系人???
  243 +
  244 + // 3. 记录操作日志
  245 + AdminUserRespDTO user = null;
  246 + if (!isReceive) {
  247 + user = adminUserApi.getUser(ownerUserId);
  248 + }
  249 + for (CrmCustomerDO customer : customers) {
  250 + receiveCustomerLog(customer, user == null ? null : user.getNickname());
  251 + }
  252 + }
  253 +
  254 + @LogRecord(type = CRM_CUSTOMER_TYPE, subType = CRM_CUSTOMER_RECEIVE_SUB_TYPE, bizNo = "{{#customer.id}}", success = CRM_CUSTOMER_RECEIVE_SUCCESS)
  255 + public void receiveCustomerLog(CrmCustomerDO customer, String ownerUserName) {
  256 +
  257 + }
  258 +
  259 + //======================= 查询相关 =======================
  260 +
  261 + @Override
  262 + @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.READ)
  263 + public CrmCustomerDO getCustomer(Long id) {
  264 + return customerMapper.selectById(id);
  265 + }
  266 +
  267 + @Override
  268 + public List<CrmCustomerDO> getCustomerList(Collection<Long> ids) {
  269 + if (CollUtil.isEmpty(ids)) {
  270 + return Collections.emptyList();
  271 + }
  272 + return customerMapper.selectBatchIds(ids);
  273 + }
  274 +
  275 + @Override
  276 + public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
  277 + return customerMapper.selectPage(pageReqVO, userId);
  278 + }
  279 +
  280 + //======================= 校验相关 =======================
  281 +
  282 + /**
  283 + * 校验客户是否存在
  284 + *
  285 + * @param customerId 客户 id
  286 + */
  287 + @Override
  288 + public void validateCustomer(Long customerId) {
  289 + validateCustomerExists(customerId);
314 290 }
315 291  
316 292 private void validateCustomerOwnerExists(CrmCustomerDO customer, Boolean pool) {
... ... @@ -327,6 +303,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
327 303 }
328 304 }
329 305  
  306 + private CrmCustomerDO validateCustomerExists(Long id) {
  307 + CrmCustomerDO customerDO = customerMapper.selectById(id);
  308 + if (customerDO == null) {
  309 + throw exception(CUSTOMER_NOT_EXISTS);
  310 + }
  311 + return customerDO;
  312 + }
  313 +
330 314 private void validateCustomerIsLocked(CrmCustomerDO customer, Boolean pool) {
331 315 if (customer.getLockStatus()) {
332 316 throw exception(pool ? CUSTOMER_LOCKED_PUT_POOL_FAIL : CUSTOMER_LOCKED, customer.getName());
... ... @@ -339,9 +323,45 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
339 323 }
340 324 }
341 325  
342   - @Override
343   - public List<CrmCustomerDO> getCustomerList() {
344   - return customerMapper.selectList();
  326 + /**
  327 + * 校验用户拥有的客户数量,是否到达上限
  328 + *
  329 + * @param userId 用户编号
  330 + * @param newCount 附加数量
  331 + */
  332 + private void validateCustomerExceedOwnerLimit(Long userId, int newCount) {
  333 + List<CrmCustomerLimitConfigDO> limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId(
  334 + CUSTOMER_OWNER_LIMIT.getType(), userId);
  335 + if (CollUtil.isEmpty(limitConfigs)) {
  336 + return;
  337 + }
  338 + Long ownerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(null, userId);
  339 + Long dealOwnerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(true, userId);
  340 + limitConfigs.forEach(limitConfig -> {
  341 + long nowCount = limitConfig.getDealCountEnabled() ? ownerCount : ownerCount - dealOwnerCount;
  342 + if (nowCount + newCount > limitConfig.getMaxCount()) {
  343 + throw exception(CUSTOMER_OWNER_EXCEED_LIMIT);
  344 + }
  345 + });
  346 + }
  347 +
  348 + /**
  349 + * 校验用户锁定的客户数量,是否到达上限
  350 + *
  351 + * @param userId 用户编号
  352 + */
  353 + private void validateCustomerExceedLockLimit(Long userId) {
  354 + List<CrmCustomerLimitConfigDO> limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId(
  355 + CUSTOMER_LOCK_LIMIT.getType(), userId);
  356 + if (CollUtil.isEmpty(limitConfigs)) {
  357 + return;
  358 + }
  359 + Long lockCount = customerMapper.selectCountByLockStatusAndOwnerUserId(true, userId);
  360 + Integer maxCount = CollectionUtils.getMaxValue(limitConfigs, CrmCustomerLimitConfigDO::getMaxCount);
  361 + assert maxCount != null;
  362 + if (lockCount >= maxCount) {
  363 + throw exception(CUSTOMER_LOCK_EXCEED_LIMIT);
  364 + }
345 365 }
346 366  
347 367 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java
... ... @@ -91,6 +91,15 @@ public interface CrmPermissionService {
91 91 List<CrmPermissionDO> getPermissionListByBiz(Integer bizType, Long bizId);
92 92  
93 93 /**
  94 + * 获取数据权限列表,通过 数据类型 x 某个数据
  95 + *
  96 + * @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
  97 + * @param bizIds 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
  98 + * @return Crm 数据权限列表
  99 + */
  100 + List<CrmPermissionDO> getPermissionListByBiz(Integer bizType, Collection<Long> bizIds);
  101 +
  102 + /**
94 103 * 获取用户参与的模块数据列表
95 104 *
96 105 * @param bizType 模块类型
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
... ... @@ -188,6 +188,11 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
188 188 }
189 189  
190 190 @Override
  191 + public List<CrmPermissionDO> getPermissionListByBiz(Integer bizType, Collection<Long> bizIds) {
  192 + return crmPermissionMapper.selectByBizTypeAndBizIds(bizType, bizIds);
  193 + }
  194 +
  195 + @Override
191 196 public List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) {
192 197 return crmPermissionMapper.selectListByBizTypeAndUserId(bizType, userId);
193 198 }
... ...