Browse Source

crm-客户管理:完善客户、公海客户分页查询

puhui999 1 year ago
parent
commit
0d821d705d

+ 6 - 6
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmCustomerSceneEnum.java → yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneEnum.java

@@ -8,18 +8,18 @@ import lombok.Getter;
 import java.util.Arrays;
 
 /**
- * CRM 客户等级
+ * CRM 列表检索场景
  *
- * @author Wanwan
+ * @author HUIHUI
  */
 @Getter
 @AllArgsConstructor
-public enum CrmCustomerSceneEnum implements IntArrayValuable {
+public enum CrmSceneEnum implements IntArrayValuable {
 
-    OWNER(1, "我负责的客户"),
-    FOLLOW(2, "我关注的客户");
+    OWNER(1, "我负责的"),
+    FOLLOW(2, "我关注的");
 
-    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerSceneEnum::getType).toArray();
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneEnum::getType).toArray();
 
     /**
      * 场景类型

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

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.crm.controller.admin.customer;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -9,7 +10,6 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
 import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
 import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
-import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -51,8 +51,6 @@ public class CrmCustomerController {
     private DeptApi deptApi;
     @Resource
     private AdminUserApi adminUserApi;
-    @Resource
-    private CrmPermissionService permissionService;
 
     @PostMapping("/create")
     @Operation(summary = "创建客户")
@@ -119,20 +117,14 @@ public class CrmCustomerController {
         return success(true);
     }
 
-    // TODO @puhui999:可以在 CrmCustomerPageReqVO 里面加个 pool 参数,为 true 时,代表来自公海客户的分页
     @GetMapping("/page")
     @Operation(summary = "获得客户分页")
     @PreAuthorize("@ss.hasPermission('crm:customer:query')")
     public CommonResult<PageResult<CrmCustomerRespVO>> getCustomerPage(@Valid CrmCustomerPageReqVO pageVO) {
-        //PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(pageVO, getLoginUserId());
-        //if (CollUtil.isEmpty(pageResult.getList())) {
-        //    return success(PageResult.empty(pageResult.getTotal()));
-        //}
-        // 拼接数据
-        return convertPage(customerService.getCustomerPage(pageVO, getLoginUserId()));
-    }
-
-    private CommonResult<PageResult<CrmCustomerRespVO>> convertPage(PageResult<CrmCustomerDO> pageResult) {
+        PageResult<CrmCustomerDO> pageResult = customerService.getCustomerPage(pageVO, getLoginUserId());
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(PageResult.empty(pageResult.getTotal()));
+        }
         // 1.1 获取负责人详情
         Set<Long> userIds = convertSet(pageResult.getList(), CrmCustomerDO::getOwnerUserId);
         userIds.addAll(convertSet(pageResult.getList(), item -> Long.parseLong(item.getCreator()))); // 加入创建者
@@ -172,19 +164,19 @@ public class CrmCustomerController {
         return success(true);
     }
 
-    @PutMapping("/receive")
-    @Operation(summary = "领取公海客户")
-    // TODO @xiaqing:1)receiveCustomer 方法名字;2)cIds 改成 ids,要加下 @RequestParam,还有 swagger 注解;3)参数非空,使用 validator 校验;4)返回 true 即可;
-    @PreAuthorize("@ss.hasPermission('crm:customer:receive')")
-    public CommonResult<String> receiveByIds(List<Long> cIds) {
-        // 判断是否为空
-        if (CollectionUtils.isEmpty(cIds))
-            return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), GlobalErrorCodeConstants.BAD_REQUEST.getMsg());
-        // 领取公海任务
-        // TODO @xiaqing:userid,通过 controller 传递给 service,不要在 service 里面获取,无状态
-        customerService.receive(cIds);
-        return success("领取成功");
-    }
+    //@PutMapping("/receive")
+    //@Operation(summary = "领取公海客户")
+    //// TODO @xiaqing:1)receiveCustomer 方法名字;2)cIds 改成 ids,要加下 @RequestParam,还有 swagger 注解;3)参数非空,使用 validator 校验;4)返回 true 即可;
+    //@PreAuthorize("@ss.hasPermission('crm:customer:receive')")
+    //public CommonResult<String> receiveByIds(List<Long> cIds) {
+    //    // 判断是否为空
+    //    if (CollectionUtils.isEmpty(cIds))
+    //        return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), GlobalErrorCodeConstants.BAD_REQUEST.getMsg());
+    //    // 领取公海任务
+    //    // TODO @xiaqing:userid,通过 controller 传递给 service,不要在 service 里面获取,无状态
+    //    customerService.receive(cIds);
+    //    return success("领取成功");
+    //}
 
     // TODO @xiaqing:1)distributeCustomer 方法名;2)cIds 同上;3)参数校验,同上;4)ownerId 改成 ownerUserId,和别的模块统一;5)返回 true 即可;
     @PutMapping("/distributeByIds")

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

@@ -1,12 +1,14 @@
 package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import cn.iocoder.yudao.module.crm.enums.common.CrmCustomerSceneEnum;
+import cn.iocoder.yudao.module.crm.enums.common.CrmSceneEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
+import javax.validation.constraints.NotNull;
+
 @Schema(description = "管理后台 - CRM 客户分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -31,9 +33,13 @@ public class CrmCustomerPageReqVO extends PageParam {
     /**
      * 场景类型
      *
-     * 关联 {@link CrmCustomerSceneEnum}
+     * 关联 {@link CrmSceneEnum}
      */
     @Schema(description = "场景类型", example = "1")
     private Integer sceneType;
 
+    @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
+    @NotNull(message = "是否为公海数据不能为空")
+    private Boolean pool;
+
 }

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

@@ -7,13 +7,12 @@ import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
 import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
+import cn.iocoder.yudao.module.crm.enums.common.CrmSceneEnum;
 import cn.iocoder.yudao.module.crm.framework.enums.CrmBizTypeEnum;
-import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
 
-import java.util.Collection;
-
 /**
  * 客户 Mapper
  *
@@ -22,9 +21,30 @@ import java.util.Collection;
 @Mapper
 public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
 
-    default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Collection<Long> ids) {
-        return selectPage(pageReqVO, new LambdaQueryWrapperX<CrmCustomerDO>()
-                .inIfPresent(CrmCustomerDO::getId, ids)
+    default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO) {
+        LambdaQueryWrapperX<CrmCustomerDO> queryWrapperX = new LambdaQueryWrapperX<>();
+        if (pageReqVO.getPool()) { // 情况一:公海
+            queryWrapperX.isNull(CrmCustomerDO::getOwnerUserId);
+        } else {// 情况一:不是公海
+            queryWrapperX.isNotNull(CrmCustomerDO::getOwnerUserId);
+        }
+        return selectPage(pageReqVO, queryWrapperX
+                .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())
+                .eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile())
+                .eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId())
+                .eqIfPresent(CrmCustomerDO::getLevel, pageReqVO.getLevel())
+                .eqIfPresent(CrmCustomerDO::getSource, pageReqVO.getSource()));
+    }
+
+    default PageResult<CrmCustomerDO> selectPage1(CrmCustomerPageReqVO pageReqVO, Long userId) {
+        LambdaQueryWrapperX<CrmCustomerDO> queryWrapperX = new LambdaQueryWrapperX<>();
+        //queryWrapperX.sql
+        if (pageReqVO.getPool()) { // 情况一:公海
+            queryWrapperX.isNull(CrmCustomerDO::getOwnerUserId);
+        } else {// 情况一:不是公海
+            queryWrapperX.isNotNull(CrmCustomerDO::getOwnerUserId);
+        }
+        return selectPage(pageReqVO, queryWrapperX
                 .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())
                 .eqIfPresent(CrmCustomerDO::getMobile, pageReqVO.getMobile())
                 .eqIfPresent(CrmCustomerDO::getIndustryId, pageReqVO.getIndustryId())
@@ -33,11 +53,50 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
     }
 
     default PageResult<CrmCustomerDO> selectPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
-        // MyBatis Plus 查询
         IPage<CrmCustomerDO> mpPage = MyBatisUtils.buildPage(pageReqVO);
         MPJLambdaWrapperX<CrmCustomerDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
         // 构建数据权限连表条件
-        CrmPermissionUtils.builderLeftJoinQuery(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CUSTOMER.getType(), userId);
+        //CrmPermissionUtils.builderRightJoinQuery(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CUSTOMER.getType(), userId);
+        mpjLambdaWrapperX
+                //.rightJoin("(SELECT t1.biz_id FROM crm_permission t1 WHERE (t1.biz_type = 1 AND t1.user_id = 1)) t2 on t.id = t2.biz_id");
+                .rightJoin(CrmPermissionDO.class, CrmPermissionDO::getBizId, CrmCustomerDO::getId)
+                .eq(CrmPermissionDO::getBizType, CrmBizTypeEnum.CRM_CUSTOMER.getType())
+                .eq(CrmPermissionDO::getUserId, userId);
+        /** TODO @芋艿:
+         -- 常规连表-查询正常
+         | ==>  Preparing:
+         SELECT t.id, t.name, t.follow_up_status, t.lock_status, t.deal_status,
+         t.industry_id, t.level, t.source, t.mobile, t.telephone, t.website,
+         t.qq, t.wechat, t.email, t.description, t.remark, t.owner_user_id,
+         t.area_id, t.detail_address, t.contact_last_time, t.contact_next_time,
+         t.create_time, t.update_time, t.creator, t.updater, t.deleted
+         FROM crm_customer t RIGHT JOIN crm_permission t1 ON (t1.biz_id = t.id) AND t.tenant_id = 1
+         WHERE t.deleted = 0 AND t1.deleted = 0
+         AND (t1.biz_type = ? AND t1.user_id = ?
+         AND t.owner_user_id IS NOT NULL AND t.level = ?) AND t1.tenant_id = 1 LIMIT ?
+         | ==> Parameters: 2(Integer), 1(Long), 3(Integer), 10(Long)
+
+         -- 连接子查询-报错,但是复制到 navicat 是可以正常执行的
+         -- 区别点:常规连表会自动拼接租户 AND t.tenant_id = 1
+         SELECT
+         t.id,t.name,t.follow_up_status,t.lock_status,t.deal_status,t.industry_id,t.level,
+         t.source,t.mobile,t.telephone,t.website,t.qq,t.wechat,t.email,t.description,t.remark,
+         t.owner_user_id,t.area_id,t.detail_address,t.contact_last_time,t.contact_next_time,
+         t.create_time,t.update_time,t.creator,t.updater,t.deleted
+         FROM crm_customer t
+         RIGHT JOIN (SELECT t1.biz_id FROM crm_permission t1 WHERE (t1.biz_type = 2 AND t1.user_id = 1)) t2 on t.id = t2.biz_id
+         WHERE  t.deleted=0
+         AND (t.owner_user_id IS NOT NULL)
+         */
+        if (pageReqVO.getPool()) { // 情况一:公海
+            mpjLambdaWrapperX.isNull(CrmCustomerDO::getOwnerUserId);
+        } else {// 情况一:不是公海
+            mpjLambdaWrapperX.isNotNull(CrmCustomerDO::getOwnerUserId);
+        }
+        // TODO 场景数据过滤
+        if (CrmSceneEnum.isOwner(pageReqVO.getSceneType())) { // 场景一:我负责的数据
+            mpjLambdaWrapperX.eq(CrmCustomerDO::getOwnerUserId, userId);
+        }
         mpPage = selectJoinPage(mpPage, CrmCustomerDO.class, mpjLambdaWrapperX
                 .selectAll(CrmCustomerDO.class)
                 .likeIfPresent(CrmCustomerDO::getName, pageReqVO.getName())

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

@@ -39,6 +39,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     private CrmPermissionService crmPermissionService;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createCustomer(CrmCustomerCreateReqVO createReqVO, Long userId) {
         // 插入
         CrmCustomerDO customer = CrmCustomerConvert.INSTANCE.convert(createReqVO);
@@ -89,32 +90,19 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO, Long userId) {
-        //// 1.1 TODO 如果是超级管理员
-        //boolean admin = false;
-        //if (admin && ObjUtil.notEqual(userId, CrmPermissionDO.POOL_USER_ID)) {
-        //    return customerMapper.selectPage(pageReqVO, Collections.emptyList());
-        //}
-        //// 1.2 获取当前用户能看的分页数据
-        //// TODO @puhui999:如果业务的数据量比较大,in 太多可能有性能问题噢;看看是不是搞成 join 连表了;可以微信讨论下;
-        //List<CrmPermissionDO> permissions = crmPermissionService.getPermissionListByBizTypeAndUserId(
-        //        CrmBizTypeEnum.CRM_CUSTOMER.getType(), userId);
-        //// 1.3 TODO 场景数据过滤
-        //if (CrmCustomerSceneEnum.isOwner(pageReqVO.getSceneType())) { // 场景一:我负责的数据
-        //    permissions = CollectionUtils.filterList(permissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()));
-        //}
-        //Set<Long> ids = convertSet(permissions, CrmPermissionDO::getBizId);
-        //if (CollUtil.isEmpty(ids)) { // 没得说明没有什么给他看的
-        //    return PageResult.empty();
-        //}
-        //
-        //// 2. 获取客户分页数据
-        //return customerMapper.selectPage(pageReqVO, ids);
+        // 1.1. TODO 如果是超级管理员
+        boolean admin = false;
+        if (admin) {
+            return customerMapper.selectPage(pageReqVO);
+        }
+        // 1.2. 获取当前用户能看的分页数据
         return customerMapper.selectPage(pageReqVO, userId);
     }
 
     @Override
     public List<CrmCustomerDO> getCustomerList(CrmCustomerExportReqVO exportReqVO) {
         //return customerMapper.selectList(exportReqVO);
+        // TODO puhui999: 等数据权限完善后再实现
         return Collections.emptyList();
     }
 
@@ -161,13 +149,13 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void receive(List <Long> ids) {
-        transferCustomerOwner(ids,SecurityFrameworkUtils.getLoginUserId());
+    public void receive(List<Long> ids) {
+        transferCustomerOwner(ids, SecurityFrameworkUtils.getLoginUserId());
     }
 
     @Override
-    public void distributeByIds(List <Long> cIds, Long ownerId) {
-        transferCustomerOwner(cIds,ownerId);
+    public void distributeByIds(List<Long> cIds, Long ownerId) {
+        transferCustomerOwner(cIds, ownerId);
     }
 
     @Override
@@ -191,6 +179,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
     public void putPool(Long id) {
         // 1. 校验存在
@@ -214,7 +203,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
                 CrmPermissionLevelEnum.OWNER.getLevel());
     }
 
-    private void transferCustomerOwner(List <Long> cIds, Long ownerId){
+    private void transferCustomerOwner(List<Long> cIds, Long ownerId) {
         // 先一次性校验完成客户是否可用
         // TODO @xiaqing:批量一次性加载客户列表,然后去逐个校验;
         for (Long cId : cIds) {
@@ -228,8 +217,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
             validCustomerDeal(cId);
         }
         // TODO @xiaqing:每个客户更新的时候,where 条件,加上 owner_user_id is null,防止并发问题;
-        List<CrmCustomerDO> updateDos = new ArrayList <>();
-        for (Long cId : cIds){
+        List<CrmCustomerDO> updateDos = new ArrayList<>();
+        for (Long cId : cIds) {
             CrmCustomerDO customerDO = new CrmCustomerDO();
             customerDO.setId(cId);
             customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
@@ -239,19 +228,19 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
     }
 
     private void validCustomerOwnerExist(Long id) {
-        if (customerMapper.selectById(id).getOwnerUserId()!=null) {
+        if (customerMapper.selectById(id).getOwnerUserId() != null) {
             throw exception(CUSTOMER_OWNER_EXISTS);
         }
     }
 
     private void validCustomerIsLocked(Long id) {
-        if (customerMapper.selectById(id).getLockStatus() ==true) {
+        if (customerMapper.selectById(id).getLockStatus() == true) {
             throw exception(CUSTOMER_LOCKED);
         }
     }
 
     private void validCustomerDeal(Long id) {
-        if (customerMapper.selectById(id).getDealStatus() ==true) {
+        if (customerMapper.selectById(id).getDealStatus() == true) {
             throw exception(CUSTOMER_ALREADY_DEAL);
         }
     }

+ 3 - 6
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/util/CrmPermissionUtils.java

@@ -17,13 +17,10 @@ public class CrmPermissionUtils {
      * @param bizTyp           模块类型
      * @param userId           用户
      */
-    public static void builderLeftJoinQuery(MPJLambdaWrapper<?> mpjLambdaWrapper, Integer bizTyp, Long userId) {
+    public static void builderRightJoinQuery(MPJLambdaWrapper<?> mpjLambdaWrapper, Integer bizTyp, Long userId) {
+        String querySql = "(SELECT t1.biz_id FROM crm_permission t1 WHERE (t1.biz_type = {} AND t1.user_id = {})) t2 on t.id = t2.biz_id";
         // 默认主表别名是 t
-        mpjLambdaWrapper.leftJoin(StrUtil.format("(" +
-                "select p.biz_id from crm_permission p" +
-                " where p.biz_type = {} and p.user_id = {}" +
-                ") t2" +
-                " on t.id = t2.biz_id", bizTyp, userId));
+        mpjLambdaWrapper.rightJoin(StrUtil.format(querySql, bizTyp, userId));
     }
 
 }