Commit 9ea43ce55ac7a79ac1894d8291c498515ef6da69

Authored by 芋道源码
Committed by Gitee
2 parents 9b9f54bb eeed1fdf

!932 CRM: 完善用户画像数据统计

Merge pull request !932 from puhui999/develop
Showing 10 changed files with 118 additions and 190 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPortraitController.java
1 package cn.iocoder.yudao.module.crm.controller.admin.statistics; 1 package cn.iocoder.yudao.module.crm.controller.admin.statistics;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; 4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticsPortraitReqVO;
5 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO; 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; 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; 7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO;
@@ -30,34 +30,32 @@ public class CrmStatisticsPortraitController { @@ -30,34 +30,32 @@ public class CrmStatisticsPortraitController {
30 @Resource 30 @Resource
31 private CrmStatisticsPortraitService statisticsPortraitService; 31 private CrmStatisticsPortraitService statisticsPortraitService;
32 32
33 - // TODO @puhui999:搞个属于自己的 CrmStatisticsCustomerReqVO 类哈  
34 -  
35 @GetMapping("/get-customer-area-summary") 33 @GetMapping("/get-customer-area-summary")
36 @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面") 34 @Operation(summary = "获取客户地区统计数据", description = "用于【城市分布分析】页面")
37 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") 35 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
38 - public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerAreaSummary(@Valid CrmStatisticsCustomerReqVO reqVO) {  
39 - return success(statisticsPortraitService.getCustomerAreaSummary(reqVO)); 36 + public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerAreaSummary(@Valid CrmStatisticsPortraitReqVO reqVO) {
  37 + return success(statisticsPortraitService.getCustomerSummaryByArea(reqVO));
40 } 38 }
41 39
42 @GetMapping("/get-customer-industry-summary") 40 @GetMapping("/get-customer-industry-summary")
43 @Operation(summary = "获取客户行业统计数据", description = "用于【客户行业分析】页面") 41 @Operation(summary = "获取客户行业统计数据", description = "用于【客户行业分析】页面")
44 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") 42 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
45 - public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustrySummary(@Valid CrmStatisticsCustomerReqVO reqVO) {  
46 - return success(statisticsPortraitService.getCustomerIndustrySummary(reqVO)); 43 + public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustrySummary(@Valid CrmStatisticsPortraitReqVO reqVO) {
  44 + return success(statisticsPortraitService.getCustomerSummaryByIndustry(reqVO));
47 } 45 }
48 46
49 @GetMapping("/get-customer-level-summary") 47 @GetMapping("/get-customer-level-summary")
50 @Operation(summary = "获取客户级别统计数据", description = "用于【客户级别分析】页面") 48 @Operation(summary = "获取客户级别统计数据", description = "用于【客户级别分析】页面")
51 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") 49 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
52 - public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevelSummary(@Valid CrmStatisticsCustomerReqVO reqVO) {  
53 - return success(statisticsPortraitService.getCustomerLevelSummary(reqVO)); 50 + public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevelSummary(@Valid CrmStatisticsPortraitReqVO reqVO) {
  51 + return success(statisticsPortraitService.getCustomerSummaryByLevel(reqVO));
54 } 52 }
55 53
56 @GetMapping("/get-customer-source-summary") 54 @GetMapping("/get-customer-source-summary")
57 @Operation(summary = "获取客户来源统计数据", description = "用于【客户来源分析】页面") 55 @Operation(summary = "获取客户来源统计数据", description = "用于【客户来源分析】页面")
58 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')") 56 @PreAuthorize("@ss.hasPermission('crm:statistics-portrait:query')")
59 - public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSourceSummary(@Valid CrmStatisticsCustomerReqVO reqVO) {  
60 - return success(statisticsPortraitService.getCustomerSourceSummary(reqVO)); 57 + public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSourceSummary(@Valid CrmStatisticsPortraitReqVO reqVO) {
  58 + return success(statisticsPortraitService.getCustomerSummaryBySource(reqVO));
61 } 59 }
62 60
63 } 61 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerAreaRespVO.java
@@ -18,12 +18,4 @@ public class CrmStatisticCustomerAreaRespVO { @@ -18,12 +18,4 @@ public class CrmStatisticCustomerAreaRespVO {
18 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 18 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
19 private Integer dealCount; 19 private Integer dealCount;
20 20
21 - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。  
22 -  
23 - @Schema(description = "省份占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
24 - private Double areaPortion;  
25 -  
26 - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
27 - private Double dealPortion;  
28 -  
29 } 21 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerIndustryRespVO.java
@@ -9,9 +9,6 @@ public class CrmStatisticCustomerIndustryRespVO { @@ -9,9 +9,6 @@ public class CrmStatisticCustomerIndustryRespVO {
9 9
10 @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") 10 @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
11 private Integer industryId; 11 private Integer industryId;
12 - // TODO @puhui999:这个前端字典翻译哈  
13 - @Schema(description = "客户行业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")  
14 - private String industryName;  
15 12
16 @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 13 @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Integer customerCount; 14 private Integer customerCount;
@@ -19,12 +16,4 @@ public class CrmStatisticCustomerIndustryRespVO { @@ -19,12 +16,4 @@ public class CrmStatisticCustomerIndustryRespVO {
19 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 16 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 private Integer dealCount; 17 private Integer dealCount;
21 18
22 - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。  
23 -  
24 - @Schema(description = "行业占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
25 - private Double industryPortion;  
26 -  
27 - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
28 - private Double dealPortion;  
29 -  
30 } 19 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerLevelRespVO.java
@@ -9,9 +9,6 @@ public class CrmStatisticCustomerLevelRespVO { @@ -9,9 +9,6 @@ public class CrmStatisticCustomerLevelRespVO {
9 9
10 @Schema(description = "客户级别编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") 10 @Schema(description = "客户级别编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
11 private Integer level; 11 private Integer level;
12 - // TODO @puhui999:这个前端字典翻译哈  
13 - @Schema(description = "客户级别名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")  
14 - private String levelName;  
15 12
16 @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 13 @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Integer customerCount; 14 private Integer customerCount;
@@ -19,12 +16,4 @@ public class CrmStatisticCustomerLevelRespVO { @@ -19,12 +16,4 @@ public class CrmStatisticCustomerLevelRespVO {
19 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 16 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 private Integer dealCount; 17 private Integer dealCount;
21 18
22 - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。  
23 -  
24 - @Schema(description = "级别占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
25 - private Double levelPortion;  
26 -  
27 - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
28 - private Double dealPortion;  
29 -  
30 } 19 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticCustomerSourceRespVO.java
@@ -9,9 +9,6 @@ public class CrmStatisticCustomerSourceRespVO { @@ -9,9 +9,6 @@ public class CrmStatisticCustomerSourceRespVO {
9 9
10 @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") 10 @Schema(description = "客户来源编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
11 private Integer source; 11 private Integer source;
12 - // TODO @puhui999:这个前端字典翻译哈  
13 - @Schema(description = "客户来源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")  
14 - private String sourceName;  
15 12
16 @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 13 @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Integer customerCount; 14 private Integer customerCount;
@@ -19,12 +16,4 @@ public class CrmStatisticCustomerSourceRespVO { @@ -19,12 +16,4 @@ public class CrmStatisticCustomerSourceRespVO {
19 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 16 @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 private Integer dealCount; 17 private Integer dealCount;
21 18
22 - // TODO @puhui999:下面两个的计算,交给前端。后端只返回数据即可。  
23 -  
24 - @Schema(description = "来源占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
25 - private Double sourcePortion;  
26 -  
27 - @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
28 - private Double dealPortion;  
29 -  
30 } 19 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait;
  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 CrmStatisticsPortraitReqVO {
  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/statistics/CrmStatisticsPortraitMapper.java
1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics; 1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
2 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; 3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*;
8 import org.apache.ibatis.annotations.Mapper; 4 import org.apache.ibatis.annotations.Mapper;
9 5
10 import java.util.List; 6 import java.util.List;
@@ -17,14 +13,12 @@ import java.util.List; @@ -17,14 +13,12 @@ import java.util.List;
17 @Mapper 13 @Mapper
18 public interface CrmStatisticsPortraitMapper { 14 public interface CrmStatisticsPortraitMapper {
19 15
20 - // TODO @puuhui999:GroupBy 16 + List<CrmStatisticCustomerAreaRespVO> selectSummaryListGroupByAreaId(CrmStatisticsPortraitReqVO reqVO);
21 17
22 - List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); 18 + List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupByIndustryId(CrmStatisticsPortraitReqVO reqVO);
23 19
24 - List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); 20 + List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupBySource(CrmStatisticsPortraitReqVO reqVO);
25 21
26 - List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);  
27 -  
28 - List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); 22 + List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupByLevel(CrmStatisticsPortraitReqVO reqVO);
29 23
30 } 24 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitService.java
1 package cn.iocoder.yudao.module.crm.service.statistics; 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 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; 3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*;
8 4
9 import java.util.List; 5 import java.util.List;
10 6
@@ -21,7 +17,7 @@ public interface CrmStatisticsPortraitService { @@ -21,7 +17,7 @@ public interface CrmStatisticsPortraitService {
21 * @param reqVO 请求参数 17 * @param reqVO 请求参数
22 * @return 统计数据 18 * @return 统计数据
23 */ 19 */
24 - List<CrmStatisticCustomerAreaRespVO> getCustomerAreaSummary(CrmStatisticsCustomerReqVO reqVO); 20 + List<CrmStatisticCustomerAreaRespVO> getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO);
25 21
26 /** 22 /**
27 * 获取客户行业统计数据 23 * 获取客户行业统计数据
@@ -29,7 +25,7 @@ public interface CrmStatisticsPortraitService { @@ -29,7 +25,7 @@ public interface CrmStatisticsPortraitService {
29 * @param reqVO 请求参数 25 * @param reqVO 请求参数
30 * @return 统计数据 26 * @return 统计数据
31 */ 27 */
32 - List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustrySummary(CrmStatisticsCustomerReqVO reqVO); 28 + List<CrmStatisticCustomerIndustryRespVO> getCustomerSummaryByIndustry(CrmStatisticsPortraitReqVO reqVO);
33 29
34 /** 30 /**
35 * 获取客户级别统计数据 31 * 获取客户级别统计数据
@@ -37,7 +33,7 @@ public interface CrmStatisticsPortraitService { @@ -37,7 +33,7 @@ public interface CrmStatisticsPortraitService {
37 * @param reqVO 请求参数 33 * @param reqVO 请求参数
38 * @return 统计数据 34 * @return 统计数据
39 */ 35 */
40 - List<CrmStatisticCustomerLevelRespVO> getCustomerLevelSummary(CrmStatisticsCustomerReqVO reqVO); 36 + List<CrmStatisticCustomerLevelRespVO> getCustomerSummaryByLevel(CrmStatisticsPortraitReqVO reqVO);
41 37
42 /** 38 /**
43 * 获取客户来源统计数据 39 * 获取客户来源统计数据
@@ -45,6 +41,6 @@ public interface CrmStatisticsPortraitService { @@ -45,6 +41,6 @@ public interface CrmStatisticsPortraitService {
45 * @param reqVO 请求参数 41 * @param reqVO 请求参数
46 * @return 统计数据 42 * @return 统计数据
47 */ 43 */
48 - List<CrmStatisticCustomerSourceRespVO> getCustomerSourceSummary(CrmStatisticsCustomerReqVO reqVO); 44 + List<CrmStatisticCustomerSourceRespVO> getCustomerSummaryBySource(CrmStatisticsPortraitReqVO reqVO);
49 45
50 } 46 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPortraitServiceImpl.java
@@ -5,15 +5,10 @@ import cn.hutool.core.util.ObjUtil; @@ -5,15 +5,10 @@ import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.ip.core.Area; 5 import cn.iocoder.yudao.framework.ip.core.Area;
6 import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; 6 import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
7 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; 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; 8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.*;
13 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper; 9 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper;
14 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 10 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
15 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 11 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; 12 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
18 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 13 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
19 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
@@ -26,9 +21,7 @@ import java.util.Map; @@ -26,9 +21,7 @@ import java.util.Map;
26 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 22 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
28 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; 23 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
29 -import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;  
30 24
31 -// TODO @puhui999:参考 CrmStatisticsCustomerServiceImpl 代码风格,优化下这个类哈;包括命名、空行、注释等;  
32 /** 25 /**
33 * CRM 客户画像 Service 实现类 26 * CRM 客户画像 Service 实现类
34 * 27 *
@@ -44,64 +37,54 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe @@ -44,64 +37,54 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe
44 private AdminUserApi adminUserApi; 37 private AdminUserApi adminUserApi;
45 @Resource 38 @Resource
46 private DeptApi deptApi; 39 private DeptApi deptApi;
47 - @Resource  
48 - private DictDataApi dictDataApi;  
49 40
50 @Override 41 @Override
51 - public List<CrmStatisticCustomerAreaRespVO> getCustomerAreaSummary(CrmStatisticsCustomerReqVO reqVO) {  
52 - // 1. 获得用户编号数组 42 + public List<CrmStatisticCustomerAreaRespVO> getCustomerSummaryByArea(CrmStatisticsPortraitReqVO reqVO) {
  43 + // 1.1 获得用户编号数组
53 List<Long> userIds = getUserIds(reqVO); 44 List<Long> userIds = getUserIds(reqVO);
54 if (CollUtil.isEmpty(userIds)) { 45 if (CollUtil.isEmpty(userIds)) {
55 return Collections.emptyList(); 46 return Collections.emptyList();
56 } 47 }
57 reqVO.setUserIds(userIds); 48 reqVO.setUserIds(userIds);
58 - // 2. 获取客户地区统计数据  
59 - List<CrmStatisticCustomerAreaRespVO> list = portraitMapper.selectSummaryListByAreaId(reqVO); 49 + // 1.2 获取客户地区统计数据
  50 + List<CrmStatisticCustomerAreaRespVO> list = portraitMapper.selectSummaryListGroupByAreaId(reqVO);
60 if (CollUtil.isEmpty(list)) { 51 if (CollUtil.isEmpty(list)) {
61 return Collections.emptyList(); 52 return Collections.emptyList();
62 } 53 }
63 54
64 - // 拼接数据 55 + // 2. 拼接数据
65 List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); 56 List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area);
66 areaList.add(new Area().setId(null).setName("未知")); 57 areaList.add(new Area().setId(null).setName("未知"));
67 Map<Integer, Area> areaMap = convertMap(areaList, Area::getId); 58 Map<Integer, Area> areaMap = convertMap(areaList, Area::getId);
68 - List<CrmStatisticCustomerAreaRespVO> customerAreaRespVOList = convertList(list, item -> { 59 + return convertList(list, item -> {
69 Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); 60 Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE);
70 - // TODO @puhui999:找不到,可以归到未知哈;  
71 - if (parentId == null) {  
72 - return item; 61 + if (parentId == null) { // 找不到,归到未知
  62 + return item.setAreaId(null).setAreaName("未知");
73 } 63 }
74 findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); 64 findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName()));
75 return item; 65 return item;
76 }); 66 });
77 - return customerAreaRespVOList;  
78 } 67 }
79 68
80 @Override 69 @Override
81 - public List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustrySummary(CrmStatisticsCustomerReqVO reqVO) { 70 + public List<CrmStatisticCustomerIndustryRespVO> getCustomerSummaryByIndustry(CrmStatisticsPortraitReqVO reqVO) {
82 // 1. 获得用户编号数组 71 // 1. 获得用户编号数组
83 List<Long> userIds = getUserIds(reqVO); 72 List<Long> userIds = getUserIds(reqVO);
84 if (CollUtil.isEmpty(userIds)) { 73 if (CollUtil.isEmpty(userIds)) {
85 return Collections.emptyList(); 74 return Collections.emptyList();
86 } 75 }
87 reqVO.setUserIds(userIds); 76 reqVO.setUserIds(userIds);
  77 +
88 // 2. 获取客户行业统计数据 78 // 2. 获取客户行业统计数据
89 - List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = portraitMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); 79 + List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = portraitMapper.selectCustomerIndustryListGroupByIndustryId(reqVO);
90 if (CollUtil.isEmpty(industryRespVOList)) { 80 if (CollUtil.isEmpty(industryRespVOList)) {
91 return Collections.emptyList(); 81 return Collections.emptyList();
92 } 82 }
93 -  
94 - return convertList(industryRespVOList, item -> {  
95 - if (ObjUtil.isNull(item.getIndustryId())) {  
96 - return item;  
97 - }  
98 - item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId()));  
99 - return item;  
100 - }); 83 + return industryRespVOList;
101 } 84 }
102 85
103 @Override 86 @Override
104 - public List<CrmStatisticCustomerSourceRespVO> getCustomerSourceSummary(CrmStatisticsCustomerReqVO reqVO) { 87 + public List<CrmStatisticCustomerSourceRespVO> getCustomerSummaryBySource(CrmStatisticsPortraitReqVO reqVO) {
105 // 1. 获得用户编号数组 88 // 1. 获得用户编号数组
106 List<Long> userIds = getUserIds(reqVO); 89 List<Long> userIds = getUserIds(reqVO);
107 if (CollUtil.isEmpty(userIds)) { 90 if (CollUtil.isEmpty(userIds)) {
@@ -110,41 +93,28 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe @@ -110,41 +93,28 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe
110 reqVO.setUserIds(userIds); 93 reqVO.setUserIds(userIds);
111 94
112 // 2. 获取客户行业统计数据 95 // 2. 获取客户行业统计数据
113 - List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = portraitMapper.selectCustomerSourceListGroupbySource(reqVO); 96 + List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = portraitMapper.selectCustomerSourceListGroupBySource(reqVO);
114 if (CollUtil.isEmpty(sourceRespVOList)) { 97 if (CollUtil.isEmpty(sourceRespVOList)) {
115 return Collections.emptyList(); 98 return Collections.emptyList();
116 } 99 }
117 -  
118 - return convertList(sourceRespVOList, item -> {  
119 - if (ObjUtil.isNull(item.getSource())) {  
120 - return item;  
121 - }  
122 - item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource()));  
123 - return item;  
124 - }); 100 + return sourceRespVOList;
125 } 101 }
126 102
127 @Override 103 @Override
128 - public List<CrmStatisticCustomerLevelRespVO> getCustomerLevelSummary(CrmStatisticsCustomerReqVO reqVO) { 104 + public List<CrmStatisticCustomerLevelRespVO> getCustomerSummaryByLevel(CrmStatisticsPortraitReqVO reqVO) {
129 // 1. 获得用户编号数组 105 // 1. 获得用户编号数组
130 List<Long> userIds = getUserIds(reqVO); 106 List<Long> userIds = getUserIds(reqVO);
131 if (CollUtil.isEmpty(userIds)) { 107 if (CollUtil.isEmpty(userIds)) {
132 return Collections.emptyList(); 108 return Collections.emptyList();
133 } 109 }
134 reqVO.setUserIds(userIds); 110 reqVO.setUserIds(userIds);
135 - // 2. 获取客户行业统计数据  
136 - List<CrmStatisticCustomerLevelRespVO> levelRespVOList = portraitMapper.selectCustomerLevelListGroupbyLevel(reqVO); 111 +
  112 + // 2. 获取客户级别统计数据
  113 + List<CrmStatisticCustomerLevelRespVO> levelRespVOList = portraitMapper.selectCustomerLevelListGroupByLevel(reqVO);
137 if (CollUtil.isEmpty(levelRespVOList)) { 114 if (CollUtil.isEmpty(levelRespVOList)) {
138 return Collections.emptyList(); 115 return Collections.emptyList();
139 } 116 }
140 -  
141 - return convertList(levelRespVOList, item -> {  
142 - if (ObjUtil.isNull(item.getLevel())) {  
143 - return item;  
144 - }  
145 - item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel()));  
146 - return item;  
147 - }); 117 + return levelRespVOList;
148 } 118 }
149 119
150 /** 120 /**
@@ -153,7 +123,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe @@ -153,7 +123,7 @@ public class CrmStatisticsPortraitServiceImpl implements CrmStatisticsPortraitSe
153 * @param reqVO 请求参数 123 * @param reqVO 请求参数
154 * @return 用户编号数组 124 * @return 用户编号数组
155 */ 125 */
156 - private List<Long> getUserIds(CrmStatisticsCustomerReqVO reqVO) { 126 + private List<Long> getUserIds(CrmStatisticsPortraitReqVO reqVO) {
157 // 情况一:选中某个用户 127 // 情况一:选中某个用户
158 if (ObjUtil.isNotNull(reqVO.getUserId())) { 128 if (ObjUtil.isNotNull(reqVO.getUserId())) {
159 return List.of(reqVO.getUserId()); 129 return List.of(reqVO.getUserId());
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsPortraitMapper.xml
@@ -2,91 +2,60 @@ @@ -2,91 +2,60 @@
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 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"> 3 <mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPortraitMapper">
4 4
5 - <!-- TODO @puhui999:参考 CrmStatisticsCustomerMapper.xml 优化下 SQL 的排版;sql 结尾不用 ; ;XML 之间有空行; -->  
6 -  
7 - <select id="selectCustomerIndustryListGroupbyIndustryId"  
8 - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO">  
9 - SELECT  
10 - industry_id,  
11 - COUNT(*) AS customerCount,  
12 - SUM(deal_status) AS dealCount,  
13 - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS industryPortion,  
14 - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion  
15 - FROM  
16 - crm_customer  
17 - WHERE  
18 - deleted = 0 AND industry_id IS NOT NULL 5 + <select id="selectSummaryListGroupByAreaId"
  6 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO">
  7 + SELECT area_id, COUNT(*) AS customerCount, SUM(deal_status) AS dealCount
  8 + FROM crm_customer
  9 + WHERE deleted = 0 AND area_id IS NOT NULL
19 AND owner_user_id IN 10 AND owner_user_id IN
20 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> 11 <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
21 #{userId} 12 #{userId}
22 </foreach> 13 </foreach>
23 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
24 - #{times[1],javaType=java.time.LocalDateTime}  
25 - GROUP BY  
26 - industry_id; 14 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime}
  15 + AND #{times[1],javaType=java.time.LocalDateTime}
  16 + GROUP BY area_id
27 </select> 17 </select>
28 - <select id="selectCustomerSourceListGroupbySource"  
29 - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO">  
30 - SELECT  
31 - source,  
32 - COUNT(*) AS customerCount,  
33 - SUM(deal_status) AS dealCount,  
34 - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS sourcePortion,  
35 - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion  
36 - FROM  
37 - crm_customer  
38 - WHERE  
39 - deleted = 0 AND source IS NOT NULL 18 +
  19 + <select id="selectCustomerIndustryListGroupByIndustryId"
  20 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerIndustryRespVO">
  21 + SELECT industry_id, COUNT(*) AS customerCount, SUM(deal_status) AS dealCount
  22 + FROM crm_customer
  23 + WHERE deleted = 0 AND industry_id IS NOT NULL
40 AND owner_user_id IN 24 AND owner_user_id IN
41 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> 25 <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
42 #{userId} 26 #{userId}
43 </foreach> 27 </foreach>
44 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
45 - #{times[1],javaType=java.time.LocalDateTime}  
46 - GROUP BY  
47 - source; 28 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime}
  29 + AND #{times[1],javaType=java.time.LocalDateTime}
  30 + GROUP BY industry_id
48 </select> 31 </select>
49 - <select id="selectCustomerLevelListGroupbyLevel"  
50 - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO">  
51 - SELECT  
52 - level,  
53 - COUNT(*) AS customerCount,  
54 - SUM(deal_status) AS dealCount,  
55 - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS levelPortion,  
56 - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion  
57 - FROM  
58 - crm_customer  
59 - WHERE  
60 - deleted = 0 AND level IS NOT NULL 32 +
  33 + <select id="selectCustomerSourceListGroupBySource"
  34 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerSourceRespVO">
  35 + SELECT source, COUNT(*) AS customerCount, SUM(deal_status) AS dealCount
  36 + FROM crm_customer
  37 + WHERE deleted = 0 AND source IS NOT NULL
61 AND owner_user_id IN 38 AND owner_user_id IN
62 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> 39 <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
63 #{userId} 40 #{userId}
64 </foreach> 41 </foreach>
65 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
66 - #{times[1],javaType=java.time.LocalDateTime}  
67 - GROUP BY  
68 - level; 42 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime}
  43 + AND #{times[1],javaType=java.time.LocalDateTime}
  44 + GROUP BY source
69 </select> 45 </select>
70 - <select id="selectSummaryListByAreaId"  
71 - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerAreaRespVO">  
72 - SELECT  
73 - area_id,  
74 - COUNT(*) AS customerCount,  
75 - SUM(deal_status) AS dealCount,  
76 - ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS areaPortion,  
77 - ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion  
78 - FROM  
79 - crm_customer  
80 - WHERE  
81 - deleted = 0 AND area_id IS NOT NULL 46 +
  47 + <select id="selectCustomerLevelListGroupByLevel"
  48 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait.CrmStatisticCustomerLevelRespVO">
  49 + SELECT level, COUNT(*) AS customerCount, SUM(deal_status) AS dealCount
  50 + FROM crm_customer
  51 + WHERE deleted = 0 AND level IS NOT NULL
82 AND owner_user_id IN 52 AND owner_user_id IN
83 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> 53 <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
84 #{userId} 54 #{userId}
85 </foreach> 55 </foreach>
86 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
87 - #{times[1],javaType=java.time.LocalDateTime}  
88 - GROUP BY  
89 - area_id; 56 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime}
  57 + AND #{times[1],javaType=java.time.LocalDateTime}
  58 + GROUP BY level
90 </select> 59 </select>
91 60
92 </mapper> 61 </mapper>