Kaynağa Gözat

Merge branch 'feature/crm' of https://gitee.com/puhui999/ruoyi-vue-pro into feature/crm

# Conflicts:
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/dept/PostConvert.java
YunaiV 1 yıl önce
ebeveyn
işleme
8c9873c425
45 değiştirilmiş dosya ile 749 ekleme ve 490 silme
  1. 46 0
      yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerSceneEnum.java
  2. 2 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessTransferReqVO.java
  3. 2 9
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java
  4. 2 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractTransferReqVO.java
  5. 55 22
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java
  6. 7 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerPageReqVO.java
  7. 1 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerRespVO.java
  8. 2 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java
  9. 32 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.http
  10. 68 63
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java
  11. 1 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionBaseVO.java
  12. 8 9
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java
  13. 23 9
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionUpdateReqVO.java
  14. 2 5
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java
  15. 10 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java
  16. 2 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/ContractConvert.java
  17. 50 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java
  18. 20 5
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/permission/CrmPermissionConvert.java
  19. 4 18
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java
  20. 2 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmPermissionDO.java
  21. 4 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
  22. 9 17
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
  23. 17 24
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java
  24. 11 7
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/annotations/CrmPermission.java
  25. 107 68
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/aop/CrmPermissionAspect.java
  26. 20 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/config/SpelConfig.java
  27. 0 20
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/service/CrmPermissionValidateService.java
  28. 5 7
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/enums/CrmBizTypeEnum.java
  29. 0 10
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/enums/CrmPermissionLevelEnum.java
  30. 1 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
  31. 10 22
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
  32. 10 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java
  33. 4 5
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/ContractServiceImpl.java
  34. 2 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
  35. 34 11
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
  36. 51 14
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java
  37. 62 34
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java
  38. 1 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionCreateReqBO.java
  39. 0 32
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionPageReqBO.java
  40. 3 11
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java
  41. 1 17
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionUpdateReqBO.java
  42. 1 1
      yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImplTest.java
  43. 12 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApi.java
  44. 37 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/PostRespDTO.java
  45. 8 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApiImpl.java

+ 46 - 0
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerSceneEnum.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.crm.enums.customer;
+
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * CRM 客户等级
+ *
+ * @author Wanwan
+ */
+@Getter
+@AllArgsConstructor
+public enum CrmCustomerSceneEnum implements IntArrayValuable {
+
+    OWNER(1, "我负责的客户"),
+    FOLLOW(2, "我关注的客户");
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerSceneEnum::getType).toArray();
+
+    /**
+     * 场景类型
+     */
+    private final Integer type;
+    /**
+     * 场景名称
+     */
+    private final String name;
+
+    public static boolean isOwner(Integer type) {
+        return ObjUtil.equal(OWNER.getType(), type);
+    }
+
+    public static boolean isFollow(Integer type) {
+        return ObjUtil.equal(FOLLOW.getType(), type);
+    }
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 2 - 10
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/CrmBusinessTransferReqVO.java

@@ -21,19 +21,11 @@ public class CrmBusinessTransferReqVO {
     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     private Long newOwnerUserId;
 
-    // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
     /**
-     * 老负责人是否加入团队,是/否
-     */
-    @Schema(description = "老负责人是否加入团队", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
-    @NotNull(message = "老负责人是否加入团队不能为空")
-    private Boolean joinTeam;
-
-    /**
-     * 老负责人加入团队后的权限级别。如果 {@link #joinTeam} 为 false, permissionLevel 为 null
+     * 老负责人加入团队后的权限级别。如果 null 说明移除
      * 关联 {@link CrmPermissionLevelEnum}
      */
     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
-    private Integer permissionLevel;
+    private Integer oldOwnerPermissionLevel;
 
 }

+ 2 - 9
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactTransferReqVO.java

@@ -21,18 +21,11 @@ public class CrmContactTransferReqVO {
     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     private Long newOwnerUserId;
 
-    // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
     /**
-     * 老负责人是否加入团队,是/否
-     */
-    @Schema(description = "老负责人是否加入团队", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
-    @NotNull(message = "老负责人是否加入团队不能为空")
-    private Boolean joinTeam;
-    /**
-     * 老负责人加入团队后的权限级别。如果 {@link #joinTeam} 为 false, permissionLevel 为 null
+     * 老负责人加入团队后的权限级别。如果 null 说明移除
      * 关联 {@link CrmPermissionLevelEnum}
      */
     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
-    private Integer permissionLevel;
+    private Integer oldOwnerPermissionLevel;
 
 }

+ 2 - 10
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/CrmContractTransferReqVO.java

@@ -21,19 +21,11 @@ public class CrmContractTransferReqVO {
     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     private Long newOwnerUserId;
 
-    // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
     /**
-     * 老负责人是否加入团队,是/否
-     */
-    @Schema(description = "老负责人是否加入团队", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
-    @NotNull(message = "老负责人是否加入团队不能为空")
-    private Boolean joinTeam;
-
-    /**
-     * 老负责人加入团队后的权限级别。如果 {@link #joinTeam} 为 false, permissionLevel 为 null
+     * 老负责人加入团队后的权限级别。如果 null 说明移除
      * 关联 {@link CrmPermissionLevelEnum}
      */
     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
-    private Integer permissionLevel;
+    private Integer oldOwnerPermissionLevel;
 
 }

+ 55 - 22
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java

@@ -1,22 +1,21 @@
 package cn.iocoder.yudao.module.crm.controller.admin.customer;
 
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.NumberUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
 import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
+import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
-import com.google.common.collect.Lists;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -28,13 +27,16 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
@@ -51,6 +53,8 @@ public class CrmCustomerController {
     private DeptApi deptApi;
     @Resource
     private AdminUserApi adminUserApi;
+    @Resource
+    private CrmPermissionService permissionService;
 
     @PostMapping("/create")
     @Operation(summary = "创建客户")
@@ -81,22 +85,26 @@ public class CrmCustomerController {
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('crm:customer:query')")
     public CommonResult<CrmCustomerRespVO> getCustomer(@RequestParam("id") Long id) {
+        // 1. 获取客户
         CrmCustomerDO customer = customerService.getCustomer(id);
-        CrmCustomerRespVO customerRespVO = CrmCustomerConvert.INSTANCE.convert(customer);
-        if (ObjectUtil.isAllNotEmpty(customer, customer.getAreaId())) {
-            customerRespVO.setAreaName(AreaUtils.format(customer.getAreaId()));
-        }
-        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(CollUtil.removeNull(Lists.newArrayList(NumberUtil.parseLong(customerRespVO.getCreator()), customerRespVO.getOwnerUserId())));
-        customerRespVO.setCreatorName(Optional.ofNullable(userMap.get(NumberUtil.parseLong(customerRespVO.getCreator()))).map(AdminUserRespDTO::getNickname).orElse(null));
-        AdminUserRespDTO ownerUser = userMap.get(customer.getOwnerUserId());
-        if (Objects.nonNull(ownerUser)) {
-            customerRespVO.setOwnerUserName(ownerUser.getNickname());
-            DeptRespDTO dept = deptApi.getDept(ownerUser.getDeptId());
-            if (Objects.nonNull(dept)) {
-                customerRespVO.setOwnerUserDept(dept.getName());
-            }
+        if (customer == null) {
+            return success(null);
         }
-        return success(customerRespVO);
+
+        // 2. 拼接数据
+        // 2.1 获取负责人
+        List<CrmPermissionDO> ownerList = permissionService.getPermissionByBizTypeAndBizIdsAndLevel(
+                CrmBizTypeEnum.CRM_CUSTOMER.getType(), Collections.singletonList(customer.getId()),
+                CrmPermissionLevelEnum.OWNER.getLevel());
+        Map<Long, CrmPermissionDO> ownerMap = convertMap(ownerList, CrmPermissionDO::getBizId);
+        // 2.2 获取负责人详情
+        Set<Long> userIds = convertSet(ownerList, CrmPermissionDO::getUserId);
+        userIds.add(Long.parseLong(customer.getCreator())); // 加入创建者
+        List<AdminUserRespDTO> userList = adminUserApi.getUserList(userIds);
+        Map<Long, AdminUserRespDTO> userMap = convertMap(userList, AdminUserRespDTO::getId);
+        // 2.3 获取部门详情
+        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userList, AdminUserRespDTO::getDeptId));
+        return success(CrmCustomerConvert.INSTANCE.convert(customer, ownerMap, userMap, deptMap));
     }
 
     @GetMapping("/page")
@@ -113,6 +121,31 @@ public class CrmCustomerController {
         Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(
                 convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
         return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, userMap, deptMap));
+        return convertPage(customerService.getCustomerPage(pageVO, getLoginUserId()));
+    }
+
+    @GetMapping("/pool-page")
+    @Operation(summary = "获得公海客户分页")
+    @PreAuthorize("@ss.hasPermission('crm:customer:query')")
+    public CommonResult<PageResult<CrmCustomerRespVO>> getPoolCustomerPage(@Valid CrmCustomerPageReqVO pageVO) {
+        return convertPage(customerService.getCustomerPage(pageVO, CrmPermissionDO.POOL_USER_ID));
+    }
+
+    private CommonResult<PageResult<CrmCustomerRespVO>> convertPage(PageResult<CrmCustomerDO> pageResult) {
+        // 2. 拼接数据
+        Set<Long> ids = convertSet(pageResult.getList(), CrmCustomerDO::getId);
+        // 2.1 获取负责人
+        List<CrmPermissionDO> ownerList = permissionService.getPermissionByBizTypeAndBizIdsAndLevel(
+                CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, CrmPermissionLevelEnum.OWNER.getLevel());
+        Map<Long, CrmPermissionDO> ownerMap = convertMap(ownerList, CrmPermissionDO::getBizId);
+        // 2.2 获取负责人详情
+        Set<Long> userIds = convertSet(ownerList, CrmPermissionDO::getUserId);
+        userIds.addAll(convertSet(pageResult.getList(), item -> Long.parseLong(item.getCreator()))); // 加入创建者
+        List<AdminUserRespDTO> userList = adminUserApi.getUserList(userIds);
+        Map<Long, AdminUserRespDTO> userMap = convertMap(userList, AdminUserRespDTO::getId);
+        // 2.3 获取部门详情
+        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userList, AdminUserRespDTO::getDeptId));
+        return success(CrmCustomerConvert.INSTANCE.convertPage(pageResult, ownerMap, userMap, deptMap));
     }
 
     @GetMapping("/export-excel")

+ 7 - 1
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerPageReqVO.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerSceneEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -27,5 +28,10 @@ public class CrmCustomerPageReqVO extends PageParam {
     @Schema(description = "客户来源", example = "1")
     private Integer source;
 
-    // TODO @芋艿:场景;
+    /**
+     * 场景类型,关联 {@link CrmCustomerSceneEnum}
+     */
+    @Schema(description = "场景类型", example = "1")
+    private Integer sceneType;
+
 }

+ 1 - 1
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerRespVO.java

@@ -33,7 +33,7 @@ public class CrmCustomerRespVO extends CrmCustomerBaseVO {
     @Schema(description = "负责人名字", example = "25682")
     private String ownerUserName;
     @Schema(description = "负责人部门")
-    private String ownerUserDept;
+    private String ownerUserDeptName;
 
     @Schema(description = "地区名称", example = "北京市")
     private String areaName;

+ 2 - 10
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java

@@ -21,19 +21,11 @@ public class CrmCustomerTransferReqVO {
     @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     private Long newOwnerUserId;
 
-    // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
     /**
-     * 老负责人是否加入团队,是/否
-     */
-    @Schema(description = "老负责人是否加入团队", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
-    @NotNull(message = "老负责人是否加入团队不能为空")
-    private Boolean joinTeam;
-
-    /**
-     * 老负责人加入团队后的权限级别。如果 {@link #joinTeam} 为 false, permissionLevel 为 null
+     * 老负责人加入团队后的权限级别。如果 null 说明移除
      * 关联 {@link CrmPermissionLevelEnum}
      */
     @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
-    private Integer permissionLevel;
+    private Integer oldOwnerPermissionLevel;
 
 }

+ 32 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.http

@@ -0,0 +1,32 @@
+### 请求 /add
+PUT {{baseUrl}}/crm/permission/add
+Content-Type: application/json
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+
+{
+  "userId": 1,
+  "bizType": 2,
+  "bizId": 2,
+  "level": 1
+}
+
+### 请求 /update
+PUT {{baseUrl}}/crm/permission/update
+Content-Type: application/json
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+
+{
+  "userId": 1,
+  "bizType": 2,
+  "bizId": 2,
+  "level": 1,
+  "id": 1
+}
+
+### 请求 /delete
+DELETE {{baseUrl}}/crm/permission/delete?bizType=2&bizId=1&id=1
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+

+ 68 - 63
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java

@@ -8,8 +8,14 @@ import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionR
 import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO;
 import cn.iocoder.yudao.module.crm.convert.permission.CrmPermissionConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
-import cn.iocoder.yudao.module.crm.framework.core.service.CrmPermissionValidateService;
+import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.PostApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import io.swagger.v3.oas.annotations.Operation;
@@ -22,17 +28,16 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
-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;
-import static cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum.getNameByType;
-import static cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum.isOwner;
+import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_NOT_EXISTS;
 
 @Tag(name = "管理后台 - CRM 数据权限(数据团队成员操作)")
 @RestController
@@ -41,92 +46,85 @@ import static cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum
 public class CrmPermissionController {
 
     @Resource
-    private CrmPermissionService crmPermissionService;
+    private CrmPermissionService permissionService;
 
     @Resource
     private AdminUserApi adminUserApi;
     @Resource
-    private List<CrmPermissionValidateService> permissionValidateServices;
-
-    // TODO @puhui999:这个能不能使用 CrmPermission 注解替代?
-    private void validatePermission(Integer bizType, Long bizId) {
-        // 1. TODO 校验是否为超级管理员
-        // 2. 防御一手,如果是超级管理员不校验权限还是得校验一下数据是否存在
-        // TODO @puhui999:是不是不用校验每个业务方的数据是否存在;其实不是很关键哈;简单一点~ 说白了,负责人只要在,它的数据就是存在~
-        permissionValidateServices.forEach(item -> {
-            if (!item.validateBizIdExists(bizType, bizId)) {
-                throw exception(CRM_PERMISSION_MODEL_NOT_EXISTS, getNameByType(bizType));
-            }
-        });
-        // 3. 校验数据权限 (如果存在则表示 bizId 也存在)
-        CrmPermissionDO permission = crmPermissionService.getPermissionByBizTypeAndBizIdAndUserId(
-                bizType, bizId, getLoginUserId());
-        if (isOwner(permission.getPermissionLevel())) { // 只有负责人才可以操作团队成员
-            return;
-        }
-        throw exception(CRM_PERMISSION_DENIED, getNameByType(bizType));
-    }
+    private DeptApi deptApi;
+    @Resource
+    private PostApi postApi;
 
     @PutMapping("/add")
     @Operation(summary = "添加团队成员")
     @PreAuthorize("@ss.hasPermission('crm:permission:create')")
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_PERMISSION, bizTypeValue = "#reqVO.bizType", bizId = "#reqVO.bizId"
+            , level = CrmPermissionLevelEnum.OWNER)
     public CommonResult<Boolean> addPermission(@Valid @RequestBody CrmPermissionCreateReqVO reqVO) {
-        // 1. 前置校验
-        validatePermission(reqVO.getBizType(), reqVO.getBizId());
+        permissionService.createPermission(CrmPermissionConvert.INSTANCE.convert(reqVO));
+        return success(true);
+    }
 
-        // 2. 加入成员
-        crmPermissionService.createPermission(CrmPermissionConvert.INSTANCE.convert(reqVO));
+    @PutMapping("/receive")
+    @Operation(summary = "领取公海数据")
+    @PreAuthorize("@ss.hasPermission('crm:permission:update')")
+    public CommonResult<Boolean> receive(@RequestParam("bizType") Integer bizType, @RequestParam("bizId") Long bizId) {
+        permissionService.receiveBiz(bizType, bizId, getLoginUserId());
         return success(true);
     }
 
+    @PutMapping("/put-pool")
+    @Operation(summary = "数据放入公海")
+    @PreAuthorize("@ss.hasPermission('crm:permission:update')")
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_PERMISSION, bizTypeValue = "#bizType", bizId = "#bizId"
+            , level = CrmPermissionLevelEnum.OWNER)
+    public CommonResult<Boolean> putPool(@RequestParam(value = "bizType") Integer bizType, @RequestParam("bizId") Long bizId) {
+        permissionService.putPool(bizType, bizId, getLoginUserId());
+        return success(true);
+    }
 
     @PutMapping("/update")
-    @Operation(summary = "编辑团队成员")
+    @Operation(summary = "编辑团队成员权限")
     @PreAuthorize("@ss.hasPermission('crm:permission:update')")
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_PERMISSION, bizTypeValue = "#updateReqVO.bizType", bizId = "#updateReqVO.bizId"
+            , level = CrmPermissionLevelEnum.OWNER)
     public CommonResult<Boolean> updatePermission(@Valid @RequestBody CrmPermissionUpdateReqVO updateReqVO) {
-        // 1. 前置校验
-        validatePermission(updateReqVO.getBizType(), updateReqVO.getBizId());
-
-        // 2. 编辑团队成员
-        crmPermissionService.updatePermission(CrmPermissionConvert.INSTANCE.convert(updateReqVO));
+        permissionService.updatePermission(updateReqVO);
         return success(true);
     }
 
-    // TODO @puhui999:deletemapping
-    @GetMapping("/delete")
+    @DeleteMapping("/delete")
     @Operation(summary = "移除团队成员")
-    @Parameter(name = "id", description = "团队成员编号", required = true)
-    // TODO @puhui999:是不是 id 参数就够了?
+    @Parameters({
+            @Parameter(name = "bizType", description = "CRM 类型", required = true, example = "2"),
+            @Parameter(name = "bizId", description = "CRM 类型数据编号", required = true, example = "1024"),
+            @Parameter(name = "ids", description = "团队成员编号", required = true, example = "1024")
+    })
     @PreAuthorize("@ss.hasPermission('crm:permission:delete')")
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_PERMISSION, bizTypeValue = "#bizType", bizId = "#bizId"
+            , level = CrmPermissionLevelEnum.OWNER) // 为了校验权限请求必须带上 bizType 和  bizId
     public CommonResult<Boolean> deletePermission(@RequestParam("bizType") Integer bizType,
                                                   @RequestParam("bizId") Long bizId,
-                                                  @RequestParam("id") Long id) {
-        // 1. 前置校验
-        validatePermission(bizType, bizId);
-
-        // 2. 移除团队成员
-        crmPermissionService.deletePermission(id);
+                                                  @RequestParam("ids") Collection<Long> ids) {
+        permissionService.deletePermission(ids);
         return success(true);
     }
 
-    // TODO @puhui999:这个是哪个地方使用到哈?
-    // TODO @puhui999:是不是 deletemapping 呀;
-    @GetMapping("/quit")
+    @DeleteMapping("/quit-team")
     @Operation(summary = "退出团队")
     @Parameters({
-            @Parameter(name = "bizType", description = "CRM 类型", required = true, example = "2"),
-            @Parameter(name = "bizId", description = "CRM 类型数据编号", required = true, example = "1024")
+            @Parameter(name = "id", description = "团队成员编号", required = true, example = "1024")
     })
     @PreAuthorize("@ss.hasPermission('crm:permission:delete')")
-    public CommonResult<Boolean> quitPermission(@RequestParam("bizType") Integer bizType,
-                                                @RequestParam("bizId") Long bizId) {
-        // 没有就不是团队成员
-        CrmPermissionDO permission = crmPermissionService.getPermissionByBizTypeAndBizIdAndUserId(
-                bizType, bizId, getLoginUserId());
+    public CommonResult<Boolean> deletePermission(@RequestParam("id") Long id) {
+        // 校验数据存在且是自己
+        CrmPermissionDO permission = permissionService.getPermissionByIdAndUserId(id, getLoginUserId());
         if (permission == null) {
-            return success(false);
+            throw exception(CRM_PERMISSION_NOT_EXISTS);
         }
-        crmPermissionService.deletePermission(permission.getId());
+
+        // 删除
+        permissionService.deletePermission(Collections.singletonList(id));
         return success(true);
     }
 
@@ -139,16 +137,23 @@ public class CrmPermissionController {
     @PreAuthorize("@ss.hasPermission('crm:permission:query')")
     public CommonResult<List<CrmPermissionRespVO>> getPermissionList(@RequestParam("bizType") Integer bizType,
                                                                      @RequestParam("bizId") Long bizId) {
-        List<CrmPermissionDO> permission = crmPermissionService.getPermissionByBizTypeAndBizId(bizType, bizId);
+        List<CrmPermissionDO> permission = permissionService.getPermissionByBizTypeAndBizId(bizType, bizId);
         if (CollUtil.isEmpty(permission)) {
             return success(Collections.emptyList());
         }
         // TODO @puhui999:池子的逻辑;
-        permission.removeIf(item -> ObjUtil.equal(item.getUserId(), CrmPermissionDO.POOL_USER_ID)); // 排除
+        // 判断是否是公海数据
+        Predicate<CrmPermissionDO> filter = item -> ObjUtil.equal(item.getUserId(), CrmPermissionDO.POOL_USER_ID);
+        if (anyMatch(permission, filter)) {
+            permission.removeIf(filter); // 排除
+        }
 
         // 拼接数据
         List<AdminUserRespDTO> userList = adminUserApi.getUserList(convertSet(permission, CrmPermissionDO::getUserId));
-        return success(CrmPermissionConvert.INSTANCE.convert(permission, userList));
+        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userList, AdminUserRespDTO::getDeptId));
+        Set<Long> postIds = userList.stream().flatMap(item -> item.getPostIds().stream()).collect(Collectors.toSet());
+        Map<Long, PostRespDTO> postMap = postApi.getPostMap(postIds);
+        return success(CrmPermissionConvert.INSTANCE.convert(permission, userList, deptMap, postMap));
     }
 
 }

+ 1 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionBaseVO.java

@@ -30,10 +30,9 @@ public class CrmPermissionBaseVO {
     @NotNull(message = "Crm 类型数据编号不能为空")
     private Long bizId;
 
-    // TODO @puhui999:level;
     @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
     @InEnum(CrmPermissionLevelEnum.class)
     @NotNull(message = "权限级别不能为空")
-    private Integer permissionLevel;
+    private Integer level;
 
 }

+ 8 - 9
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionRespVO.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.permission.vo;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import java.time.LocalDateTime;
 import java.util.Set;
 
 @Schema(description = "管理后台 - CRM 数据权限(团队成员) Response VO")
@@ -12,18 +13,16 @@ public class CrmPermissionRespVO extends CrmPermissionBaseVO {
     @Schema(description = "数据权限编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
     private Long id;
 
-    // TODO @puhui999:搞到字典里;
-    @Schema(description = "团队级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "负责人")
-    private String permissionLevelName;
-
-    // TODO @puhui999:deptId、postIds 是不是要提供中文名哈;
-    @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    private Long deptId;
+    @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部")
+    private String deptName;
 
     @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
     private String nickname;
 
-    @Schema(description = "岗位编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3]")
-    private Set<Long> postIds;
+    @Schema(description = "岗位名称数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[BOOS,经理]")
+    private Set<String> postNames;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2023-01-01 00:00:00")
+    private LocalDateTime createTime;
 
 }

+ 23 - 9
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionUpdateReqVO.java

@@ -1,20 +1,34 @@
 package cn.iocoder.yudao.module.crm.controller.admin.permission.vo;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
 
 @Schema(description = "管理后台 - CRM 数据权限更新 Request VO")
 @Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class CrmPermissionUpdateReqVO extends CrmPermissionBaseVO {
+public class CrmPermissionUpdateReqVO {
+
+    @Schema(description = "数据权限编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2]")
+    @NotNull(message = "数据权限编号列表不能为空")
+    private List<Long> ids;
+
+    @Schema(description = "Crm 类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @InEnum(CrmBizTypeEnum.class)
+    @NotNull(message = "Crm 类型不能为空")
+    private Integer bizType;
 
-    @Schema(description = "数据权限编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
-    // TODO @puhui999:非空判断;
-    private Long id;
+    @Schema(description = "Crm 类型数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "Crm 类型数据编号不能为空")
+    private Long bizId;
 
-    // TODO @puhui999:是不是只更新 permission???
+    @Schema(description = "权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @InEnum(CrmPermissionLevelEnum.class)
+    @NotNull(message = "权限级别不能为空")
+    private Integer level;
 
 }

+ 2 - 5
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java

@@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.crm.convert.business;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.*;
 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionPageReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmTransferPermissionReqBO;
+import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
@@ -36,8 +35,6 @@ public interface CrmBusinessConvert {
             @Mapping(target = "bizId", source = "reqVO.id"),
             @Mapping(target = "newOwnerUserId", source = "reqVO.id")
     })
-    CrmTransferPermissionReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId);
-
-    CrmPermissionPageReqBO convert(CrmBusinessPageReqVO pageReqVO);
+    CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId);
 
 }

+ 10 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/ContactConvert.java

@@ -4,6 +4,9 @@ import java.util.*;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 
+import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*;
+import cn.iocoder.yudao.module.crm.dal.dataobject.contact.ContactDO;
+import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*;
@@ -30,6 +33,13 @@ public interface ContactConvert {
     PageResult<ContactRespVO> convertPage(PageResult<ContactDO> page);
 
     List<ContactExcelVO> convertList02(List<ContactDO> list);
+
     List<ContactSimpleRespVO> convertAllList(List<ContactDO> list);
 
+    @Mappings({
+            @Mapping(target = "bizId", source = "reqVO.id"),
+            @Mapping(target = "newOwnerUserId", source = "reqVO.id")
+    })
+    CrmPermissionTransferReqBO convert(CrmContactTransferReqVO reqVO, Long userId);
+
 }

+ 2 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/ContractConvert.java

@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.crm.convert.contract;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.*;
 import cn.iocoder.yudao.module.crm.dal.dataobject.contract.ContractDO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmTransferPermissionReqBO;
+import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
@@ -37,6 +37,6 @@ public interface ContractConvert {
             @Mapping(target = "bizId", source = "reqVO.id"),
             @Mapping(target = "newOwnerUserId", source = "reqVO.id")
     })
-    CrmTransferPermissionReqBO convert(CrmContractTransferReqVO reqVO, Long userId);
+    CrmPermissionTransferReqBO convert(CrmContractTransferReqVO reqVO, Long userId);
 
 }

+ 50 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java

@@ -4,12 +4,17 @@ import cn.hutool.core.util.NumberUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
+import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmTransferPermissionReqBO;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
+import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
@@ -18,6 +23,9 @@ import org.mapstruct.factory.Mappers;
 import java.util.List;
 import java.util.Map;
 
+import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
+import java.util.Map;
+
 /**
  * 客户 Convert
  *
@@ -34,7 +42,24 @@ public interface CrmCustomerConvert {
 
     CrmCustomerRespVO convert(CrmCustomerDO bean);
 
-    PageResult<CrmCustomerRespVO> convertPage(PageResult<CrmCustomerDO> page);
+    default CrmCustomerRespVO convert(CrmCustomerDO customer, Map<Long, CrmPermissionDO> ownerMap,
+                                      Map<Long, AdminUserRespDTO> userMap, Map<Long, DeptRespDTO> deptMap) {
+        CrmCustomerRespVO customerResp = convert(customer);
+        findAndThen(ownerMap, customerResp.getId(), owner -> {
+            customerResp.setOwnerUserId(owner.getUserId());
+            customerResp.setAreaName(AreaUtils.format(customerResp.getAreaId()));
+            findAndThen(userMap, owner.getUserId(), user -> {
+                customerResp.setOwnerUserName(user.getNickname());
+            });
+            findAndThen(userMap, Long.parseLong(customerResp.getCreator()), user -> {
+                customerResp.setCreatorName(user.getNickname());
+            });
+            findAndThen(deptMap, customerResp.getOwnerUserId(), dept -> {
+                customerResp.setOwnerUserDeptName(dept.getName());
+            });
+        });
+        return customerResp;
+    }
 
     default PageResult<CrmCustomerRespVO> convertPage(PageResult<CrmCustomerDO> page, Map<Long, AdminUserRespDTO> userMap, Map<Long, DeptRespDTO> deptMap) {
         PageResult<CrmCustomerRespVO> result = convertPage(page);
@@ -57,7 +82,30 @@ public interface CrmCustomerConvert {
             @Mapping(target = "bizId", source = "reqVO.id"),
             @Mapping(target = "newOwnerUserId", source = "reqVO.id")
     })
-    CrmTransferPermissionReqBO convert(CrmCustomerTransferReqVO reqVO, Long userId);
+    CrmPermissionTransferReqBO convert(CrmCustomerTransferReqVO reqVO, Long userId);
+
+    PageResult<CrmCustomerRespVO> convertPage(PageResult<CrmCustomerDO> page);
+
+    default PageResult<CrmCustomerRespVO> convertPage(PageResult<CrmCustomerDO> pageResult, Map<Long, CrmPermissionDO> ownerMap,
+                                                      Map<Long, AdminUserRespDTO> userMap, Map<Long, DeptRespDTO> deptMap) {
+        PageResult<CrmCustomerRespVO> result = convertPage(pageResult);
+        result.getList().forEach(item -> {
+            findAndThen(ownerMap, item.getId(), owner -> {
+                item.setOwnerUserId(owner.getUserId());
+                item.setAreaName(AreaUtils.format(item.getAreaId()));
+                findAndThen(userMap, owner.getUserId(), user -> {
+                    item.setOwnerUserName(user.getNickname());
+                });
+                findAndThen(userMap, Long.parseLong(item.getCreator()), user -> {
+                    item.setCreatorName(user.getNickname());
+                });
+                findAndThen(deptMap, item.getOwnerUserId(), dept -> {
+                    item.setOwnerUserDeptName(dept.getName());
+                });
+            });
+        });
+        return result;
+    }
 
     CrmCustomerPoolConfigRespVO convert(CrmCustomerPoolConfigDO customerPoolConfig);
 

+ 20 - 5
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/permission/CrmPermissionConvert.java

@@ -8,15 +8,17 @@ import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionU
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionUpdateReqBO;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import com.google.common.collect.Multimaps;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import static cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum.getNameByLevel;
-
 /**
  * Crm 数据权限 Convert
  *
@@ -37,15 +39,28 @@ public interface CrmPermissionConvert {
 
     List<CrmPermissionRespVO> convert(List<CrmPermissionDO> permission);
 
-    default List<CrmPermissionRespVO> convert(List<CrmPermissionDO> permission, List<AdminUserRespDTO> userList) {
+    default List<CrmPermissionRespVO> convert(List<CrmPermissionDO> permission, List<AdminUserRespDTO> userList,
+                                              Map<Long, DeptRespDTO> deptMap, Map<Long, PostRespDTO> postMap) {
         Map<Long, AdminUserRespDTO> userMap = CollectionUtils.convertMap(userList, AdminUserRespDTO::getId);
         return CollectionUtils.convertList(convert(permission), item -> {
             MapUtils.findAndThen(userMap, item.getId(), user -> {
-                item.setNickname(user.getNickname()).setDeptId(user.getDeptId()).setPostIds(user.getPostIds())
-                        .setPermissionLevelName(getNameByLevel(item.getPermissionLevel()));
+                item.setNickname(user.getNickname());
+                MapUtils.findAndThen(deptMap, user.getDeptId(), deptRespDTO -> {
+                    item.setDeptName(deptRespDTO.getName());
+                });
+                List<PostRespDTO> postRespList = MapUtils.getList(Multimaps.forMap(postMap), user.getPostIds());
+                item.setPostNames(CollectionUtils.convertSet(postRespList, PostRespDTO::getName));
             });
             return item;
         });
     }
 
+    default List<CrmPermissionDO> convertList(CrmPermissionUpdateReqVO updateReqVO) {
+        List<CrmPermissionDO> permissions = new ArrayList<>();
+        updateReqVO.getIds().forEach(id -> {
+            permissions.add(new CrmPermissionDO().setId(id).setLevel(updateReqVO.getLevel()));
+        });
+        return permissions;
+    }
+
 }

+ 4 - 18
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.crm.dal.dataobject.customer;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -49,19 +50,19 @@ public class CrmCustomerDO extends BaseDO {
     /**
      * 所属行业
      *
-     * 对应字典 {@link cn.iocoder.yudao.module.crm.enums.DictTypeConstants#CRM_CUSTOMER_INDUSTRY}
+     * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_INDUSTRY}
      */
     private Integer industryId;
     /**
      * 客户等级
      *
-     * 对应字典 {@link cn.iocoder.yudao.module.crm.enums.DictTypeConstants#CRM_CUSTOMER_LEVEL}
+     * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_LEVEL}
      */
     private Integer level;
     /**
      * 客户来源
      *
-     * 对应字典 {@link cn.iocoder.yudao.module.crm.enums.DictTypeConstants#CRM_CUSTOMER_SOURCE}
+     * 对应字典 {@link DictTypeConstants#CRM_CUSTOMER_SOURCE}
      */
     private Integer source;
     /**
@@ -96,21 +97,6 @@ public class CrmCustomerDO extends BaseDO {
      * 备注
      */
     private String remark;
-    /**
-     * 负责人的用户编号
-     *
-     * 关联 AdminUserDO 的 id 字段
-     */
-    private Long ownerUserId;
-    // TODO @puhui999:这块抽到 permission 里;
-    /**
-     * 只读权限的用户编号数组
-     */
-    private String roUserIds;
-    /**
-     * 读写权限的用户编号数组
-     */
-    private String rwUserIds;
     /**
      * 地区编号
      */

+ 2 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmPermissionDO.java

@@ -23,7 +23,7 @@ import lombok.*;
 @AllArgsConstructor
 public class CrmPermissionDO extends BaseDO {
 
-    // TODO puhui999:是不是公海的数据,就不插入了;
+    // TODO puhui999:是不是公海的数据,就不插入了;这样方便获取公海数据鸭
     /**
      * 当数据变为公海数据时,也就是数据团队成员中没有负责人的时候,将原本的负责人 userId 设置为 POOL_USER_ID 方便查询公海数据。
      * 也就是说每条数据到最后都有一个负责人,如果有人领取则 userId 为领取人
@@ -59,12 +59,11 @@ public class CrmPermissionDO extends BaseDO {
      */
     private Long userId;
 
-    // TODO @puhui999:是不是搞成 level 字段;简洁一点,主要表明已经 perssmion 实体里了;
     /**
      * 权限级别
      *
      * 关联 {@link CrmPermissionLevelEnum}
      */
-    private Integer permissionLevel;
+    private Integer level;
 
 }

+ 4 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.crm.dal.mysql.business;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.CrmBusinessExportReqVO;
@@ -18,14 +19,14 @@ import java.util.List;
 @Mapper
 public interface CrmBusinessMapper extends BaseMapperX<CrmBusinessDO> {
 
-    default List<CrmBusinessDO> selectList(CrmBusinessPageReqVO reqVO, Collection<Long> ids) {
-        return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
+    default PageResult<CrmBusinessDO> selectPage(CrmBusinessPageReqVO reqVO, Collection<Long> ids) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<CrmBusinessDO>()
                 .in(CrmBusinessDO::getId, ids)
                 .likeIfPresent(CrmBusinessDO::getName, reqVO.getName())
                 .orderByDesc(CrmBusinessDO::getId));
     }
 
-    default List<CrmBusinessDO> selectList(CrmBusinessExportReqVO reqVO) {
+    default List<CrmBusinessDO> selectPage(CrmBusinessExportReqVO reqVO) {
         return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
                 .likeIfPresent(CrmBusinessDO::getName, reqVO.getName())
                 .eqIfPresent(CrmBusinessDO::getStatusTypeId, reqVO.getStatusTypeId())

+ 9 - 17
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java

@@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.crm.dal.mysql.customer;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerExportReqVO;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 import org.apache.ibatis.annotations.Mapper;
 
-import java.util.List;
+import java.util.Collection;
 
 /**
  * 客户 Mapper
@@ -18,21 +17,14 @@ import java.util.List;
 @Mapper
 public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
 
-    default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<CrmCustomerDO>()
-                .likeIfPresent(CrmCustomerDO::getName, reqVO.getName())
-                .eqIfPresent(CrmCustomerDO::getMobile, reqVO.getMobile())
-                .eqIfPresent(CrmCustomerDO::getIndustryId, reqVO.getIndustryId())
-                .eqIfPresent(CrmCustomerDO::getLevel, reqVO.getLevel())
-                .eqIfPresent(CrmCustomerDO::getSource, reqVO.getSource())
-                .orderByDesc(CrmCustomerDO::getId));
-    }
-
-    default List<CrmCustomerDO> selectList(CrmCustomerExportReqVO reqVO) {
-        return selectList(new LambdaQueryWrapperX<CrmCustomerDO>()
-                .likeIfPresent(CrmCustomerDO::getName, reqVO.getName())
-                .eqIfPresent(CrmCustomerDO::getMobile, reqVO.getMobile())
-                .orderByDesc(CrmCustomerDO::getId));
+    default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Collection<Long> ids) {
+        return selectPage(pageReqVO, new LambdaQueryWrapperX<CrmCustomerDO>()
+                .inIfPresent(CrmCustomerDO::getId, ids)
+                .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())
+                .eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile())
+                .eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId())
+                .eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel())
+                .eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource()));
     }
 
 }

+ 17 - 24
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmPermissionMapper.java

@@ -1,13 +1,11 @@
 package cn.iocoder.yudao.module.crm.dal.mysql.permission;
 
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
-import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionPageReqBO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -18,15 +16,6 @@ import java.util.List;
 @Mapper
 public interface CrmPermissionMapper extends BaseMapperX<CrmPermissionDO> {
 
-    // TODO @puhui999:是不是不用谢这个注释;因为方法名,可以自解释;
-    /**
-     * 获取用户数据权限通过 数据类型 x 某个数据 x 用户编号
-     *
-     * @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
-     * @param bizId   数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
-     * @param userId  用户编号,AdminUser#id
-     * @return Crm 数据权限
-     */
     default CrmPermissionDO selectByBizTypeAndBizIdByUserId(Integer bizType, Long bizId, Long userId) {
         return selectOne(new LambdaQueryWrapperX<CrmPermissionDO>()
                 .eq(CrmPermissionDO::getBizType, bizType)
@@ -34,24 +23,28 @@ public interface CrmPermissionMapper extends BaseMapperX<CrmPermissionDO> {
                 .eq(CrmPermissionDO::getUserId, userId));
     }
 
-    // TODO @puhui999:是不是不用谢这个注释;因为方法名,可以自解释;
-    /**
-     * 获取数据权限列表通过 数据类型 x 某个数据
-     *
-     * @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
-     * @param bizId   数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
-     * @return Crm 数据权限列表
-     */
     default List<CrmPermissionDO> selectByBizTypeAndBizId(Integer bizType, Long bizId) {
         return selectList(new LambdaQueryWrapperX<CrmPermissionDO>()
                 .eq(CrmPermissionDO::getBizType, bizType)
                 .eq(CrmPermissionDO::getBizId, bizId));
     }
 
-    default PageResult<CrmPermissionDO> selectPage(CrmPermissionPageReqBO pageReqBO) {
-        return selectPage(pageReqBO, new LambdaQueryWrapperX<CrmPermissionDO>()
-                .eq(CrmPermissionDO::getBizType, pageReqBO.getBizType())
-                .eq(CrmPermissionDO::getUserId, pageReqBO.getUserId())); // 只要是团队成员都有读取的权限
+    default List<CrmPermissionDO> selectListByBizTypeAndUserId(Integer bizType, Long userId) {
+        return selectList(new LambdaQueryWrapperX<CrmPermissionDO>()
+                .eq(CrmPermissionDO::getBizType, bizType)
+                .eq(CrmPermissionDO::getUserId, userId));
+    }
+
+    default List<CrmPermissionDO> selectListByBizTypeAndBizIdsAndLevel(Integer bizType, Collection<Long> bizIds, Integer level) {
+        return selectList(new LambdaQueryWrapperX<CrmPermissionDO>()
+                .eq(CrmPermissionDO::getBizType, bizType)
+                .in(CrmPermissionDO::getBizId, bizIds)
+                .eq(CrmPermissionDO::getLevel, level));
+    }
+
+    default CrmPermissionDO selectByIdAndUserId(Long id, Long userId) {
+        return selectOne(new LambdaQueryWrapperX<CrmPermissionDO>()
+                .eq(CrmPermissionDO::getId, id).eq(CrmPermissionDO::getUserId, userId));
     }
 
 }

+ 11 - 7
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/annotations/CrmPermission.java

@@ -26,17 +26,21 @@ public @interface CrmPermission {
      */
     CrmBizTypeEnum bizType();
 
-    // TODO @puhui999:id,通过 spring el 表达式获取;
     /**
-     * 数据编号获取来源类,确保数据 id 编号在此类中,不能在父类中。
-     * 例:如果在 baseVO 中需要把 id 弄到 updateVO 中。
+     * crm 类型扩展
+     * 用于 CrmPermissionController 团队权限校验
      */
-    Class<?>[] getIdFor() default {};
+    String bizTypeValue() default "";
 
-    // TODO @puhui999:是不是搞成 level 字段;简洁一点,主要表明已经 perssmion 实体里了;
     /**
-     * 操作类型
+     * 数据编号,通过 spring el 表达式获取
+     * TODO 数据权限完成后去除 default ""
      */
-    CrmPermissionLevelEnum permissionLevel();
+    String bizId() default "";
+
+    /**
+     * 操作所需权限级别
+     */
+    CrmPermissionLevelEnum level();
 
 }

+ 107 - 68
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/aop/CrmPermissionAspect.java

@@ -2,24 +2,32 @@ package cn.iocoder.yudao.module.crm.framework.core.aop;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.core.KeyValue;
 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
 import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
+import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
-import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 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.framework.enums.CrmPermissionLevelEnum.*;
 
 /**
  * Crm 数据权限校验 AOP 切面
@@ -31,6 +39,11 @@ import static cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum
 @Slf4j
 public class CrmPermissionAspect {
 
+    @Resource
+    private LocalVariableTableParameterNameDiscoverer discoverer;
+    @Resource
+    private SpelExpressionParser parser;
+
     @Resource
     private CrmPermissionService crmPermissionService;
 
@@ -43,83 +56,109 @@ public class CrmPermissionAspect {
         return WebFrameworkUtils.getLoginUserId();
     }
 
-    // TODO @puhui999:id,通过 spring el 表达式获取;
-    private Long getBizId(JoinPoint joinPoint, CrmPermission crmPermission) throws NoSuchFieldException, IllegalAccessException {
-        Object[] args = joinPoint.getArgs();
-        for (Object arg : args) {
-            if (arg == null) {
-                continue;
-            }
-            if (ObjUtil.notEqual(arg.getClass().getName(), crmPermission.getIdFor()[0].getName())) {
-                continue;
-            }
-            // 使用反射获取id属性
-            Field idValue = arg.getClass().getDeclaredField("id");
-            // 设置字段为可访问
-            idValue.setAccessible(true);
-            return (Long) idValue.get(arg);
-        }
-        return null;
-    }
-
-    // TODO @puhui999:一般核心的方法,放到最前面,private 放后面。主要是,主次要分出来哈;
     @Before("@annotation(crmPermission)")
-    public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) {
+    public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) throws NoSuchMethodException {
         // TODO 芋艿:临时,方便大家调试
         if (true) {
             return;
         }
-        try {
-            Long bizId = crmPermission.getIdFor().length > 0 ? getBizId(joinPoint, crmPermission) : (Long) joinPoint.getArgs()[0]; // 获取操作数据的编号
-            Integer bizType = crmPermission.bizType().getType(); // 模块类型
-            Integer permissionLevel = crmPermission.permissionLevel().getLevel(); // 需要的权限级别
-
-            // TODO 如果是超级管理员则直接通过
-            //if (superAdmin){
-            //    return;
-            //}
-
-            // 1. 获取数据权限
-            List<CrmPermissionDO> bizPermissions = crmPermissionService.getPermissionByBizTypeAndBizId(bizType, bizId);
-            // TODO puhui999:这种情况下,最好是 CrmPermissionLevelEnum.isOwner
-            // 2.1 情况一:如果自己是负责人,则默认有所有权限
-            // TODO @puhui999:会不会存在空指针的问题?
-            CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, item -> ObjUtil.equal(item.getUserId(), getUserId()));
-            if (isOwner(userPermission.getPermissionLevel())) {
+        KeyValue<Long, Integer> bizIdAndBizType = getBizIdAndBizType(joinPoint, crmPermission);
+        Integer bizType = bizIdAndBizType.getValue(); // 模块类型
+        Long bizId = bizIdAndBizType.getKey(); // 模块数据编号
+        Integer permissionLevel = crmPermission.level().getLevel(); // 需要的权限级别
+
+        // TODO 如果是超级管理员则直接通过
+        //if (superAdmin){
+        //    return;
+        //}
+
+        // 1. 获取数据权限
+        List<CrmPermissionDO> bizPermissions = crmPermissionService.getPermissionByBizTypeAndBizId(bizType, bizId);
+        // 2.1 情况一:如果自己是负责人,则默认有所有权限
+        // TODO @puhui999:会不会存在空指针的问题?
+        CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, item -> ObjUtil.equal(item.getUserId(), getUserId()));
+        if (CrmPermissionLevelEnum.isOwner(userPermission.getLevel())) {
+            return;
+        }
+        // 2.2 情况二:校验自己是否有读权限
+        if (CrmPermissionLevelEnum.isRead(permissionLevel)) {
+            // 如果没有数据权限或没有负责人则表示此记录为公海数据所有人都有只读权限可以领取成为负责人(团队成员领取的)
+            // TODO @puhui999:89 到 92 这块的逻辑,感觉可以不用 @CrmPermission,公海那自己 check 即可;
+            if (CollUtil.isEmpty(bizPermissions) || CollUtil.anyMatch(bizPermissions,
+                    item -> ObjUtil.equal(item.getUserId(), CrmPermissionDO.POOL_USER_ID))) { // 详见 CrmPermissionDO.POOL_USER_ID 注释
                 return;
             }
-            // 2.2 情况二:校验自己是否有读权限
-            if (isRead(permissionLevel)) {
-                // 如果没有数据权限或没有负责人则表示此记录为公海数据所有人都有只读权限可以领取成为负责人(团队成员领取的)
-                // TODO @puhui999:89 到 92 这块的逻辑,感觉可以不用 @CrmPermission,公海那自己 check 即可;
-                if (CollUtil.isEmpty(bizPermissions) || CollUtil.anyMatch(bizPermissions,
-                        item -> ObjUtil.equal(item.getUserId(), CrmPermissionDO.POOL_USER_ID))) { // 详见 CrmPermissionDO.POOL_USER_ID 注释
-                    return;
-                }
-                if (isRead(userPermission.getPermissionLevel())) { // 校验当前用户是否有读权限
-                    return;
-                }
-                // 如果查询数据的话拥有写权限的也能查询
-                if (isWrite(userPermission.getPermissionLevel())) { // 校验当前用户是否有写权限
-                    return;
-                }
+            if (CrmPermissionLevelEnum.isRead(userPermission.getLevel())) { // 校验当前用户是否有读权限
+                return;
             }
-            // 2.3 情况三:校验自己是否有写权限
-            if (isWrite(permissionLevel)) {
-                if (isWrite(userPermission.getPermissionLevel())) { // 校验当前用户是否有写权限
-                    return;
-                }
+            // 如果查询数据的话拥有写权限的也能查询
+            if (CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限
+                return;
+            }
+        }
+        // 2.3 情况三:校验自己是否有写权限
+        if (CrmPermissionLevelEnum.isWrite(permissionLevel)) {
+            if (CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限
+                return;
             }
+        }
+
+        // 打个 info 日志,方便后续排查问题、审计;
+        log.info("[doBefore][crmPermission({}) 数据校验错误]", toJsonString(userPermission));
+        throw exception(CRM_PERMISSION_DENIED, crmPermission.bizType().getName());
+    }
+
+    private KeyValue<Long, Integer> getBizIdAndBizType(JoinPoint joinPoint, CrmPermission crmPermission) throws NoSuchMethodException {
+        Method method = getMethod(joinPoint);
+        // 1. 获取方法的参数值
+        Object[] args = joinPoint.getArgs();
+        EvaluationContext context = bindParam(method, args);
 
-            // 3. 没通过结束,报错 {} 操作失败,原因:没有权限
-            // TODO @puhui999:这里打个 info 日志,方便后续排查问题、审计;
-            throw exception(CRM_PERMISSION_DENIED, crmPermission.bizType().getName());
-        } catch (Exception ex) {
-            // TODO @puhui999:不用 catch 掉,就是系统异常;
-            log.error("[doBefore][crmPermission({}) 数据校验错误]", toJsonString(crmPermission), ex);
-            // TODO 报错抛个什么异常好呢
-            throw exception(CRM_PERMISSION_DENIED, crmPermission.bizType().getName());
+        // 2. 根据spel表达式获取值
+        KeyValue<Long, Integer> keyValue = new KeyValue<>();
+        // 2.1 获取模块数据编号
+        Expression expression = parser.parseExpression(crmPermission.bizId());
+        keyValue.setKey(expression.getValue(context, Long.class));
+        // 2.2 获取模块类型
+        if (ObjUtil.equal(crmPermission.bizType().getType(), CrmBizTypeEnum.CRM_PERMISSION.getType())) {
+            // 情况一:用于 CrmPermissionController 中数据权限校验
+            Expression expression2 = parser.parseExpression(crmPermission.bizTypeValue());
+            keyValue.setValue(expression2.getValue(context, Integer.class));
+            return keyValue;
+        }
+        // 情况二:正常数据权限校验
+        keyValue.setValue(crmPermission.bizType().getType());
+        return keyValue;
+    }
+
+    /**
+     * 获取当前执行的方法
+     */
+    private Method getMethod(JoinPoint joinPoint) throws NoSuchMethodException {
+        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
+        Method method = methodSignature.getMethod();
+        return joinPoint.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());
+    }
+
+    /**
+     * 将方法的参数名和参数值绑定
+     *
+     * @param method 方法,根据方法获取参数名
+     * @param args   方法的参数值
+     * @return 求值上下文
+     */
+    private EvaluationContext bindParam(Method method, Object[] args) {
+        //获取方法的参数名
+        String[] params = discoverer.getParameterNames(method);
+
+        //将参数名与参数值对应起来
+        EvaluationContext context = new StandardEvaluationContext();
+        if (params != null) {
+            for (int len = 0; len < params.length; len++) {
+                context.setVariable(params[len], args[len]);
+            }
         }
+        return context;
     }
 
 }

+ 20 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/config/SpelConfig.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.crm.framework.core.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+
+/**
+ * 注册 Spel 所需 Bean
+ *
+ * @author HUIHUI
+ */
+@Configuration
+public class SpelConfig {
+
+    @Bean
+    public SpelExpressionParser spelExpressionParser() {
+        return new SpelExpressionParser();
+    }
+
+}

+ 0 - 20
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/core/service/CrmPermissionValidateService.java

@@ -1,20 +0,0 @@
-package cn.iocoder.yudao.module.crm.framework.core.service;
-
-/**
- * 校验数据是否存在 service 接口
- * TODO 需要使用团队成员相关操作的业务接口都需要继承此接口
- *
- * @author HUIHUI
- */
-public interface CrmPermissionValidateService {
-
-    /**
-     * 校验数据是否存在
-     *
-     * @param bizType CRM 类型
-     * @param bizId   数据编号
-     * @return 是/否
-     */
-    boolean validateBizIdExists(Integer bizType, Long bizId);
-
-}

+ 5 - 7
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/enums/CrmBizTypeEnum.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.crm.framework.enums;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
 import lombok.Getter;
@@ -16,6 +17,7 @@ import java.util.Arrays;
 @Getter
 public enum CrmBizTypeEnum implements IntArrayValuable {
 
+    CRM_PERMISSION(0, "团队"), // CrmPermissionController 中使用
     CRM_LEADS(1, "线索"),
     CRM_CUSTOMER(2, "客户"),
     CRM_CONTACTS(3, "联系人"),
@@ -33,13 +35,9 @@ public enum CrmBizTypeEnum implements IntArrayValuable {
     private final String name;
 
     public static String getNameByType(Integer type) {
-        // TODO @puhui999:可以 findone,更简洁;另外,不存在返回 null 即可啦;
-        for (CrmBizTypeEnum crmBizTypeEnum : CrmBizTypeEnum.values()) {
-            if (ObjUtil.equal(crmBizTypeEnum.type, type)) {
-                return crmBizTypeEnum.name;
-            }
-        }
-        return "";
+        CrmBizTypeEnum typeEnum = CollUtil.findOne(CollUtil.newArrayList(CrmBizTypeEnum.values()),
+                item -> ObjUtil.equal(item.type, type));
+        return typeEnum == null ? null : typeEnum.getName();
     }
 
     @Override

+ 0 - 10
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/enums/CrmPermissionLevelEnum.java

@@ -48,14 +48,4 @@ public enum CrmPermissionLevelEnum implements IntArrayValuable {
         return ObjUtil.equal(WRITE.level, level);
     }
 
-    public static String getNameByLevel(Integer level) {
-        // TODO @puhui999:可以 findone,更简洁;另外,不存在返回 null 即可啦;
-        for (CrmPermissionLevelEnum levelEnum : CrmPermissionLevelEnum.values()) {
-            if (ObjUtil.equal(levelEnum.level, level)) {
-                return levelEnum.name;
-            }
-        }
-        return "";
-    }
-
 }

+ 1 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.crm.service.business;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.*;
 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
-import cn.iocoder.yudao.module.crm.framework.core.service.CrmPermissionValidateService;
 
 import javax.validation.Valid;
 import java.util.Collection;
@@ -14,7 +13,7 @@ import java.util.List;
  *
  * @author ljlleo
  */
-public interface CrmBusinessService extends CrmPermissionValidateService {
+public interface CrmBusinessService {
 
     /**
      * 创建商机

+ 10 - 22
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.crm.service.business;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.*;
 import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert;
@@ -51,7 +50,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
 
         // 创建数据权限
         crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())
-                .setBizId(business.getId()).setUserId(userId).setPermissionLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
+                .setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
 
         // 返回
         return business.getId();
@@ -59,8 +58,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, getIdFor = CrmBusinessUpdateReqVO.class,
-            permissionLevel = CrmPermissionLevelEnum.WRITE)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id",
+            level = CrmPermissionLevelEnum.WRITE)
     public void updateBusiness(CrmBusinessUpdateReqVO updateReqVO) {
         // 校验存在
         validateBusinessExists(updateReqVO.getId());
@@ -71,7 +70,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, permissionLevel = CrmPermissionLevelEnum.WRITE)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, level = CrmPermissionLevelEnum.WRITE)
     public void deleteBusiness(Long id) {
         // 校验存在
         validateBusinessExists(id);
@@ -88,7 +87,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
     }
 
     @Override
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, permissionLevel = CrmPermissionLevelEnum.READ)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, level = CrmPermissionLevelEnum.READ)
     public CrmBusinessDO getBusiness(Long id) {
         return businessMapper.selectById(id);
     }
@@ -104,21 +103,20 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
     @Override
     public PageResult<CrmBusinessDO> getBusinessPage(CrmBusinessPageReqVO pageReqVO, Long userId) {
         // 1. 获取当前用户能看的分页数据
-        PageResult<CrmPermissionDO> permissionPage = crmPermissionService.getPermissionPage(
-                CrmBusinessConvert.INSTANCE.convert(pageReqVO).setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()).setUserId(userId));
-        Set<Long> ids = convertSet(permissionPage.getList(), CrmPermissionDO::getBizId);
+        List<CrmPermissionDO> permissions = crmPermissionService.getPermissionListByBizTypeAndUserId(
+                CrmBizTypeEnum.CRM_BUSINESS.getType(), userId);
+        Set<Long> ids = convertSet(permissions, CrmPermissionDO::getBizId);
         if (CollUtil.isEmpty(ids)) { // 没得说明没有什么给他看的
             return PageResult.empty();
         }
 
         // 2. 获取商机分页数据
-        List<CrmBusinessDO> businessList = businessMapper.selectList(pageReqVO, ids);
-        return new PageResult<>(businessList, (long) businessList.size());
+        return businessMapper.selectPage(pageReqVO, ids);
     }
 
     @Override
     public List<CrmBusinessDO> getBusinessList(CrmBusinessExportReqVO exportReqVO) {
-        return businessMapper.selectList(exportReqVO);
+        return businessMapper.selectPage(exportReqVO);
     }
 
     @Override
@@ -134,14 +132,4 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
         // 3. TODO 记录转移日志
     }
 
-    @Override
-    public boolean validateBizIdExists(Integer bizType, Long bizId) {
-        // 1. 校验模块类型
-        if (!ObjUtil.equal(CrmBizTypeEnum.CRM_BUSINESS.getType(), bizId)) {
-            return false;
-        }
-        // 2. 校验是否存在
-        return businessMapper.selectById(bizId) != null;
-    }
-
 }

+ 10 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/ContactServiceImpl.java

@@ -37,11 +37,18 @@ public class ContactServiceImpl implements ContactService {
         // 插入
         ContactDO contact = ContactConvert.INSTANCE.convert(createReqVO);
         contactMapper.insert(contact);
+
+        // 创建数据权限
+        crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CONTACTS.getType())
+                .setBizId(contact.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
+
         // 返回
         return contact.getId();
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS, level = CrmPermissionLevelEnum.WRITE)
     public void updateContact(ContactUpdateReqVO updateReqVO) {
         // 校验存在
         validateContactExists(updateReqVO.getId());
@@ -51,6 +58,8 @@ public class ContactServiceImpl implements ContactService {
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS, level = CrmPermissionLevelEnum.WRITE)
     public void deleteContact(Long id) {
         // 校验存在
         validateContactExists(id);
@@ -65,6 +74,7 @@ public class ContactServiceImpl implements ContactService {
     }
 
     @Override
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACTS, level = CrmPermissionLevelEnum.READ)
     public ContactDO getContact(Long id) {
         return contactMapper.selectById(id);
     }

+ 4 - 5
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/ContractServiceImpl.java

@@ -46,7 +46,7 @@ public class ContractServiceImpl implements ContractService {
 
         // 创建数据权限
         crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType())
-                .setBizId(contract.getId()).setUserId(userId).setPermissionLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
+                .setBizId(contract.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
 
         // 返回
         return contract.getId();
@@ -54,8 +54,7 @@ public class ContractServiceImpl implements ContractService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, getIdFor = ContractUpdateReqVO.class,
-            permissionLevel = CrmPermissionLevelEnum.WRITE)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, level = CrmPermissionLevelEnum.WRITE)
     public void updateContract(ContractUpdateReqVO updateReqVO) {
         // 校验存在
         validateContractExists(updateReqVO.getId());
@@ -66,7 +65,7 @@ public class ContractServiceImpl implements ContractService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, permissionLevel = CrmPermissionLevelEnum.WRITE)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, level = CrmPermissionLevelEnum.WRITE)
     public void deleteContract(Long id) {
         // 校验存在
         validateContractExists(id);
@@ -83,7 +82,7 @@ public class ContractServiceImpl implements ContractService {
     }
 
     @Override
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, permissionLevel = CrmPermissionLevelEnum.READ)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, level = CrmPermissionLevelEnum.READ)
     public ContractDO getContract(Long id) {
         return contractMapper.selectById(id);
     }

+ 2 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java

@@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 
 import javax.validation.Valid;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -50,9 +49,10 @@ public interface CrmCustomerService {
      * 获得客户分页
      *
      * @param pageReqVO 分页查询
+     * @param userId    用户编号
      * @return 客户分页
      */
-    PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO);
+    PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId);
 
     /**
      * 获得客户列表, 用于 Excel 导出

+ 34 - 11
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java

@@ -1,10 +1,15 @@
 package cn.iocoder.yudao.module.crm.service.customer;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
 import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
 import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
+import cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerSceneEnum;
 import cn.iocoder.yudao.module.crm.framework.core.annotations.CrmPermission;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
@@ -15,10 +20,13 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS;
 
 /**
@@ -43,7 +51,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
         // 创建数据权限
         crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
-                .setBizId(customer.getId()).setUserId(userId).setPermissionLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
+                .setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
 
         // 返回
         return customer.getId();
@@ -51,12 +59,10 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, getIdFor = CrmCustomerUpdateReqVO.class,
-            permissionLevel = CrmPermissionLevelEnum.WRITE)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
     public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) {
         // 校验存在
         validateCustomerExists(updateReqVO.getId());
-        // TODO 芋艿:数据权限,校验是否可以操作
 
         // 更新
         CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
@@ -65,11 +71,10 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, permissionLevel = CrmPermissionLevelEnum.WRITE)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
     public void deleteCustomer(Long id) {
         // 校验存在
         validateCustomerExists(id);
-        // TODO 芋艿:数据权限,校验是否可以操作
 
         // 删除
         customerMapper.deleteById(id);
@@ -82,20 +87,38 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     }
 
     @Override
-    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, permissionLevel = CrmPermissionLevelEnum.READ)
+    @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.READ)
     public CrmCustomerDO getCustomer(Long id) {
         return customerMapper.selectById(id);
     }
 
     @Override
-    public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO) {
-        // TODO 芋艿:数据权限,是否可以查询到;
-        return customerMapper.selectPage(pageReqVO);
+    public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
+        // 1.1 TODO 如果是超级管理员
+        boolean admin = false;
+        if (admin && ObjUtil.notEqual(userId, CrmPermissionDO.POOL_USER_ID)) {
+            return customerMapper.selectPage(pageReqVO, Collections.emptyList());
+        }
+        // 1.2 获取当前用户能看的分页数据
+        List<CrmPermissionDO> permissions = crmPermissionService.getPermissionListByBizTypeAndUserId(
+                CrmBizTypeEnum.CRM_CUSTOMER.getType(), userId);
+        // 1.3 TODO 场景数据过滤
+        if (CrmCustomerSceneEnum.isOwner(pageReqVO.getSceneType())) { // 场景一:我负责的数据
+            permissions = CollectionUtils.filterList(permissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()));
+        }
+        Set<Long> ids = convertSet(permissions, CrmPermissionDO::getBizId);
+        if (CollUtil.isEmpty(ids)) { // 没得说明没有什么给他看的
+            return PageResult.empty();
+        }
+
+        // 2. 获取客户分页数据
+        return customerMapper.selectPage(pageReqVO, ids);
     }
 
     @Override
     public List<CrmCustomerDO> getCustomerList(CrmCustomerExportReqVO exportReqVO) {
-        return customerMapper.selectList(exportReqVO);
+        //return customerMapper.selectList(exportReqVO);
+        return Collections.emptyList();
     }
 
     /**

+ 51 - 14
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionService.java

@@ -1,15 +1,14 @@
 package cn.iocoder.yudao.module.crm.service.permission;
 
 
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionPageReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionUpdateReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmTransferPermissionReqBO;
+import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
 
 import javax.validation.Valid;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -30,16 +29,16 @@ public interface CrmPermissionService {
     /**
      * 更新数据权限
      *
-     * @param updateBO 更新信息
+     * @param updateReqVO 更新信息
      */
-    void updatePermission(@Valid CrmPermissionUpdateReqBO updateBO);
+    void updatePermission(CrmPermissionUpdateReqVO updateReqVO);
 
     /**
      * 删除数据权限
      *
-     * @param id 编号
+     * @param ids 编号
      */
-    void deletePermission(Long id);
+    void deletePermission(Collection<Long> ids);
 
     /**
      * 获取用户数据权限通过 数据类型 x 某个数据 x 用户编号
@@ -51,6 +50,15 @@ public interface CrmPermissionService {
      */
     CrmPermissionDO getPermissionByBizTypeAndBizIdAndUserId(Integer bizType, Long bizId, Long userId);
 
+    /**
+     * 获取用户数据权限通过 权限编号 x 用户编号
+     *
+     * @param id     权限编号
+     * @param userId 用户编号
+     * @return 数据权限
+     */
+    CrmPermissionDO getPermissionByIdAndUserId(Long id, Long userId);
+
     /**
      * 获取数据权限列表,通过 数据类型 x 某个数据
      *
@@ -60,19 +68,48 @@ public interface CrmPermissionService {
      */
     List<CrmPermissionDO> getPermissionByBizTypeAndBizId(Integer bizType, Long bizId);
 
+    /**
+     * 获取数据权限列表,通过 数据类型 x 某个数据
+     *
+     * @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
+     * @param bizIds  数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
+     * @param level   权限级别
+     * @return Crm 数据权限列表
+     */
+    List<CrmPermissionDO> getPermissionByBizTypeAndBizIdsAndLevel(Integer bizType, Collection<Long> bizIds, Integer level);
+
     /**
      * 数据权限转移
      *
-     * @param crmTransferPermissionReqBO 数据权限转移请求
+     * @param crmPermissionTransferReqBO 数据权限转移请求
      */
-    void transferPermission(@Valid CrmTransferPermissionReqBO crmTransferPermissionReqBO);
+    void transferPermission(@Valid CrmPermissionTransferReqBO crmPermissionTransferReqBO);
 
     /**
-     * 获取数据权限分页数据
+     * 获取用户参与的模块数据列表
      *
-     * @param pageReqBO 分页请求
-     * @return 数据权限分页数据
+     * @param bizType 模块类型
+     * @param userId  用户编号
+     * @return 模块数据列表
+     */
+    List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId);
+
+    /**
+     * 领取公海数据
+     *
+     * @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
+     * @param bizId   数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
+     * @param userId  用户编号,AdminUser#id
+     */
+    void receiveBiz(Integer bizType, Long bizId, Long userId);
+
+    /**
+     * 数据放入公海
+     *
+     * @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
+     * @param bizId   数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
+     * @param userId  用户编号,AdminUser#id
      */
-    PageResult<CrmPermissionDO> getPermissionPage(CrmPermissionPageReqBO pageReqBO);
+    void putPool(Integer bizType, Long bizId, Long userId);
 
 }

+ 62 - 34
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmPermissionServiceImpl.java

@@ -2,22 +2,21 @@ package cn.iocoder.yudao.module.crm.service.permission;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.crm.controller.admin.permission.vo.CrmPermissionUpdateReqVO;
 import cn.iocoder.yudao.module.crm.convert.permission.CrmPermissionConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
 import cn.iocoder.yudao.module.crm.dal.mysql.permission.CrmPermissionMapper;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionPageReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionUpdateReqBO;
-import cn.iocoder.yudao.module.crm.service.permission.bo.CrmTransferPermissionReqBO;
+import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
@@ -54,26 +53,22 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void updatePermission(CrmPermissionUpdateReqBO updateBO) {
-        // TODO @puhui999:这里 1.1 1.2;下面 2.;这样更有序一点;
-        // 1. 校验用户是否存在
-        adminUserApi.validateUserList(Collections.singletonList(updateBO.getUserId()));
-        // 2. 校验存在
-        validateCrmPermissionExists(updateBO.getId());
+    public void updatePermission(CrmPermissionUpdateReqVO updateReqVO) {
+        // 校验存在
+        validateCrmPermissionExists(updateReqVO.getIds());
 
-        // 更新操作
-        CrmPermissionDO updateDO = CrmPermissionConvert.INSTANCE.convert(updateBO);
-        crmPermissionMapper.updateById(updateDO);
+        List<CrmPermissionDO> updateDO = CrmPermissionConvert.INSTANCE.convertList(updateReqVO);
+        crmPermissionMapper.updateBatch(updateDO);
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void deletePermission(Long id) {
+    public void deletePermission(Collection<Long> ids) {
         // 校验存在
-        validateCrmPermissionExists(id);
+        validateCrmPermissionExists(ids);
 
         // 删除
-        crmPermissionMapper.deleteById(id);
+        crmPermissionMapper.deleteBatchIds(ids);
     }
 
     @Override
@@ -81,63 +76,96 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
         return crmPermissionMapper.selectByBizTypeAndBizIdByUserId(bizType, bizId, userId);
     }
 
+    @Override
+    public CrmPermissionDO getPermissionByIdAndUserId(Long id, Long userId) {
+        return crmPermissionMapper.selectByIdAndUserId(id, userId);
+    }
+
     @Override
     public List<CrmPermissionDO> getPermissionByBizTypeAndBizId(Integer bizType, Long bizId) {
         return crmPermissionMapper.selectByBizTypeAndBizId(bizType, bizId);
     }
 
-    private void validateCrmPermissionExists(Long id) {
-        if (crmPermissionMapper.selectById(id) == null) {
+    @Override
+    public List<CrmPermissionDO> getPermissionByBizTypeAndBizIdsAndLevel(Integer bizType, Collection<Long> bizIds, Integer level) {
+        return crmPermissionMapper.selectListByBizTypeAndBizIdsAndLevel(bizType, bizIds, level);
+    }
+
+    private void validateCrmPermissionExists(Collection<Long> ids) {
+        List<CrmPermissionDO> permissionList = crmPermissionMapper.selectBatchIds(ids);
+        // 校验存在
+        if (ObjUtil.notEqual(permissionList.size(), ids.size())) {
             throw exception(CRM_PERMISSION_NOT_EXISTS);
         }
     }
 
     @Override
-    public void transferPermission(CrmTransferPermissionReqBO transferReqBO) {
+    @Transactional(rollbackFor = Exception.class)
+    public void transferPermission(CrmPermissionTransferReqBO transferReqBO) {
         // 1. 校验数据权限-是否是负责人,只有负责人才可以转移
         CrmPermissionDO oldPermission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId(transferReqBO.getBizType(),
                 transferReqBO.getBizId(), transferReqBO.getUserId());
         String crmName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType());
         // TODO 校验是否为超级管理员 || 1
-        if (oldPermission == null || !isOwner(oldPermission.getPermissionLevel())) {
+        if (oldPermission == null || !isOwner(oldPermission.getLevel())) {
             throw exception(CRM_PERMISSION_DENIED, crmName);
         }
-
-        // TODO @puhui999:这个顺序编号,看看调整下;2. 后面是 2.1 ,结果没 2.2 有点怪;
-        // 2. 校验转移对象是否已经是该负责人
+        // 1.1 校验转移对象是否已经是该负责人
         if (ObjUtil.equal(transferReqBO.getNewOwnerUserId(), oldPermission.getUserId())) {
             throw exception(CRM_PERMISSION_MODEL_TRANSFER_FAIL_OWNER_USER_EXISTS, crmName);
         }
-        // 2.1 校验新负责人是否存在
+        // 1.2 校验新负责人是否存在
         adminUserApi.validateUserList(Collections.singletonList(transferReqBO.getNewOwnerUserId()));
-        // 3. 权限转移
+
+        // 2. 权限转移
         List<CrmPermissionDO> permissions = crmPermissionMapper.selectByBizTypeAndBizId(
                 transferReqBO.getBizType(), transferReqBO.getBizId()); // 获取所有团队成员
-        // 3.1 校验新负责人是否在团队成员中
+        // 2.1 校验新负责人是否在团队成员中
         CrmPermissionDO permission = CollUtil.findOne(permissions,
                 item -> ObjUtil.equal(item.getUserId(), transferReqBO.getNewOwnerUserId()));
         if (permission == null) { // 不存在则以负责人的级别加入这个团队
             crmPermissionMapper.insert(new CrmPermissionDO().setBizType(transferReqBO.getBizType())
                     .setBizId(transferReqBO.getBizId()).setUserId(transferReqBO.getNewOwnerUserId())
-                    .setPermissionLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
+                    .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
 
         } else { // 存在则修改权限级别
             crmPermissionMapper.updateById(new CrmPermissionDO().setId(permission.getId())
-                    .setPermissionLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
+                    .setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
         }
-
-        // 4. 老负责人处理
-        if (transferReqBO.getJoinTeam()) { // 加入团队
+        // 2.2. 老负责人处理
+        if (transferReqBO.getOldOwnerPermissionLevel() != null) { // 加入团队
             crmPermissionMapper.updateById(new CrmPermissionDO().setId(oldPermission.getId())
-                    .setPermissionLevel(transferReqBO.getPermissionLevel())); // 设置加入团队后的级别
+                    .setLevel(transferReqBO.getOldOwnerPermissionLevel())); // 设置加入团队后的级别
             return;
         }
         crmPermissionMapper.deleteById(oldPermission.getId()); // 移除
     }
 
     @Override
-    public PageResult<CrmPermissionDO> getPermissionPage(CrmPermissionPageReqBO pageReqBO) {
-        return crmPermissionMapper.selectPage(pageReqBO);
+    public List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId) {
+        return crmPermissionMapper.selectListByBizTypeAndUserId(bizType, userId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void receiveBiz(Integer bizType, Long bizId, Long userId) {
+        CrmPermissionDO permission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId(bizType, bizId, CrmPermissionDO.POOL_USER_ID);
+        if (permission == null) { // 不存在则模块数据也不存在
+            throw exception(CRM_PERMISSION_MODEL_NOT_EXISTS, CrmBizTypeEnum.getNameByType(bizType));
+        }
+
+        crmPermissionMapper.updateById(new CrmPermissionDO().setId(permission.getId()).setUserId(userId));
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void putPool(Integer bizType, Long bizId, Long userId) {
+        CrmPermissionDO permission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId(bizType, bizId, userId);
+        if (permission == null) { // 不存在则模块数据也不存在
+            throw exception(CRM_PERMISSION_MODEL_NOT_EXISTS, CrmBizTypeEnum.getNameByType(bizType));
+        }
+
+        crmPermissionMapper.updateById(new CrmPermissionDO().setId(permission.getId()).setUserId(CrmPermissionDO.POOL_USER_ID));
     }
 
 }

+ 1 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionCreateReqBO.java

@@ -33,12 +33,11 @@ public class CrmPermissionCreateReqBO {
     @NotNull(message = "Crm 数据编号不能为空")
     private Long bizId;
 
-    // TODO @puhui999:简化成 level
     /**
      * 权限级别
      */
     @NotNull(message = "权限级别不能为空")
     @InEnum(CrmPermissionLevelEnum.class)
-    private Integer permissionLevel;
+    private Integer level;
 
 }

+ 0 - 32
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionPageReqBO.java

@@ -1,32 +0,0 @@
-package cn.iocoder.yudao.module.crm.service.permission.bo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import javax.validation.constraints.NotNull;
-
-@Schema(description = "管理后台 - CRM 数据权限分页 Request BO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class CrmPermissionPageReqBO extends PageParam {
-
-    /**
-     * 当前登录用户编号
-     */
-    @NotNull(message = "用户编号不能为空")
-    private Long userId;
-
-    /**
-     * Crm 类型
-     */
-    @NotNull(message = "Crm 类型不能为空")
-    @InEnum(CrmBizTypeEnum.class)
-    private Integer bizType;
-
-}

+ 3 - 11
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmTransferPermissionReqBO.java → yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionTransferReqBO.java

@@ -7,14 +7,13 @@ import lombok.Data;
 
 import javax.validation.constraints.NotNull;
 
-// TODO @puhui999:CrmPermissionTransferReqBO
 /**
  * 数据权限转移 Request BO
  *
  * @author HUIHUI
  */
 @Data
-public class CrmTransferPermissionReqBO {
+public class CrmPermissionTransferReqBO {
 
     /**
      * 当前登录用户编号
@@ -40,17 +39,10 @@ public class CrmTransferPermissionReqBO {
     @NotNull(message = "新负责人的用户编号不能为空")
     private Long newOwnerUserId;
 
-    // TODO @puhui999:joinTeam 可以合并成 permissionLevel 里;oldOwnerPermissionLevel;这样 null 说明移除,因为都换负责人啦;
     /**
-     * 老负责人是否加入团队,是/否
-     */
-    @NotNull(message = "老负责人是否加入团队不能为空")
-    private Boolean joinTeam;
-
-    /**
-     * 老负责人加入团队后的权限级别。如果 {@link #joinTeam} 为 false, permissionLevel 为 null
+     * 老负责人加入团队后的权限级别。如果 null 说明移除
      * 关联 {@link CrmPermissionLevelEnum}
      */
-    private Integer permissionLevel;
+    private Integer oldOwnerPermissionLevel;
 
 }

+ 1 - 17
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmPermissionUpdateReqBO.java

@@ -1,8 +1,6 @@
 package cn.iocoder.yudao.module.crm.service.permission.bo;
 
 import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
-import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmPermissionLevelEnum;
 import lombok.Data;
 
@@ -28,25 +26,11 @@ public class CrmPermissionUpdateReqBO {
     @NotNull(message = "用户编号不能为空")
     private Long userId;
 
-    // TODO @puhui999:id 字段,和 bizType + bizId 是否二选一;
-    /**
-     * Crm 类型
-     */
-    @NotNull(message = "Crm 类型不能为空")
-    @InEnum(CrmBizTypeEnum.class)
-    private Integer bizType;
-    /**
-     * 数据编号
-     */
-    @NotNull(message = "Crm 数据编号不能为空")
-    private Long bizId;
-
-    // TODO @puhui999:简化成 level
     /**
      * 权限级别
      */
     @NotNull(message = "权限级别不能为空")
     @InEnum(CrmPermissionLevelEnum.class)
-    private Integer permissionLevel;
+    private Integer level;
 
 }

+ 1 - 1
yudao-module-crm/yudao-module-crm-biz/src/test/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImplTest.java

@@ -130,7 +130,7 @@ public class CrmCustomerServiceImplTest extends BaseDbUnitTest {
         //reqVO.setWebsite(null);
 
         // 调用
-        PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(reqVO);
+        PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(reqVO, 1L);
         // 断言
         assertEquals(1, pageResult.getTotal());
         assertEquals(1, pageResult.getList().size());

+ 12 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApi.java

@@ -1,6 +1,11 @@
 package cn.iocoder.yudao.module.system.api.dept;
 
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
+
 import java.util.Collection;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 岗位 API 接口
@@ -18,4 +23,11 @@ public interface PostApi {
      */
     void validPostList(Collection<Long> ids);
 
+    List<PostRespDTO> getPostList(Collection<Long> ids);
+
+    default Map<Long, PostRespDTO> getPostMap(Collection<Long> ids) {
+        List<PostRespDTO> list = getPostList(ids);
+        return CollectionUtils.convertMap(list, PostRespDTO::getId);
+    }
+
 }

+ 37 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/PostRespDTO.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.system.api.dept.dto;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import lombok.Data;
+
+/**
+ * 岗位 Response DTO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class PostRespDTO {
+
+    /**
+     * 岗位序号
+     */
+    private Long id;
+    /**
+     * 岗位名称
+     */
+    private String name;
+    /**
+     * 岗位编码
+     */
+    private String code;
+    /**
+     * 岗位排序
+     */
+    private Integer sort;
+    /**
+     * 状态
+     *
+     * 枚举 {@link CommonStatusEnum}
+     */
+    private Integer status;
+
+}

+ 8 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/PostApiImpl.java

@@ -1,10 +1,13 @@
 package cn.iocoder.yudao.module.system.api.dept;
 
+import cn.iocoder.yudao.module.system.api.dept.dto.PostRespDTO;
+import cn.iocoder.yudao.module.system.convert.dept.PostConvert;
 import cn.iocoder.yudao.module.system.service.dept.PostService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * 岗位 API 实现类
@@ -22,4 +25,9 @@ public class PostApiImpl implements PostApi {
         postService.validatePostList(ids);
     }
 
+    @Override
+    public List<PostRespDTO> getPostList(Collection<Long> ids) {
+        return PostConvert.INSTANCE.convert(postService.getPostList(ids));
+    }
+
 }