mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 07:11:52 +08:00
📖 CRM:code review 数据权限的实现
This commit is contained in:
parent
8f578a9a82
commit
23df8633f4
6
pom.xml
6
pom.xml
@ -15,12 +15,12 @@
|
|||||||
<!-- 各种 module 拓展 -->
|
<!-- 各种 module 拓展 -->
|
||||||
<module>yudao-module-system</module>
|
<module>yudao-module-system</module>
|
||||||
<module>yudao-module-infra</module>
|
<module>yudao-module-infra</module>
|
||||||
<!-- <module>yudao-module-member</module>-->
|
<module>yudao-module-member</module>
|
||||||
<!-- <module>yudao-module-bpm</module>-->
|
<!-- <module>yudao-module-bpm</module>-->
|
||||||
<!-- <module>yudao-module-report</module>-->
|
<!-- <module>yudao-module-report</module>-->
|
||||||
<!-- <module>yudao-module-mp</module>-->
|
<!-- <module>yudao-module-mp</module>-->
|
||||||
<!-- <module>yudao-module-pay</module>-->
|
<module>yudao-module-pay</module>
|
||||||
<!-- <module>yudao-module-mall</module>-->
|
<module>yudao-module-mall</module>
|
||||||
<module>yudao-module-crm</module>
|
<module>yudao-module-crm</module>
|
||||||
<!-- 示例项目 -->
|
<!-- 示例项目 -->
|
||||||
<!-- <module>yudao-example</module>-->
|
<!-- <module>yudao-example</module>-->
|
||||||
|
@ -48,8 +48,10 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
|
|||||||
return new PageResult<>(list, (long) list.size());
|
return new PageResult<>(list, (long) list.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MyBatis Plus Join 查询
|
||||||
IPage<D> mpPage = MyBatisUtils.buildPage(pageParam);
|
IPage<D> mpPage = MyBatisUtils.buildPage(pageParam);
|
||||||
mpPage = selectJoinPage(mpPage, clazz, lambdaWrapper);
|
mpPage = selectJoinPage(mpPage, clazz, lambdaWrapper);
|
||||||
|
// 转换返回
|
||||||
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
|
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,9 +17,8 @@ import java.util.Arrays;
|
|||||||
public enum CrmSceneTypeEnum implements IntArrayValuable {
|
public enum CrmSceneTypeEnum implements IntArrayValuable {
|
||||||
|
|
||||||
OWNER(1, "我负责的"),
|
OWNER(1, "我负责的"),
|
||||||
FOLLOW(2, "我关注的"),
|
INVOLVED(2, "我参与的"),
|
||||||
INVOLVED(3, "我参与的"),
|
SUBORDINATE(3, "下属负责的");
|
||||||
SUBORDINATE(4, "下属负责的");
|
|
||||||
|
|
||||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneTypeEnum::getType).toArray();
|
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneTypeEnum::getType).toArray();
|
||||||
|
|
||||||
@ -36,10 +35,6 @@ public enum CrmSceneTypeEnum implements IntArrayValuable {
|
|||||||
return ObjUtil.equal(OWNER.getType(), type);
|
return ObjUtil.equal(OWNER.getType(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFollow(Integer type) {
|
|
||||||
return ObjUtil.equal(FOLLOW.getType(), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isInvolved(Integer type) {
|
public static boolean isInvolved(Integer type) {
|
||||||
return ObjUtil.equal(INVOLVED.getType(), type);
|
return ObjUtil.equal(INVOLVED.getType(), type);
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,9 @@ public class CrmBusinessPageReqVO extends PageParam {
|
|||||||
@Schema(description = "客户编号", example = "10795")
|
@Schema(description = "客户编号", example = "10795")
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据
|
||||||
|
@ -23,12 +23,9 @@ public class CrmCluePageReqVO extends PageParam {
|
|||||||
@Schema(description = "手机号", example = "18000000000")
|
@Schema(description = "手机号", example = "18000000000")
|
||||||
private String mobile;
|
private String mobile;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据
|
||||||
|
@ -35,12 +35,9 @@ public class CrmContactPageReqVO extends PageParam {
|
|||||||
@Schema(description = "微信", example = "zzZ98373")
|
@Schema(description = "微信", example = "zzZ98373")
|
||||||
private String wechat;
|
private String wechat;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据
|
||||||
|
@ -26,14 +26,11 @@ public class CrmContractPageReqVO extends PageParam {
|
|||||||
@Schema(description = "商机编号", example = "10864")
|
@Schema(description = "商机编号", example = "10864")
|
||||||
private Long businessId;
|
private Long businessId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据 TODO @puhui999:合同没有公海。目前只有【客户】【线索】有公海,其它都没
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,9 @@ public class CrmCustomerPageReqVO extends PageParam {
|
|||||||
@Schema(description = "客户来源", example = "1")
|
@Schema(description = "客户来源", example = "1")
|
||||||
private Integer source;
|
private Integer source;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据
|
||||||
|
@ -21,12 +21,9 @@ public class CrmReceivablePlanPageReqVO extends PageParam {
|
|||||||
@Schema(description = "合同名称", example = "3473")
|
@Schema(description = "合同名称", example = "3473")
|
||||||
private Long contractId;
|
private Long contractId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据
|
||||||
|
@ -23,12 +23,9 @@ public class CrmReceivablePageReqVO extends PageParam {
|
|||||||
@Schema(description = "客户编号", example = "4963")
|
@Schema(description = "客户编号", example = "4963")
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 场景类型,为 null 时则表示全部
|
|
||||||
*/
|
|
||||||
@Schema(description = "场景类型", example = "1")
|
@Schema(description = "场景类型", example = "1")
|
||||||
@InEnum(CrmSceneTypeEnum.class)
|
@InEnum(CrmSceneTypeEnum.class)
|
||||||
private Integer sceneType;
|
private Integer sceneType; // 场景类型,为 null 时则表示全部
|
||||||
|
|
||||||
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
@Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
|
||||||
private Boolean pool; // null 则表示为不是公海数据
|
private Boolean pool; // null 则表示为不是公海数据
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* 提供 RESTful API 给前端:
|
||||||
|
* 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
|
||||||
|
* 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.module.crm.controller;
|
@ -38,9 +38,7 @@ public interface CrmBusinessConvert {
|
|||||||
|
|
||||||
List<CrmBusinessExcelVO> convertList02(List<CrmBusinessDO> list);
|
List<CrmBusinessExcelVO> convertList02(List<CrmBusinessDO> list);
|
||||||
|
|
||||||
@Mappings({
|
@Mapping(target = "bizId", source = "reqVO.id")
|
||||||
@Mapping(target = "bizId", source = "reqVO.id")
|
|
||||||
})
|
|
||||||
CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId);
|
CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId);
|
||||||
|
|
||||||
default PageResult<CrmBusinessRespVO> convertPage(PageResult<CrmBusinessDO> page, List<CrmCustomerDO> customerList,
|
default PageResult<CrmBusinessRespVO> convertPage(PageResult<CrmBusinessDO> page, List<CrmCustomerDO> customerList,
|
||||||
|
@ -54,9 +54,7 @@ public interface CrmCustomerConvert {
|
|||||||
|
|
||||||
List<CrmCustomerExcelVO> convertList02(List<CrmCustomerDO> list);
|
List<CrmCustomerExcelVO> convertList02(List<CrmCustomerDO> list);
|
||||||
|
|
||||||
@Mappings({
|
@Mapping(target = "bizId", source = "reqVO.id")
|
||||||
@Mapping(target = "bizId", source = "reqVO.id")
|
|
||||||
})
|
|
||||||
CrmPermissionTransferReqBO convert(CrmCustomerTransferReqVO reqVO, Long userId);
|
CrmPermissionTransferReqBO convert(CrmCustomerTransferReqVO reqVO, Long userId);
|
||||||
|
|
||||||
PageResult<CrmCustomerRespVO> convertPage(PageResult<CrmCustomerDO> page);
|
PageResult<CrmCustomerRespVO> convertPage(PageResult<CrmCustomerDO> page);
|
||||||
|
@ -28,22 +28,23 @@ public interface CrmBusinessMapper extends BaseMapperX<CrmBusinessDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<CrmBusinessDO> selectPage(CrmBusinessPageReqVO pageReqVO, Long userId) {
|
default PageResult<CrmBusinessDO> selectPage(CrmBusinessPageReqVO pageReqVO, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmBusinessDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmBusinessDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderPageQuery(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_BUSINESS.getType(), CrmBusinessDO::getId,
|
CrmQueryWrapperUtils.builderPageQuery(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), CrmBusinessDO::getId,
|
||||||
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
||||||
mpjLambdaWrapperX.selectAll(CrmBusinessDO.class)
|
// 拼接自身的查询条件
|
||||||
|
query.selectAll(CrmBusinessDO.class)
|
||||||
.eqIfPresent(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号
|
.eqIfPresent(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号
|
||||||
.likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName())
|
.likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName())
|
||||||
.orderByDesc(CrmBusinessDO::getId);
|
.orderByDesc(CrmBusinessDO::getId);
|
||||||
return selectJoinPage(pageReqVO, CrmBusinessDO.class, mpjLambdaWrapperX);
|
return selectJoinPage(pageReqVO, CrmBusinessDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmBusinessDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
default List<CrmBusinessDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmBusinessDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmBusinessDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderListQueryBatch(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_BUSINESS.getType(), ids, userId);
|
CrmQueryWrapperUtils.builderListQueryBatch(query, CrmBizTypeEnum.CRM_BUSINESS.getType(), ids, userId);
|
||||||
return selectJoinList(CrmBusinessDO.class, mpjLambdaWrapperX);
|
return selectJoinList(CrmBusinessDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,23 +28,24 @@ public interface CrmClueMapper extends BaseMapperX<CrmClueDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<CrmClueDO> selectPage(CrmCluePageReqVO pageReqVO, Long userId) {
|
default PageResult<CrmClueDO> selectPage(CrmCluePageReqVO pageReqVO, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmClueDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmClueDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderPageQuery(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_LEADS.getType(), CrmClueDO::getId,
|
CrmQueryWrapperUtils.builderPageQuery(query, CrmBizTypeEnum.CRM_LEADS.getType(), CrmClueDO::getId,
|
||||||
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
||||||
mpjLambdaWrapperX.selectAll(CrmClueDO.class)
|
// 拼接自身的查询条件
|
||||||
|
query.selectAll(CrmClueDO.class)
|
||||||
.likeIfPresent(CrmClueDO::getName, pageReqVO.getName())
|
.likeIfPresent(CrmClueDO::getName, pageReqVO.getName())
|
||||||
.likeIfPresent(CrmClueDO::getTelephone, pageReqVO.getTelephone())
|
.likeIfPresent(CrmClueDO::getTelephone, pageReqVO.getTelephone())
|
||||||
.likeIfPresent(CrmClueDO::getMobile, pageReqVO.getMobile())
|
.likeIfPresent(CrmClueDO::getMobile, pageReqVO.getMobile())
|
||||||
.orderByDesc(CrmClueDO::getId);
|
.orderByDesc(CrmClueDO::getId);
|
||||||
return selectJoinPage(pageReqVO, CrmClueDO.class, mpjLambdaWrapperX);
|
return selectJoinPage(pageReqVO, CrmClueDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmClueDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
default List<CrmClueDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmClueDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmClueDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderListQueryBatch(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_LEADS.getType(), ids, userId);
|
CrmQueryWrapperUtils.builderListQueryBatch(query, CrmBizTypeEnum.CRM_LEADS.getType(), ids, userId);
|
||||||
return selectJoinList(CrmClueDO.class, mpjLambdaWrapperX);
|
return selectJoinList(CrmClueDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,12 @@ public interface CrmContactMapper extends BaseMapperX<CrmContactDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<CrmContactDO> selectPage(CrmContactPageReqVO pageReqVO, Long userId) {
|
default PageResult<CrmContactDO> selectPage(CrmContactPageReqVO pageReqVO, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmContactDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmContactDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderPageQuery(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CONTACT.getType(), CrmContactDO::getId,
|
CrmQueryWrapperUtils.builderPageQuery(query, CrmBizTypeEnum.CRM_CONTACT.getType(), CrmContactDO::getId,
|
||||||
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
||||||
mpjLambdaWrapperX.selectAll(CrmContactDO.class)
|
// 拼接自身的查询条件
|
||||||
|
query.selectAll(CrmContactDO.class)
|
||||||
.eqIfPresent(CrmContactDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号
|
.eqIfPresent(CrmContactDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号
|
||||||
.likeIfPresent(CrmContactDO::getName, pageReqVO.getName())
|
.likeIfPresent(CrmContactDO::getName, pageReqVO.getName())
|
||||||
.eqIfPresent(CrmContactDO::getMobile, pageReqVO.getMobile())
|
.eqIfPresent(CrmContactDO::getMobile, pageReqVO.getMobile())
|
||||||
@ -41,14 +42,14 @@ public interface CrmContactMapper extends BaseMapperX<CrmContactDO> {
|
|||||||
.eqIfPresent(CrmContactDO::getQq, pageReqVO.getQq())
|
.eqIfPresent(CrmContactDO::getQq, pageReqVO.getQq())
|
||||||
.eqIfPresent(CrmContactDO::getWechat, pageReqVO.getWechat())
|
.eqIfPresent(CrmContactDO::getWechat, pageReqVO.getWechat())
|
||||||
.orderByDesc(CrmContactDO::getId);
|
.orderByDesc(CrmContactDO::getId);
|
||||||
return selectJoinPage(pageReqVO, CrmContactDO.class, mpjLambdaWrapperX);
|
return selectJoinPage(pageReqVO, CrmContactDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmContactDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
default List<CrmContactDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmContactDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmContactDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderListQueryBatch(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CONTACT.getType(), ids, userId);
|
CrmQueryWrapperUtils.builderListQueryBatch(query, CrmBizTypeEnum.CRM_CONTACT.getType(), ids, userId);
|
||||||
return selectJoinList(CrmContactDO.class, mpjLambdaWrapperX);
|
return selectJoinList(CrmContactDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,24 +28,25 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
|
default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmCustomerDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderPageQuery(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CUSTOMER.getType(), CrmCustomerDO::getId,
|
CrmQueryWrapperUtils.builderPageQuery(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), CrmCustomerDO::getId,
|
||||||
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
userId, pageReqVO.getSceneType(), pageReqVO.getPool());
|
||||||
mpjLambdaWrapperX.selectAll(CrmCustomerDO.class)
|
// 拼接自身的查询条件
|
||||||
|
query.selectAll(CrmCustomerDO.class)
|
||||||
.likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())
|
.likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())
|
||||||
.eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile())
|
.eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile())
|
||||||
.eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId())
|
.eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId())
|
||||||
.eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel())
|
.eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel())
|
||||||
.eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource());
|
.eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource());
|
||||||
return selectJoinPage(pageReqVO, CrmCustomerDO.class, mpjLambdaWrapperX);
|
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmCustomerDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
default List<CrmCustomerDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmCustomerDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmCustomerDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.builderListQueryBatch(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, userId);
|
CrmQueryWrapperUtils.builderListQueryBatch(query, CrmBizTypeEnum.CRM_CUSTOMER.getType(), ids, userId);
|
||||||
return selectJoinList(CrmCustomerDO.class, mpjLambdaWrapperX);
|
return selectJoinList(CrmCustomerDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -112,9 +112,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<CrmBusinessDO> getBusinessPageByCustomer(CrmBusinessPageReqVO pageReqVO, Long userId) {
|
public PageResult<CrmBusinessDO> getBusinessPageByCustomer(CrmBusinessPageReqVO pageReqVO, Long userId) {
|
||||||
// 校验客户存在
|
// 校验客户存在 TODO @puhui999:这里不校验
|
||||||
customerService.validateCustomer(pageReqVO.getCustomerId());
|
customerService.validateCustomer(pageReqVO.getCustomerId());
|
||||||
|
// TODO @puhui999:感觉这里貌似不太复用用 selectPage,因为他可能没商机权限,只是因为能看 customer,所以可以看到列表
|
||||||
return businessMapper.selectPage(pageReqVO, userId);
|
return businessMapper.selectPage(pageReqVO, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ public class CrmClueServiceImpl implements CrmClueService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmClueMapper clueMapper;
|
private CrmClueMapper clueMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmCustomerService customerService;
|
private CrmCustomerService customerService;
|
||||||
@Resource
|
@Resource
|
||||||
|
@ -137,7 +137,7 @@ public class CrmContactServiceImpl implements CrmContactService {
|
|||||||
public PageResult<CrmContactDO> getContactPageByCustomerId(CrmContactPageReqVO pageVO, Long userId) {
|
public PageResult<CrmContactDO> getContactPageByCustomerId(CrmContactPageReqVO pageVO, Long userId) {
|
||||||
// 校验用户存在
|
// 校验用户存在
|
||||||
customerService.validateCustomer(pageVO.getCustomerId());
|
customerService.validateCustomer(pageVO.getCustomerId());
|
||||||
|
// TODO @puhui999:getBusinessPageByCustomer 同理
|
||||||
return contactMapper.selectPage(pageVO, userId);
|
return contactMapper.selectPage(pageVO, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +126,9 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void deletePermission(Integer bizType, Long bizId, Integer level) {
|
public void deletePermission(Integer bizType, Long bizId, Integer level) {
|
||||||
|
// 校验存在
|
||||||
List<CrmPermissionDO> permissions = crmPermissionMapper.selectListByBizTypeAndBizIdAndLevel(
|
List<CrmPermissionDO> permissions = crmPermissionMapper.selectListByBizTypeAndBizIdAndLevel(
|
||||||
bizType, bizId, level);
|
bizType, bizId, level);
|
||||||
// 校验存在
|
|
||||||
if (CollUtil.isEmpty(permissions)) {
|
if (CollUtil.isEmpty(permissions)) {
|
||||||
throw exception(CRM_PERMISSION_NOT_EXISTS);
|
throw exception(CRM_PERMISSION_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
@ -139,6 +139,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePermission(Integer bizType, Long bizId) {
|
public void deletePermission(Integer bizType, Long bizId) {
|
||||||
|
// TODO @puhui999:这种直接写条件删除;不需要先查询,再删除
|
||||||
List<CrmPermissionDO> permissionList = crmPermissionMapper.selectByBizTypeAndBizId(bizType, bizId);
|
List<CrmPermissionDO> permissionList = crmPermissionMapper.selectByBizTypeAndBizId(bizType, bizId);
|
||||||
if (CollUtil.isEmpty(permissionList)) {
|
if (CollUtil.isEmpty(permissionList)) {
|
||||||
return;
|
return;
|
||||||
|
@ -26,67 +26,74 @@ public class CrmQueryWrapperUtils {
|
|||||||
/**
|
/**
|
||||||
* 构造 CRM 数据类型数据分页查询条件
|
* 构造 CRM 数据类型数据分页查询条件
|
||||||
*
|
*
|
||||||
* @param queryMapper 连表查询对象
|
* @param query 连表查询对象
|
||||||
* @param bizType 数据类型 {@link CrmBizTypeEnum}
|
* @param bizType 数据类型 {@link CrmBizTypeEnum}
|
||||||
* @param bizId 数据编号
|
* @param bizId 数据编号
|
||||||
* @param userId 用户编号
|
* @param userId 用户编号
|
||||||
* @param sceneType 场景类型
|
* @param sceneType 场景类型
|
||||||
* @param pool 公海
|
* @param pool 公海
|
||||||
*/
|
*/
|
||||||
public static <T extends MPJLambdaWrapper<?>, S> void builderPageQuery(
|
// TODO @puhui999:bizId 直接传递会不会简单点
|
||||||
T queryMapper, Integer bizType, SFunction<S, ?> bizId, Long userId, Integer sceneType, Boolean pool) {
|
// TODO @puhui999:builderPageQuery 应该不仅仅适合于分页查询,应该适用于所有的查询;可以改成 appendPermissionCondition
|
||||||
|
public static <T extends MPJLambdaWrapper<?>, S> void builderPageQuery(T query, Integer bizType, SFunction<S, ?> bizId,
|
||||||
|
Long userId, Integer sceneType, Boolean pool) {
|
||||||
// 1. 构建数据权限连表条件
|
// 1. 构建数据权限连表条件
|
||||||
if (ObjUtil.notEqual(validateAdminUser(userId), Boolean.TRUE)) { // 管理员不需要数据权限
|
if (ObjUtil.notEqual(validateAdminUser(userId), Boolean.TRUE)) { // 管理员不需要数据权限
|
||||||
queryMapper.innerJoin(CrmPermissionDO.class, on ->
|
query.innerJoin(CrmPermissionDO.class, on ->
|
||||||
on.eq(CrmPermissionDO::getBizType, bizType).eq(CrmPermissionDO::getBizId, bizId)
|
on.eq(CrmPermissionDO::getBizType, bizType).eq(CrmPermissionDO::getBizId, bizId)
|
||||||
.eq(CrmPermissionDO::getUserId, userId));
|
.eq(CrmPermissionDO::getUserId, userId));
|
||||||
}
|
}
|
||||||
// 1.2 场景一:我负责的数据
|
// 2.1 场景一:我负责的数据
|
||||||
if (CrmSceneTypeEnum.isOwner(sceneType)) {
|
if (CrmSceneTypeEnum.isOwner(sceneType)) {
|
||||||
queryMapper.eq("owner_user_id", userId);
|
query.eq("owner_user_id", userId);
|
||||||
}
|
}
|
||||||
// 1.3 场景一:我参与的数据
|
// 2.2 场景二:我参与的数据
|
||||||
|
// TODO @puhui999:参与,指的是有读写权限噢;可以把 1. 的合并到 2.2 里;因为 2.1 不需要;
|
||||||
if (CrmSceneTypeEnum.isInvolved(sceneType)) {
|
if (CrmSceneTypeEnum.isInvolved(sceneType)) {
|
||||||
queryMapper.ne("owner_user_id", userId);
|
query.ne("owner_user_id", userId);
|
||||||
}
|
}
|
||||||
// 1.4 场景二:下属负责的数据
|
// 2.3 场景三:下属负责的数据
|
||||||
if (CrmSceneTypeEnum.isSubordinate(sceneType)) {
|
if (CrmSceneTypeEnum.isSubordinate(sceneType)) {
|
||||||
List<AdminUserRespDTO> subordinateUsers = getAdminUserApi().getUserListBySubordinate(userId);
|
List<AdminUserRespDTO> subordinateUsers = getAdminUserApi().getUserListBySubordinate(userId);
|
||||||
|
// TODO @puhui999:如果为空,不拼接,就是查询了所有数据呀?
|
||||||
if (CollUtil.isNotEmpty(subordinateUsers)) {
|
if (CollUtil.isNotEmpty(subordinateUsers)) {
|
||||||
queryMapper.in("owner_user_id", convertSet(subordinateUsers, AdminUserRespDTO::getId));
|
query.in("owner_user_id", convertSet(subordinateUsers, AdminUserRespDTO::getId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 拼接公海的查询条件
|
// 2. 拼接公海的查询条件
|
||||||
if (ObjUtil.equal(pool, Boolean.TRUE)) { // 情况一:公海
|
if (ObjUtil.equal(pool, Boolean.TRUE)) { // 情况一:公海
|
||||||
queryMapper.isNull("owner_user_id");
|
query.isNull("owner_user_id");
|
||||||
} else { // 情况二:不是公海
|
} else { // 情况二:不是公海
|
||||||
queryMapper.isNotNull("owner_user_id");
|
query.isNotNull("owner_user_id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造 CRM 数据类型批量数据查询条件
|
* 构造 CRM 数据类型批量数据查询条件
|
||||||
*
|
*
|
||||||
* @param queryMapper 连表查询对象
|
* @param query 连表查询对象
|
||||||
* @param bizType 数据类型 {@link CrmBizTypeEnum}
|
* @param bizType 数据类型 {@link CrmBizTypeEnum}
|
||||||
* @param bizIds 数据编号
|
* @param bizIds 数据编号
|
||||||
* @param userId 用户编号
|
* @param userId 用户编号
|
||||||
*/
|
*/
|
||||||
public static <T extends MPJLambdaWrapper<?>, S> void builderListQueryBatch(
|
// TODO @puhui999:可以改成 appendPermissionCondition
|
||||||
T queryMapper, Integer bizType, Collection<Long> bizIds, Long userId) {
|
// TODO @puhui999:S 是不是可以删除
|
||||||
// 1. 构建数据权限连表条件
|
public static <T extends MPJLambdaWrapper<?>, S> void builderListQueryBatch(T query, Integer bizType, Collection<Long> bizIds, Long userId) {
|
||||||
|
// TODO @puhui999:这里先 if return 简单点
|
||||||
if (ObjUtil.notEqual(validateAdminUser(userId), Boolean.TRUE)) { // 管理员不需要数据权限
|
if (ObjUtil.notEqual(validateAdminUser(userId), Boolean.TRUE)) { // 管理员不需要数据权限
|
||||||
queryMapper.innerJoin(CrmPermissionDO.class, on ->
|
query.innerJoin(CrmPermissionDO.class, on ->
|
||||||
on.eq(CrmPermissionDO::getBizType, bizType).in(CrmPermissionDO::getBizId, bizIds)
|
on.eq(CrmPermissionDO::getBizType, bizType).in(CrmPermissionDO::getBizId, bizIds)
|
||||||
.in(CollUtil.isNotEmpty(bizIds), CrmPermissionDO::getUserId, userId));
|
.in(CollUtil.isNotEmpty(bizIds), CrmPermissionDO::getUserId, userId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:需要加个变量,不用每次都拿哈;
|
||||||
private static AdminUserApi getAdminUserApi() {
|
private static AdminUserApi getAdminUserApi() {
|
||||||
return SpringUtil.getBean(AdminUserApi.class);
|
return SpringUtil.getBean(AdminUserApi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:需要实现;
|
||||||
/**
|
/**
|
||||||
* 校验用户是否是管理员
|
* 校验用户是否是管理员
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,6 @@ public interface AdminUserApi {
|
|||||||
*/
|
*/
|
||||||
AdminUserRespDTO getUser(Long id);
|
AdminUserRespDTO getUser(Long id);
|
||||||
|
|
||||||
// TODO @puhui999:这里返回 List<AdminUserRespDTO> 方法名可以改成 getUserListBySubordinate
|
|
||||||
/**
|
/**
|
||||||
* 通过用户 ID 查询用户下属
|
* 通过用户 ID 查询用户下属
|
||||||
*
|
*
|
||||||
|
@ -39,13 +39,11 @@ public class AdminUserApiImpl implements AdminUserApi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AdminUserRespDTO> getUserListBySubordinate(Long userId) {
|
public List<AdminUserRespDTO> getUserListBySubordinate(Long userId) {
|
||||||
// 1. 获取用户信息
|
// 1.1 获取用户负责的部门
|
||||||
AdminUserDO user = userService.getUser(userId);
|
AdminUserDO user = userService.getUser(userId);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 获取用户负责的部门
|
|
||||||
ArrayList<Long> deptIds = new ArrayList<>();
|
ArrayList<Long> deptIds = new ArrayList<>();
|
||||||
DeptDO dept = deptService.getDept(user.getDeptId());
|
DeptDO dept = deptService.getDept(user.getDeptId());
|
||||||
if (dept == null) {
|
if (dept == null) {
|
||||||
@ -54,13 +52,14 @@ public class AdminUserApiImpl implements AdminUserApi {
|
|||||||
if (ObjUtil.notEqual(dept.getLeaderUserId(), userId)) { // 校验为负责人
|
if (ObjUtil.notEqual(dept.getLeaderUserId(), userId)) { // 校验为负责人
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
deptIds.add(dept.getId()); // 加入此部门
|
deptIds.add(dept.getId());
|
||||||
// 2.2 获取所有子部门
|
// 1.2 获取所有子部门
|
||||||
List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
|
List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
|
||||||
if (CollUtil.isNotEmpty(childDeptList)) {
|
if (CollUtil.isNotEmpty(childDeptList)) {
|
||||||
deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
|
deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
|
||||||
}
|
}
|
||||||
// 2.3 获取用户信息
|
|
||||||
|
// 2. 获取部门对应的用户信息
|
||||||
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
|
List<AdminUserDO> users = userService.getUserListByDeptIds(deptIds);
|
||||||
users.removeIf(item -> ObjUtil.equal(item.getId(), userId)); // 排除自己
|
users.removeIf(item -> ObjUtil.equal(item.getId(), userId)); // 排除自己
|
||||||
return BeanUtils.toBean(users, AdminUserRespDTO.class);
|
return BeanUtils.toBean(users, AdminUserRespDTO.class);
|
||||||
|
@ -37,11 +37,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 会员中心。默认注释,保证编译速度 -->
|
<!-- 会员中心。默认注释,保证编译速度 -->
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<!-- <artifactId>yudao-module-member-biz</artifactId>-->
|
<artifactId>yudao-module-member-biz</artifactId>
|
||||||
<!-- <version>${revision}</version>-->
|
<version>${revision}</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
|
|
||||||
<!-- 数据报表。默认注释,保证编译速度 -->
|
<!-- 数据报表。默认注释,保证编译速度 -->
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
@ -56,11 +56,11 @@
|
|||||||
<!-- <version>${revision}</version>-->
|
<!-- <version>${revision}</version>-->
|
||||||
<!-- </dependency>-->
|
<!-- </dependency>-->
|
||||||
<!-- 支付服务。默认注释,保证编译速度 -->
|
<!-- 支付服务。默认注释,保证编译速度 -->
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<!-- <artifactId>yudao-module-pay-biz</artifactId>-->
|
<artifactId>yudao-module-pay-biz</artifactId>
|
||||||
<!-- <version>${revision}</version>-->
|
<version>${revision}</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
|
|
||||||
<!-- 微信公众号模块。默认注释,保证编译速度 -->
|
<!-- 微信公众号模块。默认注释,保证编译速度 -->
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
@ -70,26 +70,26 @@
|
|||||||
<!-- </dependency>-->
|
<!-- </dependency>-->
|
||||||
|
|
||||||
<!-- 商城相关模块。默认注释,保证编译速度-->
|
<!-- 商城相关模块。默认注释,保证编译速度-->
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<!-- <artifactId>yudao-module-promotion-biz</artifactId>-->
|
<artifactId>yudao-module-promotion-biz</artifactId>
|
||||||
<!-- <version>${revision}</version>-->
|
<version>${revision}</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<!-- <artifactId>yudao-module-product-biz</artifactId>-->
|
<artifactId>yudao-module-product-biz</artifactId>
|
||||||
<!-- <version>${revision}</version>-->
|
<version>${revision}</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<!-- <artifactId>yudao-module-trade-biz</artifactId>-->
|
<artifactId>yudao-module-trade-biz</artifactId>
|
||||||
<!-- <version>${revision}</version>-->
|
<version>${revision}</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<dependency>
|
||||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<!-- <artifactId>yudao-module-statistics-biz</artifactId>-->
|
<artifactId>yudao-module-statistics-biz</artifactId>
|
||||||
<!-- <version>${revision}</version>-->
|
<version>${revision}</version>
|
||||||
<!-- </dependency>-->
|
</dependency>
|
||||||
|
|
||||||
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
Loading…
Reference in New Issue
Block a user