From a4ff54c148654e6099ff5ced274b31aa9351ea4f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 2 Oct 2024 14:32:41 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=90=8C=E6=AD=A5=E3=80=91BOOT=20?= =?UTF-8?q?=E5=92=8C=20CLOUD=20=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=88CRM=20?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/handler/GlobalExceptionHandler.java | 6 ++ .../gateway/util/BannerApplicationRunner.java | 2 + .../admin/clue/vo/CrmCluePageReqVO.java | 3 - .../dal/mysql/business/CrmBusinessMapper.java | 2 +- .../crm/dal/mysql/clue/CrmClueMapper.java | 16 +--- .../dal/mysql/contact/CrmContactMapper.java | 2 +- .../dal/mysql/contract/CrmContractMapper.java | 16 +--- .../dal/mysql/customer/CrmCustomerMapper.java | 28 +++---- .../mysql/receivable/CrmReceivableMapper.java | 13 +--- .../receivable/CrmReceivablePlanMapper.java | 15 +--- .../CrmStatisticsCustomerMapper.java | 14 ++-- .../core/aop/CrmPermissionAspect.java | 78 +++++++++++++------ .../crm/service/clue/CrmClueService.java | 10 --- .../crm/service/clue/CrmClueServiceImpl.java | 12 +-- .../module/crm/util/CrmPermissionUtils.java | 46 ++--------- 15 files changed, 101 insertions(+), 162 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java index 173a5b8ad..8d6372443 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -383,6 +383,12 @@ public class GlobalExceptionHandler { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]"); } + // 9. IOT 物联网 + if (message.contains("iot_")) { + log.error("[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + } return null; } diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java index 9ab9e81b0..a3d5ccdaa 100644 --- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java +++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java @@ -47,6 +47,8 @@ public class BannerApplicationRunner implements ApplicationRunner { System.out.println("[支付系统 yudao-module-pay - 教程][参考 https://doc.iocoder.cn/pay/build/ 开启]"); // AI 大模型 System.out.println("[AI 大模型 yudao-module-ai - 教程][参考 https://cloud.iocoder.cn/ai/build/ 开启]"); + // IOT 物联网 + System.out.println("[IOT 物联网 yudao-module-iot - 教程][参考 https://doc.iocoder.cn/iot/build/ 开启]"); }); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java index a63d946e9..d3282f35a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java @@ -30,9 +30,6 @@ public class CrmCluePageReqVO extends PageParam { @InEnum(CrmSceneTypeEnum.class) private Integer sceneType; // 场景类型,为 null 时则表示全部 - @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") - private Boolean pool; // null 则表示为不是公海数据 - @Schema(description = "所属行业", example = "1") private Integer industryId; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java index ba347bcf6..894ab325d 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -47,7 +47,7 @@ public interface CrmBusinessMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), - CrmBusinessDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + CrmBusinessDO::getId, userId, pageReqVO.getSceneType()); // 拼接自身的查询条件 query.selectAll(CrmBusinessDO.class) .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java index d0665c604..88650dc89 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/clue/CrmClueMapper.java @@ -10,9 +10,6 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; import org.apache.ibatis.annotations.Mapper; -import java.util.Collection; -import java.util.List; - /** * 线索 Mapper * @@ -25,7 +22,7 @@ public interface CrmClueMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), - CrmClueDO::getId, userId, pageReqVO.getSceneType(), pageReqVO.getPool()); + CrmClueDO::getId, userId, pageReqVO.getSceneType()); // 拼接自身的查询条件 query.selectAll(CrmClueDO.class) .likeIfPresent(CrmClueDO::getName, pageReqVO.getName()) @@ -40,20 +37,11 @@ public interface CrmClueMapper extends BaseMapperX { return selectJoinPage(pageReqVO, CrmClueDO.class, query); } - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), ids, userId); - query.selectAll(CrmClueDO.class).in(CrmClueDO::getId, ids).orderByDesc(CrmClueDO::getId); - // 拼接自身的查询条件 - return selectJoinList(CrmClueDO.class, query); - } - default Long selectCountByFollow(Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CLUE.getType(), - CrmClueDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmClueDO::getId, userId, CrmSceneTypeEnum.OWNER.getType()); // 未跟进 + 未转化 query.eq(CrmClueDO::getFollowUpStatus, false) .eq(CrmClueDO::getTransformStatus, false); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java index 75f2a750e..06114ae98 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contact/CrmContactMapper.java @@ -56,7 +56,7 @@ public interface CrmContactMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTACT.getType(), - CrmContactDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + CrmContactDO::getId, userId, pageReqVO.getSceneType()); // 拼接自身的查询条件 query.selectAll(CrmContactDO.class) .likeIfPresent(CrmContactDO::getName, pageReqVO.getName()) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java index 14d743291..130311249 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contract/CrmContractMapper.java @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; import org.apache.ibatis.annotations.Mapper; import java.time.LocalDateTime; -import java.util.Collection; import java.util.List; /** @@ -54,7 +53,7 @@ public interface CrmContractMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), - CrmContractDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + CrmContractDO::getId, userId, pageReqVO.getSceneType()); // 拼接自身的查询条件 query.selectAll(CrmContractDO.class) .likeIfPresent(CrmContractDO::getNo, pageReqVO.getNo()) @@ -77,15 +76,6 @@ public interface CrmContractMapper extends BaseMapperX { return selectJoinPage(pageReqVO, CrmContractDO.class, query); } - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 构建数据权限连表条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), ids, userId); - // 拼接自身的查询条件 - query.selectAll(CrmContractDO.class).in(CrmContractDO::getId, ids).orderByDesc(CrmContractDO::getId); - return selectJoinList(CrmContractDO.class, query); - } - default Long selectCountByContactId(Long contactId) { return selectCount(CrmContractDO::getSignContactId, contactId); } @@ -98,7 +88,7 @@ public interface CrmContractMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), - CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType()); // 未审核 query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); return selectCount(query); @@ -108,7 +98,7 @@ public interface CrmContractMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), - CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmContractDO::getId, userId, CrmSceneTypeEnum.OWNER.getType()); // 即将到期 LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java index 615783950..6be118677 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java @@ -20,7 +20,6 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import java.time.LocalDateTime; -import java.util.Collection; import java.util.List; /** @@ -52,8 +51,12 @@ public interface CrmCustomerMapper extends BaseMapperX { default PageResult selectPage(CrmCustomerPageReqVO pageReqVO, Long ownerUserId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), pageReqVO.getPool()); + if (Boolean.TRUE.equals(pageReqVO.getPool())) { + query.isNull(CrmCustomerDO::getOwnerUserId); + } else { + CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), + CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType()); + } // 拼接自身的查询条件 query.selectAll(CrmCustomerDO.class) .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName()) @@ -81,15 +84,6 @@ public interface CrmCustomerMapper extends BaseMapperX { return selectJoinPage(pageReqVO, CrmCustomerDO.class, query); } - default List selectBatchIds(Collection ids, Long ownerUserId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, ownerUserId); - // 拼接自身的查询条件 - query.selectAll(CrmCustomerDO.class).in(CrmCustomerDO::getId, ids).orderByDesc(CrmCustomerDO::getId); - return selectJoinList(CrmCustomerDO.class, query); - } - default CrmCustomerDO selectByCustomerName(String name) { return selectOne(CrmCustomerDO::getName, name); } @@ -102,9 +96,9 @@ public interface CrmCustomerMapper extends BaseMapperX { } default Long selectPutPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO, - CrmCustomerPoolConfigDO poolConfigDO, + CrmCustomerPoolConfigDO poolConfig, Long userId) { - final MPJLambdaWrapperX query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfigDO, userId); + final MPJLambdaWrapperX query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, userId); return selectCount(query); } @@ -114,7 +108,7 @@ public interface CrmCustomerMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType(), null); + CrmCustomerDO::getId, ownerUserId, pageReqVO.getSceneType()); // 未锁定 + 未成交 query.eq(CrmCustomerDO::getLockStatus, false).eq(CrmCustomerDO::getDealStatus, false); @@ -168,7 +162,7 @@ public interface CrmCustomerMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType()); // 今天需联系 LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); LocalDateTime endOfToday = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); @@ -180,7 +174,7 @@ public interface CrmCustomerMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), - CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmCustomerDO::getId, ownerUserId, CrmSceneTypeEnum.OWNER.getType()); // 未跟进 query.eq(CrmClueDO::getFollowUpStatus, false); return selectCount(query); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java index 99bc09f0b..904357ea4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivableMapper.java @@ -48,7 +48,7 @@ public interface CrmReceivableMapper extends BaseMapperX { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), - CrmReceivableDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + CrmReceivableDO::getId, userId, pageReqVO.getSceneType()); // 拼接自身的查询条件 query.selectAll(CrmReceivableDO.class) .eqIfPresent(CrmReceivableDO::getNo, pageReqVO.getNo()) @@ -59,20 +59,11 @@ public interface CrmReceivableMapper extends BaseMapperX { return selectJoinPage(pageReqVO, CrmReceivableDO.class, query); } - default List selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), ids, userId); - // 拼接自身的查询条件 - query.selectAll(CrmReceivableDO.class).in(CrmReceivableDO::getId, ids).orderByDesc(CrmReceivableDO::getId); - return selectJoinList(CrmReceivableDO.class, query); - } - default Long selectCountByAudit(Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE.getType(), - CrmReceivableDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmReceivableDO::getId, userId, CrmSceneTypeEnum.OWNER.getType()); // 未审核 query.eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()); return selectCount(query); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java index 4d5389793..4ee160afe 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/receivable/CrmReceivablePlanMapper.java @@ -13,8 +13,6 @@ import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; import org.apache.ibatis.annotations.Mapper; import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; import java.util.Objects; /** @@ -48,7 +46,7 @@ public interface CrmReceivablePlanMapper extends BaseMapperX query = new MPJLambdaWrapperX<>(); // 拼接数据权限的查询条件 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), - CrmReceivablePlanDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE); + CrmReceivablePlanDO::getId, userId, pageReqVO.getSceneType()); // 拼接自身的查询条件 query.selectAll(CrmReceivablePlanDO.class) .eqIfPresent(CrmReceivablePlanDO::getCustomerId, pageReqVO.getCustomerId()) @@ -74,20 +72,11 @@ public interface CrmReceivablePlanMapper extends BaseMapperX selectBatchIds(Collection ids, Long userId) { - MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); - // 拼接数据权限的查询条件 - CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), ids, userId); - // 拼接自身的查询条件 - query.selectAll(CrmReceivablePlanDO.class).in(CrmReceivablePlanDO::getId, ids).orderByDesc(CrmReceivablePlanDO::getId); - return selectJoinList(CrmReceivablePlanDO.class, query); - } - default Long selectReceivablePlanCountByRemind(Long userId) { MPJLambdaWrapperX query = new MPJLambdaWrapperX<>(); // 我负责的 + 非公海 CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType(), - CrmReceivablePlanDO::getId, userId, CrmSceneTypeEnum.OWNER.getType(), Boolean.FALSE); + CrmReceivablePlanDO::getId, userId, CrmSceneTypeEnum.OWNER.getType()); // 未回款 + 已逾期 + 今天开始提醒 LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now()); query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index ca9a08252..171d432b0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -130,9 +130,9 @@ public interface CrmStatisticsCustomerMapper { List voList = new ArrayList<>(); while (currrentDate.isBefore(endDate)) { voList.add(new CrmStatisticsPoolSummaryByDateRespVO() - .setTime(LocalDateTimeUtil.format(currrentDate, "yyyy-MM-dd")) - .setCustomerPutCount(RandomUtil.randomInt(0, 10)) - .setCustomerTakeCount(RandomUtil.randomInt(0, 10))); + .setTime(LocalDateTimeUtil.format(currrentDate, "yyyy-MM-dd")) + .setCustomerPutCount(RandomUtil.randomInt(0, 10)) + .setCustomerTakeCount(RandomUtil.randomInt(0, 10))); currrentDate = currrentDate.plusDays(1); } @@ -159,10 +159,10 @@ public interface CrmStatisticsCustomerMapper { // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 default List selectPoolCustomerPutCountByUser(CrmStatisticsCustomerReqVO reqVO) { return convertList(reqVO.getUserIds(), userId -> - (CrmStatisticsPoolSummaryByUserRespVO) new CrmStatisticsPoolSummaryByUserRespVO() - .setCustomerPutCount(RandomUtil.randomInt(0, 10)) - .setCustomerTakeCount(RandomUtil.randomInt(0, 10)) - .setOwnerUserId(userId)); + (CrmStatisticsPoolSummaryByUserRespVO) new CrmStatisticsPoolSummaryByUserRespVO() + .setCustomerPutCount(RandomUtil.randomInt(0, 10)) + .setCustomerTakeCount(RandomUtil.randomInt(0, 10)) + .setOwnerUserId(userId)); } /** diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java index 95e182c02..e642636ba 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java @@ -11,6 +11,8 @@ import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; @@ -38,6 +40,9 @@ public class CrmPermissionAspect { @Resource private CrmPermissionService crmPermissionService; + @Resource + private AdminUserApi adminUserApi; + @Before("@annotation(crmPermission)") public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) { // 1.1 获取相关属性值 @@ -65,48 +70,75 @@ public class CrmPermissionAspect { if (CrmPermissionUtils.isCrmAdmin()) { return; } - // 1.1 没有数据权限的情况 + // 特殊:没有数据权限的情况,针对 READ 的特殊处理 if (CollUtil.isEmpty(bizPermissions)) { - // 公海数据如果没有团队成员大家也因该有读权限才对 + // 1.1 公海数据,如果没有团队成员,大家也应该有 READ 权限才对 if (CrmPermissionLevelEnum.isRead(permissionLevel)) { return; } // 没有数据权限的情况下超出了读权限直接报错,避免后面校验空指针 throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); } else { // 1.2 有数据权限但是没有负责人的情况 - if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))) { - if (CrmPermissionLevelEnum.isRead(permissionLevel)) { - return; - } + if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel())) + && CrmPermissionLevelEnum.isRead(permissionLevel)) { + return; } } - // 2.1 情况一:如果自己是负责人,则默认有所有权限 - CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), getUserId())); + // 2. 只考虑自的身权限 + Long userId = getUserId(); + CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), userId)); if (userPermission != null) { - if (CrmPermissionLevelEnum.isOwner(userPermission.getLevel())) { + if (isUserPermissionValid(userPermission, permissionLevel)) { return; } - // 2.2 情况二:校验自己是否有读权限 - if (CrmPermissionLevelEnum.isRead(permissionLevel)) { - if (CrmPermissionLevelEnum.isRead(userPermission.getLevel()) // 校验当前用户是否有读权限 - || CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 - return; - } - } - // 2.3 情况三:校验自己是否有写权限 - if (CrmPermissionLevelEnum.isWrite(permissionLevel)) { - if (CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 - return; - } + } + + // 3. 考虑下级的权限 + List subordinateUserIds = adminUserApi.getUserListBySubordinate(userId).getCheckedData(); + for (Long subordinateUserId : convertSet(subordinateUserIds, AdminUserRespDTO::getId)) { + CrmPermissionDO subordinatePermission = CollUtil.findOne(bizPermissions, + permission -> ObjUtil.equal(permission.getUserId(), subordinateUserId)); + if (subordinatePermission != null && isUserPermissionValid(subordinatePermission, permissionLevel)) { + return; } } - // 2.4 没有权限,抛出异常 + + // 4. 没有权限,抛出异常 log.info("[doBefore][userId({}) 要求权限({}) 实际权限({}) 数据校验错误]", // 打个 info 日志,方便后续排查问题、审计 - getUserId(), permissionLevel, toJsonString(userPermission)); + userId, permissionLevel, toJsonString(userPermission)); throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType)); } + /** + * 校验用户权限是否有效 + * + * @param userPermission 用户拥有的权限 + * @param permissionLevel 需要的权限级别 + * @return 是否有效 + */ + @SuppressWarnings("RedundantIfStatement") + private boolean isUserPermissionValid(CrmPermissionDO userPermission, Integer permissionLevel) { + // 2.1 情况一:如果自己是负责人,则默认有所有权限 + if (CrmPermissionLevelEnum.isOwner(userPermission.getLevel())) { + return true; + } + // 2.2 情况二:校验自己是否有读权限 + if (CrmPermissionLevelEnum.isRead(permissionLevel)) { + if (CrmPermissionLevelEnum.isRead(userPermission.getLevel()) // 校验当前用户是否有读权限 + || CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 + return true; + } + } + // 2.3 情况三:校验自己是否有写权限 + if (CrmPermissionLevelEnum.isWrite(permissionLevel)) { + if (CrmPermissionLevelEnum.isWrite(userPermission.getLevel())) { // 校验当前用户是否有写权限 + return true; + } + } + return false; + } + /** * 获得用户编号 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java index b84c6d51c..26d08361e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueService.java @@ -8,8 +8,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; import jakarta.validation.Valid; import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; /** * 线索 Service 接口 @@ -57,14 +55,6 @@ public interface CrmClueService { */ CrmClueDO getClue(Long id); - /** - * 获得线索列表 - * - * @param ids 编号 - * @return 线索列表 - */ - List getClueList(Collection ids, Long userId); - /** * 获得线索分页 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java index 6b40620bc..c8c850ab4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.crm.service.clue; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -32,7 +31,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; -import java.util.Collection; import java.util.List; import java.util.Objects; @@ -114,7 +112,7 @@ public class CrmClueServiceImpl implements CrmClueService { private void validateRelationDataExists(CrmClueSaveReqVO reqVO) { // 校验负责人 if (Objects.nonNull(reqVO.getOwnerUserId()) && - Objects.isNull(adminUserApi.getUser(reqVO.getOwnerUserId()).getCheckedData())) { + Objects.isNull(adminUserApi.getUser(reqVO.getOwnerUserId()))) { throw exception(USER_NOT_EXISTS); } } @@ -220,14 +218,6 @@ public class CrmClueServiceImpl implements CrmClueService { return clueMapper.selectById(id); } - @Override - public List getClueList(Collection ids, Long userId) { - if (CollUtil.isEmpty(ids)) { - return ListUtil.empty(); - } - return clueMapper.selectBatchIds(ids, userId); - } - @Override public PageResult getCluePage(CrmCluePageReqVO pageReqVO, Long userId) { return clueMapper.selectPage(pageReqVO, userId); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java index a82be864c..d15a09b9b 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.crm.util; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO; import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; @@ -15,7 +14,6 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.github.yulichang.autoconfigure.MybatisPlusJoinProperties; import com.github.yulichang.wrapper.MPJLambdaWrapper; -import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @@ -39,37 +37,33 @@ public class CrmPermissionUtils { } /** - * 构造 CRM 数据类型数据分页查询条件 + * 构造 CRM 数据类型数据【分页】查询条件 * * @param query 连表查询对象 * @param bizType 数据类型 {@link CrmBizTypeEnum} * @param bizId 数据编号 * @param userId 用户编号 * @param sceneType 场景类型 - * @param pool 公海 */ public static , S> void appendPermissionCondition(T query, Integer bizType, SFunction bizId, - Long userId, Integer sceneType, Boolean pool) { + Long userId, Integer sceneType) { MybatisPlusJoinProperties mybatisPlusJoinProperties = SpringUtil.getBean(MybatisPlusJoinProperties.class); final String ownerUserIdField = mybatisPlusJoinProperties.getTableAlias() + ".owner_user_id"; - // 1. 构建数据权限连表条件 - if (!CrmPermissionUtils.isCrmAdmin() && ObjUtil.notEqual(pool, Boolean.TRUE)) { // 管理员,公海不需要数据权限 - query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) - .eq(CrmPermissionDO::getBizId, bizId) // 只能使用 SFunction 如果传 id 解析出来的 sql 不对 - .eq(CrmPermissionDO::getUserId, userId)); - } - // 2.1 场景一:我负责的数据 + // 场景一:我负责的数据 if (CrmSceneTypeEnum.isOwner(sceneType)) { query.eq(ownerUserIdField, userId); } - // 2.2 场景二:我参与的数据 + // 场景二:我参与的数据(我有读或写权限,并且不是负责人) if (CrmSceneTypeEnum.isInvolved(sceneType)) { + if (CrmPermissionUtils.isCrmAdmin()) { // 特殊逻辑:如果是超管,直接查询所有,不过滤数据权限 + return; + } query.innerJoin(CrmPermissionDO.class, on -> on.eq(CrmPermissionDO::getBizType, bizType) .eq(CrmPermissionDO::getBizId, bizId) .in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel())); query.ne(ownerUserIdField, userId); } - // 2.3 场景三:下属负责的数据 + // 场景三:下属负责的数据(下属是负责人) if (CrmSceneTypeEnum.isSubordinate(sceneType)) { AdminUserApi adminUserApi = SpringUtil.getBean(AdminUserApi.class); List subordinateUsers = adminUserApi.getUserListBySubordinate(userId).getCheckedData(); @@ -79,30 +73,6 @@ public class CrmPermissionUtils { query.in(ownerUserIdField, convertSet(subordinateUsers, AdminUserRespDTO::getId)); } } - - // 3. 拼接公海的查询条件 - if (ObjUtil.equal(pool, Boolean.TRUE)) { // 情况一:公海 - query.isNull(ownerUserIdField); - } else { // 情况二:不是公海 - query.isNotNull(ownerUserIdField); - } - } - - /** - * 构造 CRM 数据类型批量数据查询条件 - * - * @param query 连表查询对象 - * @param bizType 数据类型 {@link CrmBizTypeEnum} - * @param bizIds 数据编号 - * @param userId 用户编号 - */ - public static > void appendPermissionCondition(T query, Integer bizType, Collection bizIds, Long userId) { - if (isCrmAdmin()) {// 管理员不需要数据权限 - return; - } - query.innerJoin(CrmPermissionDO.class, on -> - on.eq(CrmPermissionDO::getBizType, bizType).in(CrmPermissionDO::getBizId, bizIds) - .eq(CollUtil.isNotEmpty(bizIds), CrmPermissionDO::getUserId, userId)); } }