소스 검색

CRM:code review 客户权限的实现

YunaiV 1 년 전
부모
커밋
89fc83c419
21개의 변경된 파일71개의 추가작업 그리고 42개의 파일을 삭제
  1. 1 1
      sql/mysql/ruoyi-vue-pro.sql
  2. 2 2
      yudao-dependencies/pom.xml
  3. 3 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java
  4. 1 2
      yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java
  5. 3 1
      yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java
  6. 27 19
      yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java
  7. 1 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java
  8. 2 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java
  9. 1 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerTransferReqVO.java
  10. 4 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java
  11. 2 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/vo/CrmPermissionSaveReqVO.java
  12. 1 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java
  13. 4 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java
  14. 3 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java
  15. 3 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java
  16. 3 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java
  17. 3 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java
  18. 1 1
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java
  19. 1 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
  20. 3 3
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java
  21. 2 2
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java

+ 1 - 1
sql/mysql/ruoyi-vue-pro.sql

@@ -11,7 +11,7 @@
  Target Server Version : 80200 (8.2.0)
  File Encoding         : 65001
 
- Date: 01/03/2024 19:39:45
+ Date: 05/03/2024 23:36:35
 */
 
 SET NAMES utf8mb4;

+ 2 - 2
yudao-dependencies/pom.xml

@@ -627,11 +627,11 @@
                 <artifactId>ureport2-console</artifactId>
                 <version>${ureport2.version}</version>
                 <exclusions>
-                    <exclusion><!-- 包冲突 积木报表 导出Excel报错 -->
+                    <exclusion><!-- 包冲突:解决积木报表导出 Excel 报错 -->
                         <groupId>org.apache.poi</groupId>
                         <artifactId>poi</artifactId>
                     </exclusion>
-                    <exclusion><!-- 包冲突 积木报表 导出Excel报错 -->
+                    <exclusion><!-- 包冲突:解决积木报表导出 Excel 报错 -->
                         <groupId>org.apache.poi</groupId>
                         <artifactId>poi-ooxml</artifactId>
                     </exclusion>

+ 3 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/MapUtils.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.util.collection;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.core.KeyValue;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multimap;
@@ -40,6 +41,7 @@ public class MapUtils {
 
     /**
      * 从哈希表查找到 key 对应的 value,然后进一步处理
+     * key 为 null 时, 不处理
      * 注意,如果查找到的 value 为 null 时,不进行处理
      *
      * @param map 哈希表
@@ -47,7 +49,7 @@ public class MapUtils {
      * @param consumer 进一步处理的逻辑
      */
     public static <K, V> void findAndThen(Map<K, V> map, K key, Consumer<V> consumer) {
-        if (CollUtil.isEmpty(map)) {
+        if (ObjUtil.isNull(key) || CollUtil.isEmpty(map)) {
             return;
         }
         V value = map.get(key);

+ 1 - 2
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/dict/core/DictFrameworkUtils.java

@@ -13,8 +13,6 @@ import lombok.extern.slf4j.Slf4j;
 import java.time.Duration;
 import java.util.List;
 
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
-
 /**
  * 字典工具类
  *
@@ -27,6 +25,7 @@ public class DictFrameworkUtils {
 
     private static final DictDataRespDTO DICT_DATA_NULL = new DictDataRespDTO();
 
+    // TODO @puhui999:GET_DICT_DATA_CACHE、GET_DICT_DATA_LIST_CACHE、PARSE_DICT_DATA_CACHE 这 3 个缓存是有点重叠,可以思考下,有没可能减少 1 个。微信讨论好私聊,再具体改哈
     /**
      * 针对 {@link #getDictDataLabel(String, String)} 的缓存
      */

+ 3 - 1
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/ExcelColumnSelect.java

@@ -3,7 +3,9 @@ package cn.iocoder.yudao.framework.excel.core.annotations;
 import java.lang.annotation.*;
 
 /**
- * 给列添加下拉选择数据
+ * 给 Excel 列添加下拉选择数据
+ *
+ * 其中 {@link #dictType()} 和 {@link #functionName()} 二选一
  *
  * @author HUIHUI
  */

+ 27 - 19
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/handler/SelectSheetWriteHandler.java

@@ -1,8 +1,9 @@
 package cn.iocoder.yudao.framework.excel.core.handler;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.hutool.poi.excel.ExcelUtil;
@@ -59,7 +60,6 @@ public class SelectSheetWriteHandler implements SheetWriteHandler {
         }
 
         // 解析下拉数据
-        // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的。回答:主要是用于定位到列索引
         Map<String, Field> excelPropertyFields = getFieldsWithAnnotation(head, ExcelProperty.class);
         Map<String, Field> excelColumnSelectFields = getFieldsWithAnnotation(head, ExcelColumnSelect.class);
         int colIndex = 0;
@@ -71,39 +71,47 @@ public class SelectSheetWriteHandler implements SheetWriteHandler {
                 if (index != -1) {
                     colIndex = index;
                 }
-                getSelectDataList(colIndex, field);
+                buildSelectDataList(colIndex, field);
             }
             colIndex++;
         }
+        // TODO @puhui999:感觉可以 head 循环 field,如果有 ExcelColumnSelect 则进行处理;而 ExcelProperty 可能是非必须的。回答:主要是用于定位到列索引;补充:可以看看下面这样写?
+//        for (Field field : head.getDeclaredFields()) {
+//            if (field.isAnnotationPresent(ExcelColumnSelect.class)) {
+//                ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
+//                if (excelProperty != null) {
+//                    colIndex = excelProperty.index();
+//                }
+//                getSelectDataList(colIndex, field);
+//            }
+//            colIndex++;
+//        }
     }
 
     /**
-     * 获得下拉数据
+     * 获得下拉数据,并添加到 {@link #selectMap} 中
      *
      * @param colIndex 列索引
      * @param field    字段
      */
-    private void getSelectDataList(int colIndex, Field field) {
-        // 获得下拉注解信息
+    private void buildSelectDataList(int colIndex, Field field) {
         ExcelColumnSelect columnSelect = field.getAnnotation(ExcelColumnSelect.class);
         String dictType = columnSelect.dictType();
+        String functionName = columnSelect.functionName();
+        Assert.isTrue(ObjectUtil.isNotEmpty(dictType) || ObjectUtil.isNotEmpty(functionName),
+                "Field({}) 的 @ExcelColumnSelect 注解,dictType 和 functionName 不能同时为空", field.getName());
+
+        // 情况一:使用 dictType 获得下拉数据
         if (StrUtil.isNotEmpty(dictType)) { // 情况一: 字典数据 (默认)
             selectMap.put(colIndex, DictFrameworkUtils.getDictDataLabelList(dictType));
             return;
         }
-        String functionName = columnSelect.functionName();
-        if (StrUtil.isEmpty(functionName)) { // 情况二: 获取自定义数据
-            log.warn("[getSelectDataList]解析下拉数据失败,参数信息 dictType[{}] functionName[{}]", dictType, functionName);
-            return;
-        }
-        // 获得所有的下拉数据源获取方法
+
+        // 情况二:使用 functionName 获得下拉数据
         Map<String, ExcelColumnSelectFunction> functionMap = SpringUtil.getApplicationContext().getBeansOfType(ExcelColumnSelectFunction.class);
-        functionMap.values().forEach(func -> {
-            if (ObjUtil.notEqual(func.getName(), functionName)) {
-                return;
-            }
-            selectMap.put(colIndex, func.getOptions());
-        });
+        ExcelColumnSelectFunction function = CollUtil.findOne(functionMap.values(), item -> item.getName().equals(functionName));
+        Assert.notNull(function, "未找到对应的 function({})", functionName);
+        selectMap.put(colIndex, function.getOptions());
     }
 
     @Override
@@ -121,7 +129,7 @@ public class SelectSheetWriteHandler implements SheetWriteHandler {
         Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME);
         for (KeyValue<Integer, List<String>> keyValue : keyValues) {
             int rowLength = keyValue.getValue().size();
-            // 2.1 设置字典 sheet 页的值 每一列一个字典项
+            // 2.1 设置字典 sheet 页的值每一列一个字典项
             for (int i = 0; i < rowLength; i++) {
                 Row row = dictSheet.getRow(i);
                 if (row == null) {

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

@@ -13,6 +13,7 @@ import lombok.NoArgsConstructor;
 @AllArgsConstructor
 public class CrmBusinessTransferReqVO {
 
+    // TODO @puhui999:这里最好还是用 id 哈,主要还是在 Business 业务里
     @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     @NotNull(message = "商机编号不能为空")
     private Long bizId;

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

@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 import cn.iocoder.yudao.framework.excel.core.annotations.ExcelColumnSelect;
 import cn.iocoder.yudao.framework.excel.core.convert.AreaConvert;
 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
-import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunctionImpl;
+import cn.iocoder.yudao.module.crm.framework.excel.core.AreaExcelColumnSelectFunction;
 import com.alibaba.excel.annotation.ExcelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -43,7 +43,7 @@ public class CrmCustomerImportExcelVO {
     private String email;
 
     @ExcelProperty(value = "地区", converter = AreaConvert.class)
-    @ExcelColumnSelect(functionName = AreaExcelColumnSelectFunctionImpl.NAME)
+    @ExcelColumnSelect(functionName = AreaExcelColumnSelectFunction.NAME)
     private Integer areaId;
 
     @ExcelProperty("详细地址")

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

@@ -31,7 +31,7 @@ public class CrmCustomerTransferReqVO {
     private Integer oldOwnerPermissionLevel;
 
     /**
-     * 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择
+     * 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择。选中时,也一起转移
      */
     @Schema(description = "同时转移", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     private List<Integer> toBizTypes;

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

@@ -68,22 +68,24 @@ public class CrmPermissionController {
     @Resource
     private PostApi postApi;
 
+    // TODO @puhui999:是不是还是叫 create 好点哈。
     @PostMapping("/create")
     @Operation(summary = "创建数据权限")
     @Transactional(rollbackFor = Exception.class)
     @PreAuthorize("@ss.hasPermission('crm:permission:create')")
     @CrmPermission(bizTypeValue = "#reqVO.bizType", bizId = "#reqVO.bizId", level = CrmPermissionLevelEnum.OWNER)
-    public CommonResult<Boolean> addPermission(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) {
+    public CommonResult<Boolean> savePermission(@Valid @RequestBody CrmPermissionSaveReqVO reqVO) {
         permissionService.createPermission(BeanUtils.toBean(reqVO, CrmPermissionCreateReqBO.class));
+        // 处理【同时添加至】的权限
         if (CollUtil.isNotEmpty(reqVO.getToBizTypes())) {
             createBizTypePermissions(reqVO);
         }
         return success(true);
     }
 
-
     private void createBizTypePermissions(CrmPermissionSaveReqVO reqVO) {
         List<CrmPermissionCreateReqBO> createPermissions = new ArrayList<>();
+        // TODO @puhui999:需要考虑,被添加人,是不是应该有对应的权限了;
         if (reqVO.getToBizTypes().contains(CrmBizTypeEnum.CRM_CONTACT.getType())) {
             List<CrmContactDO> contactList = contactService.getContactListByCustomerIdOwnerUserId(reqVO.getBizId(), getLoginUserId());
             contactList.forEach(item -> {

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

@@ -33,7 +33,8 @@ public class CrmPermissionSaveReqVO {
     private Integer level;
 
     /**
-     * 添加客户团队成员时,需要额外有【联系人】【商机】【合同】的 checkbox 选择
+     * 添加客户团队成员时,需要额外有【联系人】【商机】【合同】的 checkbox 选择。
+     * 选中时,同时添加对应的权限
      */
     @Schema(description = "同时添加", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430")
     private List<Integer> toBizTypes;

+ 1 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java

@@ -74,6 +74,7 @@ public interface CrmContactMapper extends BaseMapperX<CrmContactDO> {
     }
 
     default List<CrmContactDO> selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) {
+        // TODO @puhui999:父类有 selectList,查询 2 个字段的简化方法哈,可以用下
         return selectList(new LambdaQueryWrapperX<CrmContactDO>()
                 .eq(CrmContactDO::getCustomerId, customerId)
                 .eq(CrmContactDO::getOwnerUserId, ownerUserId));

+ 4 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java

@@ -99,4 +99,8 @@ public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> {
         return convertMap(result, obj -> (Long) obj.get("contract_id"), obj -> (BigDecimal) obj.get("total_price"));
     }
 
+    default Long selectCountByContractId(Long contractId) {
+        return selectCount(CrmReceivableDO::getContractId, contractId);
+    }
+
 }

+ 3 - 1
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunctionImpl.java → yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/core/AreaExcelColumnSelectFunction.java

@@ -10,10 +10,12 @@ import java.util.List;
 /**
  * Excel 所属地区列下拉数据源获取接口实现类
  *
+ * // TODO @puhui999:类名叫:地区下拉框数据源的 {@link ExcelColumnSelectFunction} 实现类,这样看起来会更简洁一点哈
+ *
  * @author HUIHUI
  */
 @Service
-public class AreaExcelColumnSelectFunctionImpl implements ExcelColumnSelectFunction {
+public class AreaExcelColumnSelectFunction implements ExcelColumnSelectFunction {
 
     public static final String NAME = "getCrmAreaNameList"; // 防止和别的模块重名
 

+ 3 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/excel/package-info.java

@@ -1 +1,4 @@
+/**
+ * crm 模块的 excel 拓展封装
+ */
 package cn.iocoder.yudao.module.crm.framework.excel;

+ 3 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/operatelog/package-info.java

@@ -1 +1,4 @@
+/**
+ * crm 模块的 operatelog 拓展封装
+ */
 package cn.iocoder.yudao.module.crm.framework.operatelog;

+ 3 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/package-info.java

@@ -1 +1,4 @@
+/**
+ * crm 模块的 permission 拓展封装
+ */
 package cn.iocoder.yudao.module.crm.framework.permission;

+ 1 - 1
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/web/package-info.java

@@ -1,4 +1,4 @@
 /**
- * trade 模块的 web 配置
+ * crm 模块的 web 拓展封装
  */
 package cn.iocoder.yudao.module.crm.framework.web;

+ 1 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java

@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.ObjUtil;
-import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -27,7 +26,6 @@ import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPerm
 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
 import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
-import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerServiceImpl;
 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
@@ -231,7 +229,7 @@ public class CrmContractServiceImpl implements CrmContractService {
         // 1.1 校验存在
         CrmContractDO contract = validateContractExists(id);
         // 1.2 如果被 CrmReceivableDO 所使用,则不允许删除
-        if (receivableService.getReceivableByContractId(contract.getId()) != 0) {
+        if (receivableService.getReceivableCountByContractId(contract.getId()) > 0) {
             throw exception(CONTRACT_DELETE_FAIL);
         }
 

+ 3 - 3
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableService.java

@@ -123,11 +123,11 @@ public interface CrmReceivableService {
     Map<Long, BigDecimal> getReceivablePriceMapByContractId(Collection<Long> contractIds);
 
     /**
-     * 更具合同编号查询回款列表
+     * 根据合同编号查询回款数量
      *
      * @param contractId 合同编号
-     * @return 回款
+     * @return 回款数量
      */
-    Long getReceivableByContractId(Long contractId);
+    Long getReceivableCountByContractId(Long contractId);
 
 }

+ 2 - 2
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java

@@ -302,8 +302,8 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
     }
 
     @Override
-    public Long getReceivableByContractId(Long contractId) {
-        return receivableMapper.selectCount(CrmReceivableDO::getContractId, contractId);
+    public Long getReceivableCountByContractId(Long contractId) {
+        return receivableMapper.selectCountByContractId(contractId);
     }
 
 }