Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/iot

# Conflicts:
#	yudao-dependencies/pom.xml
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java
#	yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java
This commit is contained in:
YunaiV
2025-01-28 03:54:16 +08:00
615 changed files with 18343 additions and 7604 deletions

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.crm.enums.business;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -13,13 +13,13 @@ import java.util.Arrays;
*/
@RequiredArgsConstructor
@Getter
public enum CrmBusinessEndStatusEnum implements IntArrayValuable {
public enum CrmBusinessEndStatusEnum implements ArrayValuable<Integer> {
WIN(1, "赢单"),
LOSE(2, "输单"),
INVALID(3, "无效");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBusinessEndStatusEnum::getStatus).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmBusinessEndStatusEnum::getStatus).toArray(Integer[]::new);
/**
* 场景类型
@@ -31,7 +31,7 @@ public enum CrmBusinessEndStatusEnum implements IntArrayValuable {
private final String name;
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.crm.enums.common;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -13,7 +13,7 @@ import java.util.Arrays;
*/
@RequiredArgsConstructor
@Getter
public enum CrmAuditStatusEnum implements IntArrayValuable {
public enum CrmAuditStatusEnum implements ArrayValuable<Integer> {
DRAFT(0, "未提交"),
PROCESS(10, "审批中"),
@@ -24,10 +24,10 @@ public enum CrmAuditStatusEnum implements IntArrayValuable {
private final Integer status;
private final String name;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmAuditStatusEnum::getStatus).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmAuditStatusEnum::getStatus).toArray(Integer[]::new);
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.enums.common;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -15,7 +15,7 @@ import java.util.Arrays;
*/
@RequiredArgsConstructor
@Getter
public enum CrmBizTypeEnum implements IntArrayValuable {
public enum CrmBizTypeEnum implements ArrayValuable<Integer> {
CRM_CLUE(1, "线索"),
CRM_CUSTOMER(2, "客户"),
@@ -27,7 +27,7 @@ public enum CrmBizTypeEnum implements IntArrayValuable {
CRM_RECEIVABLE_PLAN(8, "回款计划")
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBizTypeEnum::getType).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmBizTypeEnum::getType).toArray(Integer[]::new);
/**
* 类型
@@ -45,7 +45,7 @@ public enum CrmBizTypeEnum implements IntArrayValuable {
}
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.crm.enums.common;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -14,13 +14,13 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum CrmSceneTypeEnum implements IntArrayValuable {
public enum CrmSceneTypeEnum implements ArrayValuable<Integer> {
OWNER(1, "我负责的"),
INVOLVED(2, "我参与的"),
SUBORDINATE(3, "下属负责的");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneTypeEnum::getType).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmSceneTypeEnum::getType).toArray(Integer[]::new);
/**
* 场景类型
@@ -44,7 +44,7 @@ public enum CrmSceneTypeEnum implements IntArrayValuable {
}
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.crm.enums.customer;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -13,13 +13,13 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum CrmCustomerLevelEnum implements IntArrayValuable {
public enum CrmCustomerLevelEnum implements ArrayValuable<Integer> {
IMPORTANT(1, "A重点客户"),
GENERAL(2, "B普通客户"),
LOW_PRIORITY(3, "C非优先客户");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLevelEnum::getLevel).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmCustomerLevelEnum::getLevel).toArray(Integer[]::new);
/**
* 状态
@@ -31,7 +31,7 @@ public enum CrmCustomerLevelEnum implements IntArrayValuable {
private final String name;
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.enums.customer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -15,7 +15,7 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum CrmCustomerLimitConfigTypeEnum implements IntArrayValuable {
public enum CrmCustomerLimitConfigTypeEnum implements ArrayValuable<Integer> {
/**
* 拥有客户数限制
@@ -27,7 +27,7 @@ public enum CrmCustomerLimitConfigTypeEnum implements IntArrayValuable {
CUSTOMER_LOCK_LIMIT(2, "锁定客户数限制"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLimitConfigTypeEnum::getType).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmCustomerLimitConfigTypeEnum::getType).toArray(Integer[]::new);
/**
* 状态
@@ -45,7 +45,7 @@ public enum CrmCustomerLimitConfigTypeEnum implements IntArrayValuable {
}
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.crm.enums.permission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -17,13 +17,13 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum CrmPermissionLevelEnum implements IntArrayValuable {
public enum CrmPermissionLevelEnum implements ArrayValuable<Integer> {
OWNER(1, "负责人"),
READ(2, "只读"),
WRITE(3, "读写");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmPermissionLevelEnum::getLevel).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmPermissionLevelEnum::getLevel).toArray(Integer[]::new);
/**
* 级别
@@ -35,7 +35,7 @@ public enum CrmPermissionLevelEnum implements IntArrayValuable {
private final String name;
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.crm.enums.product;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -15,12 +15,12 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum CrmProductStatusEnum implements IntArrayValuable {
public enum CrmProductStatusEnum implements ArrayValuable<Integer> {
DISABLE(0, "下架"),
ENABLE(1, "上架");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmProductStatusEnum::getStatus).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmProductStatusEnum::getStatus).toArray(Integer[]::new);
/**
* 状态
@@ -32,7 +32,7 @@ public enum CrmProductStatusEnum implements IntArrayValuable {
private final String name;
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.crm.enums.receivable;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -13,7 +13,7 @@ import java.util.Arrays;
*/
@Getter
@AllArgsConstructor
public enum CrmReceivableReturnTypeEnum implements IntArrayValuable {
public enum CrmReceivableReturnTypeEnum implements ArrayValuable<Integer> {
CHECK(1, "支票"),
CASH(2, "现金"),
@@ -24,7 +24,7 @@ public enum CrmReceivableReturnTypeEnum implements IntArrayValuable {
WECHAT_PAY(7, "微信支付"),
OTHER(8, "其它");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmReceivableReturnTypeEnum::getType).toArray();
public static final Integer[] ARRAYS = Arrays.stream(values()).map(CrmReceivableReturnTypeEnum::getType).toArray(Integer[]::new);
/**
* 类型
@@ -36,7 +36,7 @@ public enum CrmReceivableReturnTypeEnum implements IntArrayValuable {
private final String name;
@Override
public int[] array() {
public Integer[] array() {
return ARRAYS;
}

View File

@@ -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;

View File

@@ -47,7 +47,7 @@ public interface CrmBusinessMapper extends BaseMapperX<CrmBusinessDO> {
MPJLambdaWrapperX<CrmBusinessDO> 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())

View File

@@ -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<CrmClueDO> {
MPJLambdaWrapperX<CrmClueDO> 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<CrmClueDO> {
return selectJoinPage(pageReqVO, CrmClueDO.class, query);
}
default List<CrmClueDO> selectBatchIds(Collection<Long> ids, Long userId) {
MPJLambdaWrapperX<CrmClueDO> 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<CrmClueDO> 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);

View File

@@ -56,7 +56,7 @@ public interface CrmContactMapper extends BaseMapperX<CrmContactDO> {
MPJLambdaWrapperX<CrmContactDO> 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())

View File

@@ -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<CrmContractDO> {
MPJLambdaWrapperX<CrmContractDO> 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<CrmContractDO> {
return selectJoinPage(pageReqVO, CrmContractDO.class, query);
}
default List<CrmContractDO> selectBatchIds(Collection<Long> ids, Long userId) {
MPJLambdaWrapperX<CrmContractDO> 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<CrmContractDO> {
MPJLambdaWrapperX<CrmContractDO> 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<CrmContractDO> {
MPJLambdaWrapperX<CrmContractDO> 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());

View File

@@ -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<CrmCustomerDO> {
default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long ownerUserId) {
MPJLambdaWrapperX<CrmCustomerDO> 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<CrmCustomerDO> {
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
}
default List<CrmCustomerDO> selectBatchIds(Collection<Long> ids, Long ownerUserId) {
MPJLambdaWrapperX<CrmCustomerDO> 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<CrmCustomerDO> {
}
default Long selectPutPoolRemindCustomerCount(CrmCustomerPageReqVO pageReqVO,
CrmCustomerPoolConfigDO poolConfigDO,
CrmCustomerPoolConfigDO poolConfig,
Long userId) {
final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfigDO, userId);
final MPJLambdaWrapperX<CrmCustomerDO> query = buildPutPoolRemindCustomerQuery(pageReqVO, poolConfig, userId);
return selectCount(query);
}
@@ -114,7 +108,7 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
MPJLambdaWrapperX<CrmCustomerDO> 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<CrmCustomerDO> {
MPJLambdaWrapperX<CrmCustomerDO> 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<CrmCustomerDO> {
MPJLambdaWrapperX<CrmCustomerDO> 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);

View File

@@ -48,7 +48,7 @@ public interface CrmReceivableMapper extends BaseMapperX<CrmReceivableDO> {
MPJLambdaWrapperX<CrmReceivableDO> 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<CrmReceivableDO> {
return selectJoinPage(pageReqVO, CrmReceivableDO.class, query);
}
default List<CrmReceivableDO> selectBatchIds(Collection<Long> ids, Long userId) {
MPJLambdaWrapperX<CrmReceivableDO> 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<CrmReceivableDO> 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);

View File

@@ -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<CrmReceivablePlanDO
MPJLambdaWrapperX<CrmReceivablePlanDO> 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())
@@ -62,32 +60,24 @@ public interface CrmReceivablePlanMapper extends BaseMapperX<CrmReceivablePlanDO
// Backlog: 回款提醒类型
LocalDateTime beginOfToday = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
if (CrmReceivablePlanPageReqVO.REMIND_TYPE_NEEDED.equals(pageReqVO.getRemindType())) { // 待回款
// 查询条件:未回款 + 提醒时间 <= 当前时间(反过来即当前时间 >= 提醒时间,已经到达提醒的时间点)
query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款
.lt(CrmReceivablePlanDO::getReturnTime, beginOfToday) // 已逾期
.lt(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒
} else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) { // 已逾期
.le(CrmReceivablePlanDO::getRemindTime, beginOfToday); // 今天开始提醒
} else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_EXPIRED.equals(pageReqVO.getRemindType())) { // 已逾期
// 查询条件:未回款 + 回款时间 < 当前时间(反过来即当前时间 > 回款时间,已经过了回款时间点)
query.isNull(CrmReceivablePlanDO::getReceivableId) // 未回款
.ge(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期
.lt(CrmReceivablePlanDO::getReturnTime, beginOfToday); // 已逾期
} else if (CrmReceivablePlanPageReqVO.REMIND_TYPE_RECEIVED.equals(pageReqVO.getRemindType())) { // 已回款
query.isNotNull(CrmReceivablePlanDO::getReceivableId);
}
return selectJoinPage(pageReqVO, CrmReceivablePlanDO.class, query);
}
default List<CrmReceivablePlanDO> selectBatchIds(Collection<Long> ids, Long userId) {
MPJLambdaWrapperX<CrmReceivablePlanDO> 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<CrmReceivablePlanDO> 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) // 未回款

View File

@@ -9,8 +9,10 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
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.util.CrmPermissionUtils;
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<AdminUserRespDTO> subordinateUserIds = adminUserApi.getUserListBySubordinate(userId);
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;
}
/**
* 获得用户编号
*

View File

@@ -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<CrmClueDO> getClueList(Collection<Long> ids, Long userId);
/**
* 获得线索分页
*

View File

@@ -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;
@@ -220,14 +218,6 @@ public class CrmClueServiceImpl implements CrmClueService {
return clueMapper.selectById(id);
}
@Override
public List<CrmClueDO> getClueList(Collection<Long> ids, Long userId) {
if (CollUtil.isEmpty(ids)) {
return ListUtil.empty();
}
return clueMapper.selectBatchIds(ids, userId);
}
@Override
public PageResult<CrmClueDO> getCluePage(CrmCluePageReqVO pageReqVO, Long userId) {
return clueMapper.selectPage(pageReqVO, userId);

View File

@@ -270,7 +270,7 @@ public class CrmContractServiceImpl implements CrmContractService {
}
@Override
@LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}",
@LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_FOLLOW_UP_SUB_TYPE, bizNo = "{{#id}}",
success = CRM_CONTRACT_FOLLOW_UP_SUCCESS)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE)
public void updateContractFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent) {

View File

@@ -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,34 @@ public class CrmPermissionUtils {
}
/**
* 构造 CRM 数据类型数据分页查询条件
* 构造 CRM 数据类型数据分页查询条件
*
* @param query 连表查询对象
* @param bizType 数据类型 {@link CrmBizTypeEnum}
* @param bizId 数据编号
* @param userId 用户编号
* @param sceneType 场景类型
* @param pool 公海
*/
public static <T extends MPJLambdaWrapper<?>, S> void appendPermissionCondition(T query, Integer bizType, SFunction<S, ?> 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()));
.in(CrmPermissionDO::getLevel, CrmPermissionLevelEnum.READ.getLevel(), CrmPermissionLevelEnum.WRITE.getLevel())
.eq(CrmPermissionDO::getUserId,userId));
query.ne(ownerUserIdField, userId);
}
// 2.3 场景三:下属负责的数据
// 场景三:下属负责的数据(下属是负责人)
if (CrmSceneTypeEnum.isSubordinate(sceneType)) {
AdminUserApi adminUserApi = SpringUtil.getBean(AdminUserApi.class);
List<AdminUserRespDTO> subordinateUsers = adminUserApi.getUserListBySubordinate(userId);
@@ -79,30 +74,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 <T extends MPJLambdaWrapper<?>> void appendPermissionCondition(T query, Integer bizType, Collection<Long> 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));
}
}