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,7 +40,7 @@ public interface ErrorCodeConstants {
40 ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定"); 40 ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定");
41 ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常"); 41 ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常");
42 ErrorCode CUSTOMER_LOCK_FAIL_IS_LOCK = new ErrorCode(1_020_006_007, "锁定客户失败,它已经处于锁定状态"); 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 ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限"); 44 ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
45 ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限"); 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,32 +2,56 @@ package cn.iocoder.yudao.module.crm.enums;
2 2
3 /** 3 /**
4 * CRM 操作日志枚举 4 * CRM 操作日志枚举
  5 + * 目的:统一管理,也减少 Service 里各种“复杂”字符串
5 * 6 *
6 * @author HUIHUI 7 * @author HUIHUI
7 */ 8 */
8 public interface LogRecordConstants { 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,6 +3,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.customer;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; 7 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
7 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 8 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
8 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*; 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,7 +39,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
38 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; 39 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
39 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; 40 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
40 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 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 @Tag(name = "管理后台 - CRM 客户") 44 @Tag(name = "管理后台 - CRM 客户")
44 @RestController 45 @RestController
@@ -115,6 +116,15 @@ public class CrmCustomerController { @@ -115,6 +116,15 @@ public class CrmCustomerController {
115 return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap)); 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 @GetMapping("/export-excel") 128 @GetMapping("/export-excel")
119 @Operation(summary = "导出客户 Excel") 129 @Operation(summary = "导出客户 Excel")
120 @PreAuthorize("@ss.hasPermission('crm:customer:export')") 130 @PreAuthorize("@ss.hasPermission('crm:customer:export')")
@@ -143,7 +153,7 @@ public class CrmCustomerController { @@ -143,7 +153,7 @@ public class CrmCustomerController {
143 public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(@RequestParam("id") Long id) { 153 public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(@RequestParam("id") Long id) {
144 OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO(); 154 OperateLogV2PageReqDTO reqDTO = new OperateLogV2PageReqDTO();
145 reqDTO.setPageSize(PAGE_SIZE_NONE); // 不分页 155 reqDTO.setPageSize(PAGE_SIZE_NONE); // 不分页
146 - reqDTO.setBizType(CRM_CUSTOMER); 156 + reqDTO.setBizType(CRM_CUSTOMER_TYPE);
147 reqDTO.setBizId(id); 157 reqDTO.setBizId(id);
148 return success(operateLogApi.getOperateLogPage(reqDTO)); 158 return success(operateLogApi.getOperateLogPage(reqDTO));
149 } 159 }
@@ -172,7 +182,7 @@ public class CrmCustomerController { @@ -172,7 +182,7 @@ public class CrmCustomerController {
172 @Parameter(name = "ids", description = "编号数组", required = true, example = "1,2,3") 182 @Parameter(name = "ids", description = "编号数组", required = true, example = "1,2,3")
173 @PreAuthorize("@ss.hasPermission('crm:customer:receive')") 183 @PreAuthorize("@ss.hasPermission('crm:customer:receive')")
174 public CommonResult<Boolean> receiveCustomer(@RequestParam(value = "ids") List<Long> ids) { 184 public CommonResult<Boolean> receiveCustomer(@RequestParam(value = "ids") List<Long> ids) {
175 - customerService.receiveCustomer(ids, getLoginUserId()); 185 + customerService.receiveCustomer(ids, getLoginUserId(), Boolean.TRUE);
176 return success(true); 186 return success(true);
177 } 187 }
178 188
@@ -180,18 +190,8 @@ public class CrmCustomerController { @@ -180,18 +190,8 @@ public class CrmCustomerController {
180 @Operation(summary = "分配公海给对应负责人") 190 @Operation(summary = "分配公海给对应负责人")
181 @PreAuthorize("@ss.hasPermission('crm:customer:distribute')") 191 @PreAuthorize("@ss.hasPermission('crm:customer:distribute')")
182 public CommonResult<Boolean> distributeCustomer(@Valid @RequestBody CrmCustomerDistributeReqVO distributeReqVO) { 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 return success(true); 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,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; 5 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
6 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
7 7
  8 +import java.util.Collection;
8 import java.util.List; 9 import java.util.List;
9 10
10 /** 11 /**
@@ -28,6 +29,12 @@ public interface CrmPermissionMapper extends BaseMapperX&lt;CrmPermissionDO&gt; { @@ -28,6 +29,12 @@ public interface CrmPermissionMapper extends BaseMapperX&lt;CrmPermissionDO&gt; {
28 .eq(CrmPermissionDO::getBizId, bizId)); 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 default List<CrmPermissionDO> selectListByBizTypeAndUserId(Integer bizType, Long userId) { 38 default List<CrmPermissionDO> selectListByBizTypeAndUserId(Integer bizType, Long userId) {
32 return selectList(new LambdaQueryWrapperX<CrmPermissionDO>() 39 return selectList(new LambdaQueryWrapperX<CrmPermissionDO>()
33 .eq(CrmPermissionDO::getBizType, bizType) 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,12 +18,10 @@ import org.aspectj.lang.annotation.Aspect;
18 import org.aspectj.lang.annotation.Before; 18 import org.aspectj.lang.annotation.Before;
19 import org.springframework.stereotype.Component; 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 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 25 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
28 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED; 26 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED;
29 27
@@ -46,16 +44,29 @@ public class CrmPermissionAspect { @@ -46,16 +44,29 @@ public class CrmPermissionAspect {
46 Map<String, Object> expressionValues = parseExpressions(joinPoint, crmPermission); 44 Map<String, Object> expressionValues = parseExpressions(joinPoint, crmPermission);
47 Integer bizType = StrUtil.isEmpty(crmPermission.bizTypeValue()) ? 45 Integer bizType = StrUtil.isEmpty(crmPermission.bizTypeValue()) ?
48 crmPermission.bizType()[0].getType() : (Integer) expressionValues.get(crmPermission.bizTypeValue()); // 模块类型 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 Integer permissionLevel = crmPermission.level().getLevel(); // 需要的权限级别 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 if (CrmPermissionUtils.isCrmAdmin()) { 65 if (CrmPermissionUtils.isCrmAdmin()) {
54 return; 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 if (CrmPermissionLevelEnum.isRead(permissionLevel)) { 71 if (CrmPermissionLevelEnum.isRead(permissionLevel)) {
61 return; 72 return;
@@ -63,7 +74,7 @@ public class CrmPermissionAspect { @@ -63,7 +74,7 @@ public class CrmPermissionAspect {
63 74
64 // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针 75 // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针
65 throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); 76 throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType));
66 - } else { // 有数据权限但是没有负责人的情况 77 + } else { // 1.2 有数据权限但是没有负责人的情况
67 if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) { 78 if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) {
68 if (CrmPermissionLevelEnum.isRead(permissionLevel)) { 79 if (CrmPermissionLevelEnum.isRead(permissionLevel)) {
69 return; 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,7 +86,7 @@ public interface CrmCustomerService {
86 * 锁定/解锁客户 86 * 锁定/解锁客户
87 * 87 *
88 * @param lockReqVO 更新信息 88 * @param lockReqVO 更新信息
89 - * @param userId 用户编号 89 + * @param userId 用户编号
90 */ 90 */
91 void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId); 91 void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId);
92 92
@@ -104,15 +104,8 @@ public interface CrmCustomerService { @@ -104,15 +104,8 @@ public interface CrmCustomerService {
104 * 104 *
105 * @param ids 要领取的客户编号数组 105 * @param ids 要领取的客户编号数组
106 * @param ownerUserId 负责人 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,9 +16,11 @@ import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
16 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 16 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
17 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; 17 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
18 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; 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 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; 20 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
20 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; 21 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
21 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 22 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  23 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
22 import com.mzt.logapi.context.LogRecordContext; 24 import com.mzt.logapi.context.LogRecordContext;
23 import com.mzt.logapi.service.impl.DiffParseFunction; 25 import com.mzt.logapi.service.impl.DiffParseFunction;
24 import com.mzt.logapi.starter.annotation.LogRecord; 26 import com.mzt.logapi.starter.annotation.LogRecord;
@@ -35,8 +37,7 @@ import java.util.List; @@ -35,8 +37,7 @@ import java.util.List;
35 37
36 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 38 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
37 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; 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 import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT; 41 import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
41 import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT; 42 import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT;
42 import static java.util.Collections.singletonList; 43 import static java.util.Collections.singletonList;
@@ -63,8 +64,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -63,8 +64,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
63 64
64 @Override 65 @Override
65 @Transactional(rollbackFor = Exception.class) 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 public Long createCustomer(CrmCustomerSaveReqVO createReqVO, Long userId) { 68 public Long createCustomer(CrmCustomerSaveReqVO createReqVO, Long userId) {
69 createReqVO.setId(null); 69 createReqVO.setId(null);
70 // 1. 校验拥有客户是否到达上限 70 // 1. 校验拥有客户是否到达上限
@@ -81,14 +81,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -81,14 +81,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
81 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) 81 permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
82 .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人 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 return customer.getId(); 86 return customer.getId();
87 } 87 }
88 88
89 @Override 89 @Override
90 @Transactional(rollbackFor = Exception.class) 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 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE) 92 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
93 public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) { 93 public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
94 Assert.notNull(updateReqVO.getId(), "客户编号不能为空"); 94 Assert.notNull(updateReqVO.getId(), "客户编号不能为空");
@@ -101,17 +101,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -101,17 +101,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
101 CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO); 101 CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
102 customerMapper.updateById(updateObj); 102 customerMapper.updateById(updateObj);
103 103
104 - // 3. 记录操作日志 104 + // 3. 记录操作日志上下文
105 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerSaveReqVO.class)); 105 LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerSaveReqVO.class));
  106 + LogRecordContext.putVariable("customerName", oldCustomer.getName());
106 } 107 }
107 108
108 @Override 109 @Override
109 @Transactional(rollbackFor = Exception.class) 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 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) 112 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
112 public void deleteCustomer(Long id) { 113 public void deleteCustomer(Long id) {
113 // 校验存在 114 // 校验存在
114 - validateCustomerExists(id); 115 + CrmCustomerDO customer = validateCustomerExists(id);
115 // TODO @puhui999:如果有联系人、商机,则不允许删除; 116 // TODO @puhui999:如果有联系人、商机,则不允许删除;
116 117
117 // 删除 118 // 删除
@@ -119,48 +120,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -119,48 +120,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
119 // 删除数据权限 120 // 删除数据权限
120 permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id); 121 permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id);
121 // TODO @puhui999:删除跟进记录 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 @Override 128 @Override
162 @Transactional(rollbackFor = Exception.class) 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 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) 131 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
165 public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { 132 public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
166 // 1.1 校验客户是否存在 133 // 1.1 校验客户是否存在
@@ -175,20 +142,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -175,20 +142,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
175 customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId()); 142 customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
176 143
177 // 3. TODO 记录转移日志 144 // 3. TODO 记录转移日志
  145 + // 记录操作日志上下文
178 LogRecordContext.putVariable("crmCustomer", customer); 146 LogRecordContext.putVariable("crmCustomer", customer);
179 } 147 }
180 148
181 @Override 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 public void lockCustomer(CrmCustomerLockReqVO lockReqVO, Long userId) { 152 public void lockCustomer(CrmCustomerLockReqVO lockReqVO, Long userId) {
188 // 1.1 校验当前客户是否存在 153 // 1.1 校验当前客户是否存在
189 - validateCustomerExists(lockReqVO.getId()); 154 + CrmCustomerDO customer = validateCustomerExists(lockReqVO.getId());
190 // 1.2 校验当前是否重复操作锁定/解锁状态 155 // 1.2 校验当前是否重复操作锁定/解锁状态
191 - CrmCustomerDO customer = customerMapper.selectById(lockReqVO.getId());  
192 if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) { 156 if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) {
193 throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK); 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,53 +163,16 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
199 163
200 // 2. 更新锁定状态 164 // 2. 更新锁定状态
201 customerMapper.updateById(BeanUtils.toBean(lockReqVO, CrmCustomerDO.class)); 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 @Override 173 @Override
246 @Transactional(rollbackFor = Exception.class) 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 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER) 176 @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
250 public void putCustomerPool(Long id) { 177 public void putCustomerPool(Long id) {
251 // 1. 校验存在 178 // 1. 校验存在
@@ -267,16 +194,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -267,16 +194,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
267 permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(), 194 permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(),
268 CrmPermissionLevelEnum.OWNER.getLevel()); 195 CrmPermissionLevelEnum.OWNER.getLevel());
269 // TODO @puhui999:联系人的负责人,也要设置为 null;这块和领取是对应的;因为领取后,负责人也要关联过来; 196 // TODO @puhui999:联系人的负责人,也要设置为 null;这块和领取是对应的;因为领取后,负责人也要关联过来;
  197 +
  198 + // 记录操作日志上下文
  199 + LogRecordContext.putVariable("customerName", customer.getName());
270 } 200 }
271 201
272 @Override 202 @Override
273 @Transactional(rollbackFor = Exception.class) 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 // 1.1 校验存在 209 // 1.1 校验存在
281 List<CrmCustomerDO> customers = customerMapper.selectBatchIds(ids); 210 List<CrmCustomerDO> customers = customerMapper.selectBatchIds(ids);
282 if (customers.size() != ids.size()) { 211 if (customers.size() != ids.size()) {
@@ -311,6 +240,53 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -311,6 +240,53 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
311 // 2.3 创建负责人数据权限 240 // 2.3 创建负责人数据权限
312 permissionService.createPermissionBatch(createPermissions); 241 permissionService.createPermissionBatch(createPermissions);
313 // TODO @芋艿:要不要处理关联的联系人??? 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 private void validateCustomerOwnerExists(CrmCustomerDO customer, Boolean pool) { 292 private void validateCustomerOwnerExists(CrmCustomerDO customer, Boolean pool) {
@@ -327,6 +303,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -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 private void validateCustomerIsLocked(CrmCustomerDO customer, Boolean pool) { 314 private void validateCustomerIsLocked(CrmCustomerDO customer, Boolean pool) {
331 if (customer.getLockStatus()) { 315 if (customer.getLockStatus()) {
332 throw exception(pool ? CUSTOMER_LOCKED_PUT_POOL_FAIL : CUSTOMER_LOCKED, customer.getName()); 316 throw exception(pool ? CUSTOMER_LOCKED_PUT_POOL_FAIL : CUSTOMER_LOCKED, customer.getName());
@@ -339,9 +323,45 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -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,6 +91,15 @@ public interface CrmPermissionService {
91 List<CrmPermissionDO> getPermissionListByBiz(Integer bizType, Long bizId); 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 * @param bizType 模块类型 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,6 +188,11 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
188 } 188 }
189 189
190 @Override 190 @Override
  191 + public List<CrmPermissionDO> getPermissionListByBiz(Integer bizType, Collection<Long> bizIds) {
  192 + return crmPermissionMapper.selectByBizTypeAndBizIds(bizType, bizIds);
  193 + }
  194 +
  195 + @Override
191 public List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) { 196 public List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) {
192 return crmPermissionMapper.selectListByBizTypeAndUserId(bizType, userId); 197 return crmPermissionMapper.selectListByBizTypeAndUserId(bizType, userId);
193 } 198 }