Commit 924580f4a29db98d7add392e516be8505d0ed61b

Authored by YunaiV
1 parent 3b379d8c

CRM:重构【客户画像】,从【客户统计】拆分出去先~

Showing 16 changed files with 400 additions and 286 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java
... ... @@ -2,10 +2,6 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
5   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO;
6   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
7   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
8   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
9 5 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService;
10 6 import io.swagger.v3.oas.annotations.Operation;
11 7 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -90,32 +86,4 @@ public class CrmStatisticsCustomerController {
90 86  
91 87 // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析;
92 88  
93   - @GetMapping("/get-customer-industry-summary")
94   - @Operation(summary = "获取客户行业统计数据")
95   - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
96   - public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) {
97   - return success(customerService.getCustomerIndustry(reqVO));
98   - }
99   -
100   - @GetMapping("/get-customer-source-summary")
101   - @Operation(summary = "获取客户来源统计数据")
102   - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
103   - public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) {
104   - return success(customerService.getCustomerSource(reqVO));
105   - }
106   -
107   - @GetMapping("/get-customer-level-summary")
108   - @Operation(summary = "获取客户级别统计数据")
109   - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
110   - public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) {
111   - return success(customerService.getCustomerLevel(reqVO));
112   - }
113   -
114   - @GetMapping("/get-customer-area-summary")
115   - @Operation(summary = "获取客户地区统计数据")
116   - @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
117   - public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerArea(@Valid CrmStatisticsCustomerReqVO reqVO) {
118   - return success(customerService.getCustomerArea(reqVO));
119   - }
120   -
121 89 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.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.customer.CrmStatisticsCustomerReqVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO;
  7 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO;
  8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO;
  9 +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPortraitService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.tags.Tag;
  12 +import jakarta.annotation.Resource;
  13 +import jakarta.validation.Valid;
  14 +import org.springframework.security.access.prepost.PreAuthorize;
  15 +import org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.GetMapping;
  17 +import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RestController;
  19 +
  20 +import java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Tag(name = "管理后台 - CRM 客户画像")
  25 +@RestController
  26 +@RequestMapping("/crm/statistics-portrait")
  27 +@Validated
  28 +public class CrmStatisticsPortraitController {
  29 +
  30 + @Resource
  31 + private CrmStatisticsPortraitService statisticsPortraitService;
  32 +
  33 + @GetMapping("/get-customer-area-summary")
  34 + @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面")
  35 + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
  36 + public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerAreaSummary(@Valid CrmStatisticsCustomerReqVO reqVO) {
  37 + return success(statisticsPortraitService.getCustomerArea(reqVO));
  38 + }
  39 +
  40 + @GetMapping("/get-customer-industry-summary")
  41 + @Operation(summary = "获取客户行业统计数据")
  42 + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
  43 + public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) {
  44 + return success(statisticsPortraitService.getCustomerIndustry(reqVO));
  45 + }
  46 +
  47 + @GetMapping("/get-customer-level-summary")
  48 + @Operation(summary = "获取客户级别统计数据")
  49 + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
  50 + public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) {
  51 + return success(statisticsPortraitService.getCustomerLevel(reqVO));
  52 + }
  53 +
  54 + @GetMapping("/get-customer-source-summary")
  55 + @Operation(summary = "获取客户来源统计数据")
  56 + @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
  57 + public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) {
  58 + return success(statisticsPortraitService.getCustomerSource(reqVO));
  59 + }
  60 +
  61 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsRankController.java
... ... @@ -18,7 +18,6 @@ import java.util.List;
18 18  
19 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
20 20  
21   -
22 21 @Tag(name = "管理后台 - CRM 排行榜统计")
23 22 @RestController
24 23 @RequestMapping("/crm/statistics-rank")
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java
... ... @@ -45,12 +45,4 @@ public class CrmStatisticsCustomerReqVO {
45 45 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
46 46 private LocalDateTime[] times;
47 47  
48   - /**
49   - * group by DATE_FORMAT(field, #{dateFormat})
50   - * 非前端传递, 由Service计算后传递给Mapper的参数
51   - */
52   - @Deprecated
53   - @Schema(description = "Group By 日期格式", hidden = true, example = "%Y%m")
54   - private String sqlDateFormat;
55   -
56 48 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java
1   -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java
1   -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java
1   -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java
1   -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
1 1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
2 2  
3 3 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
4   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO;
5   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
6   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
7   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
8 4 import org.apache.ibatis.annotations.Mapper;
9 5  
10 6 import java.util.List;
11 7  
12 8 /**
13   - * CRM 数据统计 员工客户分析 Mapper
  9 + * CRM 数据统计 Mapper
14 10 *
15 11 * @author dhb52
16 12 */
... ... @@ -45,12 +41,4 @@ public interface CrmStatisticsCustomerMapper {
45 41  
46 42 List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO);
47 43  
48   - List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO);
49   -
50   - List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO);
51   -
52   - List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);
53   -
54   - List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO);
55   -
56 44 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPortraitMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
  2 +
  3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO;
  7 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * CRM 数据画像 Mapper
  14 + *
  15 + * @author dhb52
  16 + */
  17 +@Mapper
  18 +public interface CrmStatisticsPortraitMapper {
  19 +
  20 + List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO);
  21 +
  22 + List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO);
  23 +
  24 + List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);
  25 +
  26 + List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO);
  27 +
  28 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java
1 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 2  
3 3 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
4   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO;
5   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
6   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
7   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
8 4  
9 5 import java.util.List;
10 6  
... ... @@ -81,36 +77,4 @@ public interface CrmStatisticsCustomerService {
81 77 */
82 78 List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO);
83 79  
84   - /**
85   - * 获取客户行业统计数据
86   - *
87   - * @param reqVO 请求参数
88   - * @return 统计数据
89   - */
90   - List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO);
91   -
92   - /**
93   - * 获取客户来源统计数据
94   - *
95   - * @param reqVO 请求参数
96   - * @return 统计数据
97   - */
98   - List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO);
99   -
100   - /**
101   - * 获取客户级别统计数据
102   - *
103   - * @param reqVO 请求参数
104   - * @return 统计数据
105   - */
106   - List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO);
107   -
108   - /**
109   - * 获取客户地区统计数据
110   - *
111   - * @param reqVO 请求参数
112   - * @return 统计数据
113   - */
114   - List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO);
115   -
116 80 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
... ... @@ -4,14 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjUtil;
5 5 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
6 6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
7   -import cn.iocoder.yudao.framework.ip.core.Area;
8   -import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
9   -import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
10 7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
11   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO;
12   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
13   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
14   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
15 8 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper;
16 9 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
17 10 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
... ... @@ -30,8 +23,6 @@ import java.util.stream.Stream;
30 23  
31 24 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
32 25 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
33   -import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
34   -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
35 26  
36 27 /**
37 28 * CRM 客户分析 Service 实现类
... ... @@ -245,104 +236,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
245 236 return summaryList;
246 237 }
247 238  
248   - @Override
249   - public List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) {
250   - // 1. 获得用户编号数组
251   - List<Long> userIds = getUserIds(reqVO);
252   - if (CollUtil.isEmpty(userIds)) {
253   - return Collections.emptyList();
254   - }
255   - reqVO.setUserIds(userIds);
256   - // 2. 获取客户行业统计数据
257   - List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = customerMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO);
258   - if (CollUtil.isEmpty(industryRespVOList)) {
259   - return Collections.emptyList();
260   - }
261   -
262   - return convertList(industryRespVOList, item -> {
263   - if (ObjUtil.isNull(item.getIndustryId())) {
264   - return item;
265   - }
266   - item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId()));
267   - return item;
268   - });
269   - }
270   -
271   - @Override
272   - public List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO) {
273   - // 1. 获得用户编号数组
274   - List<Long> userIds = getUserIds(reqVO);
275   - if (CollUtil.isEmpty(userIds)) {
276   - return Collections.emptyList();
277   - }
278   - reqVO.setUserIds(userIds);
279   - // 2. 获取客户行业统计数据
280   - List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = customerMapper.selectCustomerSourceListGroupbySource(reqVO);
281   - if (CollUtil.isEmpty(sourceRespVOList)) {
282   - return Collections.emptyList();
283   - }
284   -
285   - return convertList(sourceRespVOList, item -> {
286   - if (ObjUtil.isNull(item.getSource())) {
287   - return item;
288   - }
289   - item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource()));
290   - return item;
291   - });
292   - }
293   -
294   - @Override
295   - public List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) {
296   - // 1. 获得用户编号数组
297   - List<Long> userIds = getUserIds(reqVO);
298   - if (CollUtil.isEmpty(userIds)) {
299   - return Collections.emptyList();
300   - }
301   - reqVO.setUserIds(userIds);
302   - // 2. 获取客户行业统计数据
303   - List<CrmStatisticCustomerLevelRespVO> levelRespVOList = customerMapper.selectCustomerLevelListGroupbyLevel(reqVO);
304   - if (CollUtil.isEmpty(levelRespVOList)) {
305   - return Collections.emptyList();
306   - }
307   -
308   - return convertList(levelRespVOList, item -> {
309   - if (ObjUtil.isNull(item.getLevel())) {
310   - return item;
311   - }
312   - item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel()));
313   - return item;
314   - });
315   - }
316   -
317   - @Override
318   - public List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO) {
319   - // 1. 获得用户编号数组
320   - List<Long> userIds = getUserIds(reqVO);
321   - if (CollUtil.isEmpty(userIds)) {
322   - return Collections.emptyList();
323   - }
324   - reqVO.setUserIds(userIds);
325   - // 2. 获取客户地区统计数据
326   - List<CrmStatisticCustomerAreaRespVO> list = customerMapper.selectSummaryListByAreaId(reqVO);
327   - if (CollUtil.isEmpty(list)) {
328   - return Collections.emptyList();
329   - }
330   -
331   - // 拼接数据
332   - List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area);
333   - areaList.add(new Area().setId(null).setName("未知"));
334   - Map<Integer, Area> areaMap = convertMap(areaList, Area::getId);
335   - List<CrmStatisticCustomerAreaRespVO> customerAreaRespVOList = convertList(list, item -> {
336   - Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE);
337   - if (parentId == null) {
338   - return item;
339   - }
340   - findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName()));
341   - return item;
342   - });
343   - return customerAreaRespVOList;
344   - }
345   -
346 239 /**
347 240 * 拼接用户信息(昵称)
348 241 *
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.statistics;
  2 +
  3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO;
  7 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * CRM 客户画像 Service 接口
  13 + *
  14 + * @author HUIHUI
  15 + */
  16 +public interface CrmStatisticsPortraitService {
  17 +
  18 + /**
  19 + * 获取客户地区统计数据
  20 + *
  21 + * @param reqVO 请求参数
  22 + * @return 统计数据
  23 + */
  24 + List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO);
  25 +
  26 + /**
  27 + * 获取客户行业统计数据
  28 + *
  29 + * @param reqVO 请求参数
  30 + * @return 统计数据
  31 + */
  32 + List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO);
  33 +
  34 + /**
  35 + * 获取客户级别统计数据
  36 + *
  37 + * @param reqVO 请求参数
  38 + * @return 统计数据
  39 + */
  40 + List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO);
  41 +
  42 + /**
  43 + * 获取客户来源统计数据
  44 + *
  45 + * @param reqVO 请求参数
  46 + * @return 统计数据
  47 + */
  48 + List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO);
  49 +
  50 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.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.framework.ip.core.Area;
  6 +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
  7 +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
  8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO;
  9 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO;
  10 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO;
  11 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO;
  12 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO;
  13 +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper;
  14 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  15 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  16 +import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
  17 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  18 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  19 +import jakarta.annotation.Resource;
  20 +import org.springframework.stereotype.Service;
  21 +
  22 +import java.util.Collections;
  23 +import java.util.List;
  24 +import java.util.Map;
  25 +
  26 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  28 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  29 +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
  30 +
  31 +/**
  32 + * CRM 客户画像 Service 实现类
  33 + *
  34 + * @author HUIHUI
  35 + */
  36 +@Service
  37 +public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitService {
  38 +
  39 + @Resource
  40 + private CrmStatisticsPortraitMapper portraitMapper;
  41 +
  42 + @Resource
  43 + private AdminUserApi adminUserApi;
  44 + @Resource
  45 + private DeptApi deptApi;
  46 + @Resource
  47 + private DictDataApi dictDataApi;
  48 +
  49 + @Override
  50 + public List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) {
  51 + // 1. 获得用户编号数组
  52 + List<Long> userIds = getUserIds(reqVO);
  53 + if (CollUtil.isEmpty(userIds)) {
  54 + return Collections.emptyList();
  55 + }
  56 + reqVO.setUserIds(userIds);
  57 + // 2. 获取客户行业统计数据
  58 + List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = portraitMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO);
  59 + if (CollUtil.isEmpty(industryRespVOList)) {
  60 + return Collections.emptyList();
  61 + }
  62 +
  63 + return convertList(industryRespVOList, item -> {
  64 + if (ObjUtil.isNull(item.getIndustryId())) {
  65 + return item;
  66 + }
  67 + item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId()));
  68 + return item;
  69 + });
  70 + }
  71 +
  72 + @Override
  73 + public List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO) {
  74 + // 1. 获得用户编号数组
  75 + List<Long> userIds = getUserIds(reqVO);
  76 + if (CollUtil.isEmpty(userIds)) {
  77 + return Collections.emptyList();
  78 + }
  79 + reqVO.setUserIds(userIds);
  80 + // 2. 获取客户行业统计数据
  81 + List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = portraitMapper.selectCustomerSourceListGroupbySource(reqVO);
  82 + if (CollUtil.isEmpty(sourceRespVOList)) {
  83 + return Collections.emptyList();
  84 + }
  85 +
  86 + return convertList(sourceRespVOList, item -> {
  87 + if (ObjUtil.isNull(item.getSource())) {
  88 + return item;
  89 + }
  90 + item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource()));
  91 + return item;
  92 + });
  93 + }
  94 +
  95 + @Override
  96 + public List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) {
  97 + // 1. 获得用户编号数组
  98 + List<Long> userIds = getUserIds(reqVO);
  99 + if (CollUtil.isEmpty(userIds)) {
  100 + return Collections.emptyList();
  101 + }
  102 + reqVO.setUserIds(userIds);
  103 + // 2. 获取客户行业统计数据
  104 + List<CrmStatisticCustomerLevelRespVO> levelRespVOList = portraitMapper.selectCustomerLevelListGroupbyLevel(reqVO);
  105 + if (CollUtil.isEmpty(levelRespVOList)) {
  106 + return Collections.emptyList();
  107 + }
  108 +
  109 + return convertList(levelRespVOList, item -> {
  110 + if (ObjUtil.isNull(item.getLevel())) {
  111 + return item;
  112 + }
  113 + item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel()));
  114 + return item;
  115 + });
  116 + }
  117 +
  118 + @Override
  119 + public List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO) {
  120 + // 1. 获得用户编号数组
  121 + List<Long> userIds = getUserIds(reqVO);
  122 + if (CollUtil.isEmpty(userIds)) {
  123 + return Collections.emptyList();
  124 + }
  125 + reqVO.setUserIds(userIds);
  126 + // 2. 获取客户地区统计数据
  127 + List<CrmStatisticCustomerAreaRespVO> list = portraitMapper.selectSummaryListByAreaId(reqVO);
  128 + if (CollUtil.isEmpty(list)) {
  129 + return Collections.emptyList();
  130 + }
  131 +
  132 + // 拼接数据
  133 + List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area);
  134 + areaList.add(new Area().setId(null).setName("未知"));
  135 + Map<Integer, Area> areaMap = convertMap(areaList, Area::getId);
  136 + List<CrmStatisticCustomerAreaRespVO> customerAreaRespVOList = convertList(list, item -> {
  137 + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE);
  138 + if (parentId == null) {
  139 + return item;
  140 + }
  141 + findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName()));
  142 + return item;
  143 + });
  144 + return customerAreaRespVOList;
  145 + }
  146 +
  147 + /**
  148 + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号
  149 + *
  150 + * @param reqVO 请求参数
  151 + * @return 用户编号数组
  152 + */
  153 + private List<Long> getUserIds(CrmStatisticsCustomerReqVO reqVO) {
  154 + // 情况一:选中某个用户
  155 + if (ObjUtil.isNotNull(reqVO.getUserId())) {
  156 + return List.of(reqVO.getUserId());
  157 + }
  158 + // 情况二:选中某个部门
  159 + // 2.1 获得部门列表
  160 + List<Long> deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId);
  161 + deptIds.add(reqVO.getDeptId());
  162 + // 2.2 获得用户编号
  163 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
  164 + }
  165 +
  166 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
... ... @@ -229,89 +229,4 @@
229 229 GROUP BY customer.owner_user_id
230 230 </select>
231 231  
232   - <select id="selectCustomerIndustryListGroupbyIndustryId"
233   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO">
234   - SELECT
235   - industry_id,
236   - COUNT(*) AS customerCount,
237   - SUM(deal_status) AS dealCount,
238   - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS industryPortion,
239   - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
240   - FROM
241   - crm_customer
242   - WHERE
243   - deleted = 0 AND industry_id IS NOT NULL
244   - AND owner_user_id IN
245   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
246   - #{userId}
247   - </foreach>
248   - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
249   - #{times[1],javaType=java.time.LocalDateTime}
250   - GROUP BY
251   - industry_id;
252   - </select>
253   - <select id="selectCustomerSourceListGroupbySource"
254   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO">
255   - SELECT
256   - source,
257   - COUNT(*) AS customerCount,
258   - SUM(deal_status) AS dealCount,
259   - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS sourcePortion,
260   - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
261   - FROM
262   - crm_customer
263   - WHERE
264   - deleted = 0 AND source IS NOT NULL
265   - AND owner_user_id IN
266   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
267   - #{userId}
268   - </foreach>
269   - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
270   - #{times[1],javaType=java.time.LocalDateTime}
271   - GROUP BY
272   - source;
273   - </select>
274   - <select id="selectCustomerLevelListGroupbyLevel"
275   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO">
276   - SELECT
277   - level,
278   - COUNT(*) AS customerCount,
279   - SUM(deal_status) AS dealCount,
280   - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS levelPortion,
281   - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
282   - FROM
283   - crm_customer
284   - WHERE
285   - deleted = 0 AND level IS NOT NULL
286   - AND owner_user_id IN
287   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
288   - #{userId}
289   - </foreach>
290   - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
291   - #{times[1],javaType=java.time.LocalDateTime}
292   - GROUP BY
293   - level;
294   - </select>
295   - <select id="selectSummaryListByAreaId"
296   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO">
297   - SELECT
298   - area_id,
299   - COUNT(*) AS customerCount,
300   - SUM(deal_status) AS dealCount,
301   - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS areaPortion,
302   - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
303   - FROM
304   - crm_customer
305   - WHERE
306   - deleted = 0 AND area_id IS NOT NULL
307   - AND owner_user_id IN
308   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
309   - #{userId}
310   - </foreach>
311   - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
312   - #{times[1],javaType=java.time.LocalDateTime}
313   - GROUP BY
314   - area_id;
315   - </select>
316   -
317 232 </mapper>
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.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.CrmStatisticsPortraitMapper">
  4 +
  5 + <select id="selectCustomerIndustryListGroupbyIndustryId"
  6 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO">
  7 + SELECT
  8 + industry_id,
  9 + COUNT(*) AS customerCount,
  10 + SUM(deal_status) AS dealCount,
  11 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS industryPortion,
  12 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  13 + FROM
  14 + crm_customer
  15 + WHERE
  16 + deleted = 0 AND industry_id IS NOT NULL
  17 + AND owner_user_id IN
  18 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  19 + #{userId}
  20 + </foreach>
  21 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  22 + #{times[1],javaType=java.time.LocalDateTime}
  23 + GROUP BY
  24 + industry_id;
  25 + </select>
  26 + <select id="selectCustomerSourceListGroupbySource"
  27 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO">
  28 + SELECT
  29 + source,
  30 + COUNT(*) AS customerCount,
  31 + SUM(deal_status) AS dealCount,
  32 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS sourcePortion,
  33 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  34 + FROM
  35 + crm_customer
  36 + WHERE
  37 + deleted = 0 AND source IS NOT NULL
  38 + AND owner_user_id IN
  39 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  40 + #{userId}
  41 + </foreach>
  42 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  43 + #{times[1],javaType=java.time.LocalDateTime}
  44 + GROUP BY
  45 + source;
  46 + </select>
  47 + <select id="selectCustomerLevelListGroupbyLevel"
  48 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO">
  49 + SELECT
  50 + level,
  51 + COUNT(*) AS customerCount,
  52 + SUM(deal_status) AS dealCount,
  53 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS levelPortion,
  54 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  55 + FROM
  56 + crm_customer
  57 + WHERE
  58 + deleted = 0 AND level IS NOT NULL
  59 + AND owner_user_id IN
  60 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  61 + #{userId}
  62 + </foreach>
  63 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  64 + #{times[1],javaType=java.time.LocalDateTime}
  65 + GROUP BY
  66 + level;
  67 + </select>
  68 + <select id="selectSummaryListByAreaId"
  69 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO">
  70 + SELECT
  71 + area_id,
  72 + COUNT(*) AS customerCount,
  73 + SUM(deal_status) AS dealCount,
  74 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS areaPortion,
  75 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  76 + FROM
  77 + crm_customer
  78 + WHERE
  79 + deleted = 0 AND area_id IS NOT NULL
  80 + AND owner_user_id IN
  81 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  82 + #{userId}
  83 + </foreach>
  84 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  85 + #{times[1],javaType=java.time.LocalDateTime}
  86 + GROUP BY
  87 + area_id;
  88 + </select>
  89 +
  90 +</mapper>
... ...