Răsfoiți Sursa

feat(customer): 添加客户跟进状态总览功能并完善联系人权限控制

- 新增CustomerStatusOverViewBO用于表示客户跟进状态总览数据
- 在SysCustomerFollowService中新增queryStatusOverViewData方法,用于按用户和客户查询跟进状态统计
- SysCustomerDataPrivateService查询客户详情时加入跟进状态总览数据,基于用户权限过滤数据
- SysCustomerDataPublicService查询产品总览时支持传入用户ID实现权限控制
- SysCustomerDetailBO新增statusOverviewData字段存储跟进状态总览数据
- 更新SysCustomerFollowService中queryProductOverViewData方法,增加用户维度过滤功能
- 联系人模块新增operUserId字段记录添加联系人用户,完善删除权限校验逻辑
- 在SysCustomerPersonService中实现删除权限检查,只有管理员或创建人可删除联系人
- 查询联系人时增加deleteStatus标志,指示当前用户是否有删除权限
- 优化联系人查询条件,增加对办公电话和创建人字段模糊匹配支持
zhangxf 1 lună în urmă
părinte
comite
6937800486

+ 4 - 0
src/main/java/com/jtzx/crm/module/sys/entity/SysCustomerPersonEntity.java

@@ -55,6 +55,10 @@ public class SysCustomerPersonEntity extends HelioBaseEntity<Long> {
     @TableField(value = "remark")
     private String remark;
 
+    @Schema(description = "添加联系人的用户id")
+    @TableField(value = "oper_user_id")
+    private Long operUserId;
+
     @Schema(description = "逻辑删除标识", title = "0=否 1=是")
     @TableField("del_flag")
     private Integer delFlag;

+ 33 - 0
src/main/java/com/jtzx/crm/module/sys/model/response/CustomerStatusOverViewBO.java

@@ -0,0 +1,33 @@
+package com.jtzx.crm.module.sys.model.response;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import lombok.experimental.SuperBuilder;
+
+import java.io.Serializable;
+
+
+/**
+ * 产品总览
+ */
+@Accessors(chain = true)
+@SuperBuilder
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class CustomerStatusOverViewBO implements Serializable {
+
+
+    @Schema(description = "状态名称")
+    private String statusName;
+
+    @Schema(description = "排序")
+    private Integer sortCode;
+
+    @Schema(description = "数量")
+    private Integer count;
+
+}

+ 3 - 0
src/main/java/com/jtzx/crm/module/sys/model/response/SysCustomerDetailBO.java

@@ -32,6 +32,9 @@ public class SysCustomerDetailBO implements Serializable {
     @Schema(description = "跟进产品总数")
     private Integer productCount;
 
+    @Schema(description = "跟进状态总览数据")
+    private List<CustomerStatusOverViewBO> statusOverviewData;
+
     @Schema(description = "跟进产品总览数据")
     private List<CustomerProductOverViewBO> productOverviewData;
 

+ 6 - 0
src/main/java/com/jtzx/crm/module/sys/model/response/SysCustomerPersonBO.java

@@ -61,4 +61,10 @@ public class SysCustomerPersonBO implements Serializable {
     @Schema(description = "备注")
     private String remark;
 
+    @Schema(description = "添加联系人的用户id")
+    private Long operUserId;
+
+    @Schema(description = "删除状态")
+    private Boolean deleteStatus;
+
 }

+ 17 - 2
src/main/java/com/jtzx/crm/module/sys/service/SysCustomerDataPrivateService.java

@@ -4,6 +4,7 @@ package com.jtzx.crm.module.sys.service;
 import cc.uncarbon.framework.core.context.UserContextHolder;
 import cc.uncarbon.framework.core.exception.BusinessException;
 import cc.uncarbon.framework.core.page.PageResult;
+import cc.uncarbon.framework.crud.entity.HelioBaseEntity;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.text.CharSequenceUtil;
@@ -242,10 +243,20 @@ public class SysCustomerDataPrivateService {
      */
     public SysCustomerDetailBO queryCustomerDetail(AdminSysCustomerFollowReqDTO dto) {
         permissionService.publicPrivateCustomerPermission();
+
         SysCustomerDetailBO detailBO = SysCustomerDetailBO.builder().build();
         dto.setUserId(UserContextHolder.getUserId());
         if(UserContextHolder.getUserContext().getRoles().contains("Admin")){
-            dto.setUserId(null);
+            SysCustomerDataEntity entity =
+                    sysCustomerDataMapper.selectOne(
+                            new LambdaQueryWrapper<>(SysCustomerDataEntity.class)
+                                    .select(
+                                            SysCustomerDataEntity::getId,
+                                            SysCustomerDataEntity::getClaimUserId
+                                    )
+                                    .eq(HelioBaseEntity::getId,dto.getCustomerId())
+                    );
+            dto.setUserId(entity.getClaimUserId());
         }
         //顶部筛选条件数据
         SysCustomerFollowHistorySelectBO publicCustomerSelectData = sysCustomerDataFollowService.queryCustomerFollowSelectCommonData(dto.getCustomerId(), dto.getUserId());
@@ -254,8 +265,12 @@ public class SysCustomerDataPrivateService {
         PageResult<SysCustomerFollowListBO> dataPageList = sysCustomerDataFollowService.queryCustomerFollowDataCommonByPage(dto);
         detailBO.setDataPageList(dataPageList);
         detailBO.setProductCount(0);
+        //跟进状态查询
+        List<CustomerStatusOverViewBO> statusOverViewData = sysCustomerFollowService.queryStatusOverViewData(dto.getCustomerId(),dto.getUserId());
+        detailBO.setStatusOverviewData(statusOverViewData);
+
         //跟进产品信息总览
-        List<CustomerProductOverViewBO> overViewBOS = sysCustomerFollowService.queryProductOverViewData(dto.getCustomerId());
+        List<CustomerProductOverViewBO> overViewBOS = sysCustomerFollowService.queryProductOverViewData(dto.getCustomerId(),dto.getUserId());
         if (CollUtil.isNotEmpty(overViewBOS)) {
             int productCount = overViewBOS.stream().map(CustomerProductOverViewBO::getCount).reduce(0, Integer::sum);
             detailBO.setProductCount(productCount);

+ 1 - 1
src/main/java/com/jtzx/crm/module/sys/service/SysCustomerDataPublicService.java

@@ -204,7 +204,7 @@ public class SysCustomerDataPublicService {
         PageResult<SysCustomerFollowListBO> dataPageList = sysCustomerDataFollowService.queryCustomerFollowDataCommonByPage(dto);
         detailBO.setDataPageList(dataPageList);
         //信息总览
-        detailBO.setProductOverviewData(sysCustomerFollowService.queryProductOverViewData(dto.getCustomerId()));
+        detailBO.setProductOverviewData(sysCustomerFollowService.queryProductOverViewData(dto.getCustomerId(),null));
         //跟进记录总览
         detailBO.setFollowOverViewData(sysCustomerFollowService.handleCustomerFollowOverViewData(dto.getCustomerId(), null));
         return detailBO;

+ 54 - 5
src/main/java/com/jtzx/crm/module/sys/service/SysCustomerFollowService.java

@@ -12,10 +12,7 @@ import com.jtzx.crm.module.sys.entity.*;
 import com.jtzx.crm.module.sys.mapper.*;
 import com.jtzx.crm.module.sys.model.request.AdminSysCustomerFollowInsertOrUpdateDTO;
 import com.jtzx.crm.module.sys.model.request.CannelOrderDTO;
-import com.jtzx.crm.module.sys.model.response.CustomerFollowOverViewBO;
-import com.jtzx.crm.module.sys.model.response.CustomerProductBO;
-import com.jtzx.crm.module.sys.model.response.CustomerProductOverViewBO;
-import com.jtzx.crm.module.sys.model.response.SysCustomerFollowDataBO;
+import com.jtzx.crm.module.sys.model.response.*;
 import com.redismq.utils.RedisMQTemplate;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -182,7 +179,7 @@ public class SysCustomerFollowService {
      * @param customerId
      * @return
      */
-    public List<CustomerProductOverViewBO> queryProductOverViewData(Long customerId) {
+    public List<CustomerProductOverViewBO> queryProductOverViewData(Long customerId, Long userId) {
 
         List<CustomerProductOverViewBO> productOverViewBOList = new ArrayList<>();
         List<SysCustomerFollowEntity> followEntityList =
@@ -192,6 +189,7 @@ public class SysCustomerFollowService {
                                         SysCustomerFollowEntity::getProductId,
                                         SysCustomerFollowEntity::getProductName
                                 )
+                                .eq(userId != null, SysCustomerFollowEntity::getClaimUserId, userId)
                                 .eq(SysCustomerFollowEntity::getCustomerId, customerId));
 
         if (CollUtil.isNotEmpty(followEntityList)) {
@@ -225,6 +223,57 @@ public class SysCustomerFollowService {
         return productOverViewBOList;
     }
 
+
+
+    /**
+     * 查询我的客户状态信息总览
+     *
+     * @param customerId
+     * @return
+     */
+    public List<CustomerStatusOverViewBO> queryStatusOverViewData(Long customerId,Long userId) {
+
+        List<CustomerStatusOverViewBO> productOverViewBOList = new ArrayList<>();
+        List<SysCustomerFollowEntity> followEntityList =
+                sysCustomerFollowMapper.selectList(
+                        new LambdaQueryWrapper<>(SysCustomerFollowEntity.class)
+                                .select(
+                                        SysCustomerFollowEntity::getFollowId,
+                                        SysCustomerFollowEntity::getFollowName
+                                )
+                                .eq(userId != null, SysCustomerFollowEntity::getClaimUserId, userId)
+                                .eq(SysCustomerFollowEntity::getCustomerId, customerId));
+
+        if (CollUtil.isNotEmpty(followEntityList)) {
+            List<Long> followIdList = followEntityList.stream()
+                    .map(SysCustomerFollowEntity::getFollowId).distinct().toList();
+
+            List<SysParamBaseDataEntity> statusDataList =
+                    sysParamBaseDataMapper.selectList(
+                            new LambdaQueryWrapper<>(SysParamBaseDataEntity.class)
+                                    .select(
+                                            SysParamBaseDataEntity::getId,
+                                            SysParamBaseDataEntity::getTitle
+                                    )
+                                    .in(SysParamBaseDataEntity::getId, followIdList)
+                                    .orderByAsc(SysParamBaseDataEntity::getSortCode)
+                    );
+            if (CollUtil.isNotEmpty(statusDataList)) {
+                statusDataList.forEach(e -> {
+                    CustomerStatusOverViewBO bo = CustomerStatusOverViewBO.builder()
+                            .statusName(e.getTitle())
+                            .build();
+                    bo.setCount(
+                            followEntityList.stream()
+                                    .filter(x -> x.getFollowId().equals(e.getId()))
+                                    .toList().size());
+                    productOverViewBOList.add(bo);
+                });
+            }
+        }
+        return productOverViewBOList;
+    }
+
     /**
      * 跟进产品数据信息
      *

+ 22 - 13
src/main/java/com/jtzx/crm/module/sys/service/SysCustomerPersonService.java

@@ -57,8 +57,8 @@ public class SysCustomerPersonService {
 //                        .eq(dto.getUserId()!=null,SysCustomerPersonEntity::getCreatedBy,dto.getUserId())
                         // 职务id(param_base_data表主id)
                         .eq(dto.getPositionId() != null, SysCustomerPersonEntity::getPositionId, dto.getPositionId())
-                        .and(StrUtil.isNotEmpty(dto.getQueryStr()),z->z.like(SysCustomerPersonEntity::getName,dto.getQueryStr())
-                                .or().like(SysCustomerPersonEntity::getPhoneNo,dto.getQueryStr())
+                        .and(StrUtil.isNotEmpty(dto.getQueryStr()), z -> z.like(SysCustomerPersonEntity::getName, dto.getQueryStr())
+                                .or().like(SysCustomerPersonEntity::getPhoneNo, dto.getQueryStr())
                                 .or().like(SysCustomerPersonEntity::getOfficePhoneNo, dto.getQueryStr())
                                 .or().like(SysCustomerPersonEntity::getCreatedBy, dto.getQueryStr())
                         )
@@ -94,7 +94,7 @@ public class SysCustomerPersonService {
         dto.setId(null);
         SysCustomerPersonEntity entity = new SysCustomerPersonEntity();
         BeanUtil.copyProperties(dto, entity);
-
+        entity.setOperUserId(UserContextHolder.getUserId());
         sysCustomerPersonMapper.insert(entity);
 
         //新增联系人日志
@@ -113,7 +113,6 @@ public class SysCustomerPersonService {
                 .content(dto.getStr())
                 .build();
         sysCustomerOperLogMapper.insert(logEntity);
-
         return entity.getId();
     }
 
@@ -127,6 +126,11 @@ public class SysCustomerPersonService {
         if (entity == null) {
             throw new BusinessException(400, "无效客户(学校)数据ID");
         }
+        SysCustomerPersonEntity sysCustomerPersonEntity = sysCustomerPersonMapper.selectById(dto.getId());
+        if (!UserContextHolder.getUserContext().getRoles().contains("Admin") ||
+                sysCustomerPersonEntity.getOperUserId().equals(UserContextHolder.getUserId())) {
+            throw new BusinessException(400, "无权操作");
+        }
         //查询用户的小组数据
         SysUserGroupRelationEntity userGroupRelation = sysUserGroupRelationMapper.selectOne(
                 new LambdaQueryWrapper<SysUserGroupRelationEntity>()
@@ -139,8 +143,6 @@ public class SysCustomerPersonService {
                         .eq(SysUserGroupRelationEntity::getCityId, entity.getCityId())
                         .last("limit 1")
         );
-        SysCustomerPersonEntity sysCustomerPersonEntity = sysCustomerPersonMapper.selectById(dto.getId());
-
 
         SysCustomerOperLogEntity logEntity = SysCustomerOperLogEntity.builder()
                 .customerId(entity.getId())
@@ -175,6 +177,11 @@ public class SysCustomerPersonService {
         if (sysCustomerPersonEntity == null) {
             throw new BusinessException(400, "联系人不存在");
         }
+        if (!UserContextHolder.getUserContext().getRoles().contains("Admin") ||
+                sysCustomerPersonEntity.getOperUserId().equals(UserContextHolder.getUserId())) {
+            throw new BusinessException(400, "无权操作");
+        }
+
         SysCustomerDataEntity entity = sysCustomerDataMapper.selectById(sysCustomerPersonEntity.getCustomerId());
         if (entity == null) {
             throw new BusinessException(400, "无效客户(学校)数据ID");
@@ -209,8 +216,6 @@ public class SysCustomerPersonService {
             logEntity.setOperUserGroupId(userGroupRelation.getGroupId());
         }
         sysCustomerOperLogMapper.insert(logEntity);
-
-
         sysCustomerPersonMapper.deleteById(id);
     }
 
@@ -234,9 +239,13 @@ public class SysCustomerPersonService {
 
         SysCustomerPersonBO bo = new SysCustomerPersonBO();
         BeanUtil.copyProperties(entity, bo);
-
         // 可以在此处为BO填充字段
-
+        bo.setOperUserId(entity.getOperUserId());
+        bo.setDeleteStatus(false);
+        if (UserContextHolder.getUserContext().getRoles().contains("Admin") ||
+                entity.getOperUserId().equals(UserContextHolder.getUserId())) {
+            bo.setDeleteStatus(true);
+        }
         return bo;
     }
 
@@ -270,14 +279,14 @@ public class SysCustomerPersonService {
         entityList.forEach(
                 entity -> {
                     SysCustomerPersonBO bo = this.entity2BO(entity);
-                    if(CollUtil.isNotEmpty(lastFollowEntityList)){
+                    if (CollUtil.isNotEmpty(lastFollowEntityList)) {
                         List<SysCustomerFollowEntity> list = lastFollowEntityList.stream()
                                 .filter(lastFollowEntity -> lastFollowEntity.getPositionId().equals(entity.getPositionId()))
                                 .sorted(Comparator.comparing(SysCustomerFollowEntity::getCreatedAt).reversed())
                                 .toList();
-                        if(CollUtil.isNotEmpty(list)){
+                        if (CollUtil.isNotEmpty(list)) {
                             bo.setLastFollowDate(
-                            list.getFirst().getCreatedAt());
+                                    list.getFirst().getCreatedAt());
                         }
                     }
                     ret.add(bo);