mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	📖 CRM:code review 客户管理的数据权限、操作权限
This commit is contained in:
		| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| @@ -13,19 +14,12 @@ public class CrmClueTransferReqVO { | ||||
|     @NotNull(message = "线索编号不能为空") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 新负责人的用户编号 | ||||
|      */ | ||||
|     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") | ||||
|     @NotNull(message = "新负责人的用户编号不能为空") | ||||
|     private Long newOwnerUserId; | ||||
|  | ||||
|     /** | ||||
|      * 老负责人加入团队后的权限级别。如果 null 说明移除 | ||||
|      * | ||||
|      * 关联 {@link CrmPermissionLevelEnum} | ||||
|      */ | ||||
|     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private Integer oldOwnerPermissionLevel; | ||||
|     @InEnum(value = CrmPermissionLevelEnum.class) | ||||
|     private Integer oldOwnerPermissionLevel; // 老负责人加入团队后的权限级别。如果 null 说明移除 | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -135,18 +135,22 @@ public class CrmCustomerController { | ||||
|         return success(true); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:operate-log-list 或者 operate-log-page 如果分页 | ||||
|     @GetMapping("/operate-log") | ||||
|     @Operation(summary = "获得客户操作日志") | ||||
|     @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:customer:query')") | ||||
|     // TODO @puhui999:最好有读权限;方法名改成 getCustomerOperateLog | ||||
|     public CommonResult<List<OperateLogV2RespDTO>> getOperateLog(@RequestParam("id") Long id) { | ||||
|         // 1. 获取客户 | ||||
|         // TODO @puhui999:这个校验可以去掉哈; | ||||
|         CrmCustomerDO customer = customerService.getCustomer(id); | ||||
|         if (customer == null) { | ||||
|             return success(null); | ||||
|         } | ||||
|  | ||||
|         // 2. 获取操作日志 | ||||
|         // TODO @puhui999:操作日志,返回可能要分页哈; | ||||
|         return success(operateLogApi.getOperateLogByModuleAndBizId(CRM_CUSTOMER, id)); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| @@ -13,19 +14,12 @@ public class CrmReceivablePlanTransferReqVO { | ||||
|     @NotNull(message = "回款计划编号不能为空") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 新负责人的用户编号 | ||||
|      */ | ||||
|     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") | ||||
|     @NotNull(message = "新负责人的用户编号不能为空") | ||||
|     private Long newOwnerUserId; | ||||
|  | ||||
|     /** | ||||
|      * 老负责人加入团队后的权限级别。如果 null 说明移除 | ||||
|      * | ||||
|      * 关联 {@link CrmPermissionLevelEnum} | ||||
|      */ | ||||
|     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private Integer oldOwnerPermissionLevel; | ||||
|     @InEnum(value = CrmPermissionLevelEnum.class) | ||||
|     private Integer oldOwnerPermissionLevel; // 老负责人加入团队后的权限级别。如果 null 说明移除 | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||
| import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| @@ -13,19 +14,12 @@ public class CrmReceivableTransferReqVO { | ||||
|     @NotNull(message = "回款编号不能为空") | ||||
|     private Long id; | ||||
|  | ||||
|     /** | ||||
|      * 新负责人的用户编号 | ||||
|      */ | ||||
|     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") | ||||
|     @NotNull(message = "新负责人的用户编号不能为空") | ||||
|     private Long newOwnerUserId; | ||||
|  | ||||
|     /** | ||||
|      * 老负责人加入团队后的权限级别。如果 null 说明移除 | ||||
|      * | ||||
|      * 关联 {@link CrmPermissionLevelEnum} | ||||
|      */ | ||||
|     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private Integer oldOwnerPermissionLevel; | ||||
|     @InEnum(value = CrmPermissionLevelEnum.class) | ||||
|     private Integer oldOwnerPermissionLevel; // 老负责人加入团队后的权限级别。如果 null 说明移除 | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import org.springframework.stereotype.Component; | ||||
|  | ||||
| import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY; | ||||
|  | ||||
| // TODO @puhui999:包名使用 operatelog 更合适哈; | ||||
| /** | ||||
|  * 自定义函数-通过行业编号获取行业信息 | ||||
|  * | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString | ||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED; | ||||
| import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_MODEL_NOT_EXISTS; | ||||
|  | ||||
| // TODO 这个包,改成 permission,然后搞 config 和 core 包,这个类在 core 包里;目的是:framework 最好分类下 | ||||
| /** | ||||
|  * Crm 数据权限校验 AOP 切面 | ||||
|  * | ||||
|   | ||||
| @@ -137,12 +137,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     // TODO @puhui999:@LogRecord(type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS) | ||||
|     @LogRecord(success = TRANSFER_CUSTOMER_LOG_SUCCESS, type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}") | ||||
|     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER) | ||||
|     public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) { | ||||
|         // 1. 校验客户是否存在 | ||||
|         validateCustomer(reqVO.getId()); | ||||
|         // 添加 crmCustomer 到日志上下文 TODO 日志记录放在 service 里是因为已经过了权限校验查询时不用走两次校验 | ||||
|         // TODO @puhui999:customer 不用查询,从 1. 拿到哈;然后 put这个动作,可以放到 3.;这样逻辑结构就是,校验、逻辑、日志,更加清晰 | ||||
|         LogRecordContext.putVariable("crmCustomer", customerMapper.selectById(reqVO.getId())); | ||||
|         // 2.1 数据权限转移 | ||||
|         crmPermissionService.transferPermission( | ||||
|   | ||||
| @@ -138,11 +138,10 @@ public class CrmPermissionServiceImpl implements CrmPermissionService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     @Transactional(rollbackFor = Exception.class) // TODO @puhui999:这里不用加的,就一个操作哈; | ||||
|     public void deletePermission(Integer bizType, Long bizId) { | ||||
|         // 删除数据权限 | ||||
|         int deletedCol = crmPermissionMapper.deletePermission(bizType, bizId); | ||||
|         if (deletedCol == 0) { | ||||
|         int deletedCount = crmPermissionMapper.deletePermission(bizType, bizId); | ||||
|         if (deletedCount == 0) { | ||||
|             throw exception(CRM_PERMISSION_NOT_EXISTS); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -61,9 +61,9 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService { | ||||
|  | ||||
|         receivablePlanMapper.insert(receivablePlan); | ||||
|         // 创建数据权限 | ||||
|         crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()) | ||||
|                 .setBizId(receivablePlan.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); | ||||
|         // 返回 | ||||
|         crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId) | ||||
|                 .setBizType(CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType()).setBizId(receivablePlan.getId()) | ||||
|                 .setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); | ||||
|         return receivablePlan.getId(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -35,14 +35,14 @@ public class CrmQueryWrapperUtils { | ||||
|      * @param pool      公海 | ||||
|      * @return 是否 (是:需要执行查询,否:不需要查询调用方法直接返回空) | ||||
|      */ | ||||
|     // TODO @puhui999:bizId 直接传递会不会简单点 回复:还是需要 SFunction 因为分页连表时不知道 bizId 是多少 | ||||
|     // TODO @puhui999:bizId 直接传递会不会简单点 回复:还是需要 SFunction 因为分页连表时不知道 bizId 是多少;是不是把 bizId 传入就好啦? | ||||
|     public static <T extends MPJLambdaWrapper<?>, S> boolean appendPermissionCondition(T query, Integer bizType, SFunction<S, ?> bizId, | ||||
|                                                                                        Long userId, Integer sceneType, Boolean pool) { | ||||
|         // 1. 构建数据权限连表条件 | ||||
|         if (ObjUtil.notEqual(validateAdminUser(userId), Boolean.TRUE)) { // 管理员不需要数据权限 | ||||
|             query.innerJoin(CrmPermissionDO.class, on -> | ||||
|                     on.eq(CrmPermissionDO::getBizType, bizType).eq(CrmPermissionDO::getBizId, bizId) | ||||
|                             .eq(CrmPermissionDO::getUserId, userId)); | ||||
|             query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) | ||||
|                     .eq(CrmPermissionDO::getBizId, bizId) | ||||
|                     .eq(CrmPermissionDO::getUserId, userId)); | ||||
|         } | ||||
|         // 2.1 场景一:我负责的数据 | ||||
|         if (CrmSceneTypeEnum.isOwner(sceneType)) { | ||||
| @@ -50,15 +50,15 @@ public class CrmQueryWrapperUtils { | ||||
|         } | ||||
|         // 2.2 场景二:我参与的数据 | ||||
|         if (CrmSceneTypeEnum.isInvolved(sceneType)) { | ||||
|             query | ||||
|                     .ne("owner_user_id", userId) | ||||
|             query.ne("owner_user_id", userId) | ||||
|                     // TODO @puhui999:IN 是不是更合适哈; | ||||
|                     .and(q -> q.eq(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel()) | ||||
|                             .or() | ||||
|                             .eq(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.WRITE.getLevel())); | ||||
|  | ||||
|         } | ||||
|         // 2.3 场景三:下属负责的数据 | ||||
|         if (CrmSceneTypeEnum.isSubordinate(sceneType)) { | ||||
|             // TODO @puhui999:要不如果没有下属,拼一个 owner_user_id in null,不返回结果就好啦; | ||||
|             List<AdminUserRespDTO> subordinateUsers = getAdminUserApi().getUserListBySubordinate(userId); | ||||
|             if (CollUtil.isEmpty(subordinateUsers)) { | ||||
|                 return false; | ||||
| @@ -72,7 +72,6 @@ public class CrmQueryWrapperUtils { | ||||
|         } else { // 情况二:不是公海 | ||||
|             query.isNotNull("owner_user_id"); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @@ -106,6 +105,7 @@ public class CrmQueryWrapperUtils { | ||||
|      */ | ||||
|     private static boolean validateAdminUser(Long userId) { | ||||
|         // TODO 查询权限配置表用户的角色信息 | ||||
|         // TODO @puhui999:查询用户的角色;CRM_ADMIN("crm_admin", "CRM 管理员"), | ||||
|         //CrmPermissionConfig permissionConfig = crmPermissionConfigService.getPermissionConfigByUserId(userId); | ||||
|         //if (permissionConfig == null) { | ||||
|         //    return false; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV