Commit 6c9a3b0e119bd924b5201dd3e359e5fc306628ed

Authored by puhui999
1 parent c4ce9068

CRM: 完善销售漏斗分析

Showing 16 changed files with 388 additions and 14 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -97,6 +97,10 @@ public class CollectionUtils {
97 97 .collect(Collectors.toList());
98 98 }
99 99  
  100 + public static <T> Set<T> convertSet(Collection<T> from) {
  101 + return convertSet(from, v -> v);
  102 + }
  103 +
100 104 public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
101 105 if (CollUtil.isEmpty(from)) {
102 106 return new HashSet<>();
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
  7 +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService;
  8 +import io.swagger.v3.oas.annotations.Operation;
  9 +import io.swagger.v3.oas.annotations.tags.Tag;
  10 +import jakarta.annotation.Resource;
  11 +import jakarta.validation.Valid;
  12 +import org.springframework.security.access.prepost.PreAuthorize;
  13 +import org.springframework.validation.annotation.Validated;
  14 +import org.springframework.web.bind.annotation.GetMapping;
  15 +import org.springframework.web.bind.annotation.RequestMapping;
  16 +import org.springframework.web.bind.annotation.RestController;
  17 +
  18 +import java.util.List;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - CRM 销售漏斗")
  23 +@RestController
  24 +@RequestMapping("/crm/statistics-funnel")
  25 +@Validated
  26 +public class CrmStatisticsFunnelController {
  27 +
  28 + @Resource
  29 + private CrmStatisticsFunnelService crmStatisticsFunnelService;
  30 +
  31 + @GetMapping("/get-funnel-summary")
  32 + @Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面")
  33 + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
  34 + public CommonResult<CrmStatisticFunnelRespVO> getFunnelSummary(@Valid CrmStatisticsFunnelReqVO reqVO) {
  35 + return success(crmStatisticsFunnelService.getFunnelSummary(reqVO));
  36 + }
  37 +
  38 +
  39 + @GetMapping("/get-business-end-status-summary")
  40 + @Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面")
  41 + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
  42 + public CommonResult<List<CrmStatisticBusinessEndStatusRespVO>> getBusinessEndStatusSummary(@Valid CrmStatisticsFunnelReqVO reqVO) {
  43 + return success(crmStatisticsFunnelService.getBusinessEndStatusSummary(reqVO));
  44 + }
  45 +
  46 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticBusinessEndStatusRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +
  8 +import java.math.BigDecimal;
  9 +
  10 +@Schema(description = "管理后台 - CRM 商机结束状态统计 Response VO")
  11 +@NoArgsConstructor
  12 +@AllArgsConstructor
  13 +@Data
  14 +public class CrmStatisticBusinessEndStatusRespVO {
  15 +
  16 + @Schema(description = "结束状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + private Integer endStatus;
  18 +
  19 + @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  20 + private Long businessCount;
  21 +
  22 + @Schema(description = "商机总金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  23 + private BigDecimal totalPrice;
  24 +
  25 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticFunnelRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +
  8 +@Schema(description = "管理后台 - CRM 销售漏斗 Response VO")
  9 +@NoArgsConstructor
  10 +@AllArgsConstructor
  11 +@Data
  12 +public class CrmStatisticFunnelRespVO {
  13 +
  14 + @Schema(description = "客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  15 + private Long customerCount;
  16 +
  17 + @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Long businessCount;
  19 +
  20 + @Schema(description = "赢单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  21 + private Long winCount;
  22 +
  23 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.time.LocalDateTime;
  9 +import java.util.List;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +@Schema(description = "管理后台 - CRM 销售漏斗 Request VO")
  14 +@Data
  15 +public class CrmStatisticsFunnelReqVO {
  16 +
  17 + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "部门 id 不能为空")
  19 + private Long deptId;
  20 +
  21 + /**
  22 + * 负责人用户 id, 当用户为空, 则计算部门下用户
  23 + */
  24 + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1")
  25 + private Long userId;
  26 +
  27 + /**
  28 + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来
  29 + * 后续,可能会支持选择部分用户进行查询
  30 + */
  31 + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2")
  32 + private List<Long> userIds;
  33 +
  34 + /**
  35 + * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间
  36 + * 并作为参数传递给Mapper
  37 + */
  38 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
  39 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  40 + private LocalDateTime[] times;
  41 +
  42 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
... ... @@ -6,14 +6,15 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 6 import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
7 7 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO;
8 8 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
9   -import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
10 9 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
11 10 import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils;
12 11 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
13 12 import org.apache.ibatis.annotations.Mapper;
14 13  
  14 +import java.time.LocalDateTime;
15 15 import java.util.Collection;
16 16 import java.util.List;
  17 +import java.util.Set;
17 18  
18 19 /**
19 20 * 商机 Mapper
... ... @@ -59,10 +60,24 @@ public interface CrmBusinessMapper extends BaseMapperX&lt;CrmBusinessDO&gt; {
59 60 return selectCount(CrmBusinessDO::getStatusTypeId, statusTypeId);
60 61 }
61 62  
62   - default List<CrmBusinessDO> selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId){
  63 + default List<CrmBusinessDO> selectListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId) {
63 64 return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
64 65 .eq(CrmBusinessDO::getCustomerId, customerId)
65 66 .eq(CrmBusinessDO::getOwnerUserId, ownerUserId));
66 67 }
67 68  
  69 + default Long selectCountByOwnerUserIdsAndEndStatus(Collection<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus) {
  70 + return selectCount(new LambdaQueryWrapperX<CrmBusinessDO>()
  71 + .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
  72 + .eqIfPresent(CrmBusinessDO::getEndStatus, endStatus)
  73 + .betweenIfPresent(CrmBusinessDO::getCreateTime, times));
  74 + }
  75 +
  76 + default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times){
  77 + return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
  78 + .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
  79 + .betweenIfPresent(CrmBusinessDO::getCreateTime, times)
  80 + .isNotNull(CrmBusinessDO::getEndStatus));
  81 + }
  82 +
68 83 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
... ... @@ -19,9 +19,11 @@ import org.apache.ibatis.annotations.Mapper;
19 19 import org.springframework.lang.Nullable;
20 20 import org.springframework.util.Assert;
21 21  
  22 +import javax.management.ObjectName;
22 23 import java.time.LocalDateTime;
23 24 import java.util.Collection;
24 25 import java.util.List;
  26 +import java.util.Set;
25 27  
26 28 /**
27 29 * 客户 Mapper
... ... @@ -186,4 +188,10 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
186 188 return selectCount(query);
187 189 }
188 190  
  191 + default Long selectCountByOwnerUserIds(Collection<Long> ownerUserIds, LocalDateTime[] times){
  192 + return selectCount(new LambdaQueryWrapperX<CrmCustomerDO>()
  193 + .in(CrmCustomerDO::getOwnerUserId, ownerUserIds)
  194 + .betweenIfPresent(CrmCustomerDO::getCreateTime, times));
  195 + }
  196 +
189 197 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
  2 +
  3 +import org.apache.ibatis.annotations.Mapper;
  4 +
  5 +/**
  6 + * CRM 销售漏斗 Mapper
  7 + *
  8 + * @author HUIHUI
  9 + */
  10 +@Mapper
  11 +public interface CrmStatisticsFunnelMapper {
  12 +
  13 +
  14 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
... ... @@ -194,4 +194,23 @@ public interface CrmBusinessService {
194 194 */
195 195 List<CrmBusinessDO> getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId);
196 196  
  197 + /**
  198 + * 获得商机数
  199 + *
  200 + * @param ownerUserIds 负责人编号
  201 + * @param times 时间范围
  202 + * @param endStatus 商机结束状态
  203 + * @return 商机数
  204 + */
  205 + Long getBusinessCountByOwnerUserIdsAndEndStatus(List<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus);
  206 +
  207 + /**
  208 + * 获得商机列表【数据统计】
  209 + *
  210 + * @param ownerUserIds 负责人编号
  211 + * @param times 时间范围
  212 + * @return 商机列表
  213 + */
  214 + List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times);
  215 +
197 216 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -375,4 +375,20 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
375 375 return businessMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId);
376 376 }
377 377  
  378 + @Override
  379 + public Long getBusinessCountByOwnerUserIdsAndEndStatus(List<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus) {
  380 + if (CollUtil.isEmpty(ownerUserIds)) {
  381 + return 0L;
  382 + }
  383 + return businessMapper.selectCountByOwnerUserIdsAndEndStatus(convertSet(ownerUserIds), times, endStatus);
  384 + }
  385 +
  386 + @Override
  387 + public List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times) {
  388 + if (CollUtil.isEmpty(ownerUserIds)) {
  389 + return Collections.emptyList();
  390 + }
  391 + return businessMapper.selectListByOwnerUserIdsAndEndStatusNotNull(convertSet(ownerUserIds), times);
  392 + }
  393 +
378 394 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
... ... @@ -39,7 +39,7 @@ public interface CrmCustomerService {
39 39 /**
40 40 * 更新客户的跟进状态
41 41 *
42   - * @param id 编号
  42 + * @param id 编号
43 43 * @param dealStatus 跟进状态
44 44 */
45 45 void updateCustomerDealStatus(Long id, Boolean dealStatus);
... ... @@ -47,8 +47,8 @@ public interface CrmCustomerService {
47 47 /**
48 48 * 更新客户相关的跟进信息
49 49 *
50   - * @param id 编号
51   - * @param contactNextTime 下次联系时间
  50 + * @param id 编号
  51 + * @param contactNextTime 下次联系时间
52 52 * @param contactLastContent 最后联系内容
53 53 */
54 54 void updateCustomerFollowUp(Long id, LocalDateTime contactNextTime, String contactLastContent);
... ... @@ -99,8 +99,8 @@ public interface CrmCustomerService {
99 99 /**
100 100 * 获得放入公海提醒的客户分页
101 101 *
102   - * @param pageVO 分页查询
103   - * @param userId 用户编号
  102 + * @param pageVO 分页查询
  103 + * @param userId 用户编号
104 104 * @return 客户分页
105 105 */
106 106 PageResult<CrmCustomerDO> getPutPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO, Long userId);
... ... @@ -108,7 +108,7 @@ public interface CrmCustomerService {
108 108 /**
109 109 * 获得待进入公海的客户数量
110 110 *
111   - * @param userId 用户编号
  111 + * @param userId 用户编号
112 112 * @return 提醒数量
113 113 */
114 114 Long getPutPoolRemindCustomerCount(Long userId);
... ... @@ -195,4 +195,13 @@ public interface CrmCustomerService {
195 195 */
196 196 int autoPutCustomerPool();
197 197  
  198 + /**
  199 + * 获得客户数
  200 + *
  201 + * @param ownerUserIds 负责人编号
  202 + * @param times 时间范围
  203 + * @return 客户数
  204 + */
  205 + Long getCustomerCountByOwnerUserIds(List<Long> ownerUserIds, LocalDateTime[] times);
  206 +
198 207 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
... ... @@ -47,6 +47,7 @@ import java.time.LocalDateTime;
47 47 import java.util.*;
48 48  
49 49 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  50 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
50 51 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
51 52 import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
52 53 import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
... ... @@ -650,6 +651,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
650 651 }
651 652 }
652 653  
  654 + @Override
  655 + public Long getCustomerCountByOwnerUserIds(List<Long> ownerUserIds, LocalDateTime[] times) {
  656 + if (CollUtil.isEmpty(ownerUserIds)) {
  657 + return 0L;
  658 + }
  659 + return customerMapper.selectCountByOwnerUserIds(convertSet(ownerUserIds), times);
  660 + }
  661 +
653 662 /**
654 663 * 获得自身的代理对象,解决 AOP 生效问题
655 664 *
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.statistics;
  2 +
  3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * CRM 销售漏斗分析 Service
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +public interface CrmStatisticsFunnelService {
  15 +
  16 + /**
  17 + * 获得销售漏斗数据
  18 + *
  19 + * @param reqVO 请求
  20 + * @return 销售漏斗数据
  21 + */
  22 + CrmStatisticFunnelRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO);
  23 +
  24 + /**
  25 + * 获得商机结束状态统计
  26 + *
  27 + * @param reqVO 请求
  28 + * @return 商机结束状态统计
  29 + */
  30 + List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO);
  31 +
  32 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.statistics;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjUtil;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
  7 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
  8 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
  9 +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper;
  10 +import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum;
  11 +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
  12 +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
  13 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  14 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  15 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  16 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  17 +import jakarta.annotation.Resource;
  18 +import org.springframework.stereotype.Service;
  19 +
  20 +import java.math.BigDecimal;
  21 +import java.util.List;
  22 +import java.util.Map;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  25 +
  26 +/**
  27 + * CRM 销售漏斗分析 Service 实现类
  28 + *
  29 + * @author HUIHUI
  30 + */
  31 +@Service
  32 +public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelService {
  33 +
  34 + @Resource
  35 + private CrmStatisticsFunnelMapper funnelMapper;
  36 +
  37 + @Resource
  38 + private AdminUserApi adminUserApi;
  39 + @Resource
  40 + private CrmCustomerService customerService;
  41 + @Resource
  42 + private CrmBusinessService businessService;
  43 + @Resource
  44 + private DeptApi deptApi;
  45 +
  46 + @Override
  47 + public CrmStatisticFunnelRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO) {
  48 + // 1. 获得用户编号数组
  49 + List<Long> userIds = getUserIds(reqVO);
  50 + if (CollUtil.isEmpty(userIds)) {
  51 + return null;
  52 + }
  53 + reqVO.setUserIds(userIds);
  54 +
  55 + // 2. 获得漏斗数据
  56 + return new CrmStatisticFunnelRespVO(
  57 + customerService.getCustomerCountByOwnerUserIds(userIds, reqVO.getTimes()),
  58 + businessService.getBusinessCountByOwnerUserIdsAndEndStatus(userIds, reqVO.getTimes(), null),
  59 + businessService.getBusinessCountByOwnerUserIdsAndEndStatus(userIds, reqVO.getTimes(), CrmBusinessEndStatusEnum.WIN.getStatus())
  60 + );
  61 + }
  62 +
  63 + @Override
  64 + public List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO) {
  65 + // 1. 获得用户编号数组
  66 + List<Long> userIds = getUserIds(reqVO);
  67 + if (CollUtil.isEmpty(userIds)) {
  68 + return null;
  69 + }
  70 + reqVO.setUserIds(userIds);
  71 +
  72 + // 2.1 获得用户负责的商机
  73 + List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(userIds, reqVO.getTimes());
  74 + // 2.2 统计各阶段数据
  75 + Map<Integer, List<CrmBusinessDO>> businessMap = convertMultiMap(businessList, CrmBusinessDO::getEndStatus);
  76 + return convertList(CrmBusinessEndStatusEnum.values(), endStatusEnum -> {
  77 + List<CrmBusinessDO> list = businessMap.get(endStatusEnum.getStatus());
  78 + if (CollUtil.isEmpty(list)) {
  79 + return new CrmStatisticBusinessEndStatusRespVO(endStatusEnum.getStatus(), 0L, BigDecimal.ZERO);
  80 + }
  81 + return new CrmStatisticBusinessEndStatusRespVO(endStatusEnum.getStatus(), (long) list.size(),
  82 + getSumValue(list, CrmBusinessDO::getTotalPrice, BigDecimal::add));
  83 + });
  84 + }
  85 +
  86 + /**
  87 + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号
  88 + *
  89 + * @param reqVO 请求参数
  90 + * @return 用户编号数组
  91 + */
  92 + private List<Long> getUserIds(CrmStatisticsFunnelReqVO reqVO) {
  93 + // 情况一:选中某个用户
  94 + if (ObjUtil.isNotNull(reqVO.getUserId())) {
  95 + return List.of(reqVO.getUserId());
  96 + }
  97 + // 情况二:选中某个部门
  98 + // 2.1 获得部门列表
  99 + List<Long> deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId);
  100 + deptIds.add(reqVO.getDeptId());
  101 + // 2.2 获得用户编号
  102 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
  103 + }
  104 +
  105 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java
... ... @@ -20,7 +20,6 @@ import java.util.Map;
20 20  
21 21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 22 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
23   -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
24 23  
25 24 /**
26 25 * CRM 客户画像 Service 实现类
... ... @@ -55,15 +54,18 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe
55 54  
56 55 // 3. 拼接数据
57 56 List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area);
58   - areaList.add(new Area().setId(null).setName("未知")); // TODO @puhui999:是不是 65 find 的逻辑改下;不用 findAndThen,直接从 areaMap 拿;拿到就设置,不拿到就设置 null 和 未知;这样,58 本行可以删除掉完事了;这样代码更简单和一致
59 57 Map<Integer, Area> areaMap = convertMap(areaList, Area::getId);
60 58 return convertList(list, item -> {
61 59 Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE);
62   - if (parentId == null) { // 找不到,归到未知
63   - return item.setAreaId(null).setAreaName("未知");
  60 + if (parentId != null) {
  61 + Area area = areaMap.get(parentId);
  62 + if (area != null) {
  63 + item.setAreaId(parentId).setAreaName(area.getName());
  64 + return item;
  65 + }
64 66 }
65   - findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName()));
66   - return item;
  67 + // 找不到,归到未知
  68 + return item.setAreaId(null).setAreaName("未知");
67 69 });
68 70 }
69 71  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper">
  4 +
  5 +</mapper>
... ...