Commit eab962725312beb7786c6431fddd4822dc89ef1d

Authored by 芋道源码
Committed by Gitee
2 parents 94b724e3 03213e32

!909 feat: [CRM-客户分析]增加[时间间隔]选项

Merge pull request !909 from dhb52/develop
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.enums;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 时间间隔类型枚举
  11 + *
  12 + * @author dhb52
  13 + */
  14 +@Getter
  15 +@AllArgsConstructor
  16 +public enum DateIntervalEnum implements IntArrayValuable {
  17 +
  18 + TODAY(1, "今天"),
  19 + YESTERDAY(2, "昨天"),
  20 + THIS_WEEK(3, "本周"),
  21 + LAST_WEEK(4, "上周"),
  22 + THIS_MONTH(5, "本月"),
  23 + LAST_MONTH(6, "上月"),
  24 + THIS_QUARTER(7, "本季度"),
  25 + LAST_QUARTER(8, "上季度"),
  26 + THIS_YEAR(9, "本年"),
  27 + LAST_YEAR(10, "去年"),
  28 + CUSTOMER(11, "自定义"),
  29 + ;
  30 +
  31 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getType).toArray();
  32 +
  33 + /**
  34 + * 类型
  35 + */
  36 + private final Integer type;
  37 +
  38 + /**
  39 + * 名称
  40 + */
  41 + private final String name;
  42 +
  43 + @Override
  44 + public int[] array() {
  45 + return ARRAYS;
  46 + }
  47 +
  48 +}
0 \ No newline at end of file 49 \ No newline at end of file
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -103,4 +103,7 @@ public interface ErrorCodeConstants { @@ -103,4 +103,7 @@ public interface ErrorCodeConstants {
103 ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); 103 ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在");
104 ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); 104 ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限");
105 105
  106 + // ========== 数据统计 1_020_014_000 ==========
  107 + ErrorCode STATISTICS_CUSTOMER_TIMES_NOT_SET = new ErrorCode(1_020_014_000, "自定义时间间隔,必须输入时间区间");
  108 +
106 } 109 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http
1 # == 1. 客户总量分析 == 1 # == 1. 客户总量分析 ==
2 ### 1.1 客户总量分析(按日) 2 ### 1.1 客户总量分析(按日)
3 -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&times[0]=2024-01-01 00:00:00&times[1]=2024-01-29 23:59:59 3 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11&times[0]=2024-01-01 00:00:00&times[1]=2024-01-29 23:59:59
4 Authorization: Bearer {{token}} 4 Authorization: Bearer {{token}}
5 tenant-id: {{adminTenentId}} 5 tenant-id: {{adminTenentId}}
6 6
7 ### 1.2 客户总量分析(按月) 7 ### 1.2 客户总量分析(按月)
8 -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 8 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
9 Authorization: Bearer {{token}} 9 Authorization: Bearer {{token}}
10 tenant-id: {{adminTenentId}} 10 tenant-id: {{adminTenentId}}
11 11
12 ### 1.3 客户总量统计(按用户) 12 ### 1.3 客户总量统计(按用户)
13 -GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 13 +GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
14 Authorization: Bearer {{token}} 14 Authorization: Bearer {{token}}
15 tenant-id: {{adminTenentId}} 15 tenant-id: {{adminTenentId}}
16 16
17 17
18 # == 2. 客户跟进次数分析 == 18 # == 2. 客户跟进次数分析 ==
19 ### 2.1 客户跟进次数分析(按日) 19 ### 2.1 客户跟进次数分析(按日)
20 -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&times[0]=2024-01-01 00:00:00&times[1]=2024-01-29 23:59:59 20 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&intervalType=11&times[0]=2024-01-01 00:00:00&times[1]=2024-01-29 23:59:59
21 Authorization: Bearer {{token}} 21 Authorization: Bearer {{token}}
22 tenant-id: {{adminTenentId}} 22 tenant-id: {{adminTenentId}}
23 23
24 ### 2.2 客户跟进次数分析(按月) 24 ### 2.2 客户跟进次数分析(按月)
25 -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 25 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
26 Authorization: Bearer {{token}} 26 Authorization: Bearer {{token}}
27 tenant-id: {{adminTenentId}} 27 tenant-id: {{adminTenentId}}
28 28
29 ### 2.3 客户总量统计(按用户) 29 ### 2.3 客户总量统计(按用户)
30 -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 30 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
31 Authorization: Bearer {{token}} 31 Authorization: Bearer {{token}}
32 tenant-id: {{adminTenentId}} 32 tenant-id: {{adminTenentId}}
33 33
34 34
35 # == 3. 客户跟进方式分析 == 35 # == 3. 客户跟进方式分析 ==
36 ### 3.1 客户跟进方式分析 36 ### 3.1 客户跟进方式分析
37 -GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 37 +GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
38 Authorization: Bearer {{token}} 38 Authorization: Bearer {{token}}
39 tenant-id: {{adminTenentId}} 39 tenant-id: {{adminTenentId}}
40 tenant-id: {{adminTenentId}} 40 tenant-id: {{adminTenentId}}
@@ -42,7 +42,7 @@ tenant-id: {{adminTenentId}} @@ -42,7 +42,7 @@ tenant-id: {{adminTenentId}}
42 42
43 # == 4. 客户成交周期 == 43 # == 4. 客户成交周期 ==
44 ### 4.1 合同摘要信息(客户转化率页面) 44 ### 4.1 合同摘要信息(客户转化率页面)
45 -GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 45 +GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
46 Authorization: Bearer {{token}} 46 Authorization: Bearer {{token}}
47 tenant-id: {{adminTenentId}} 47 tenant-id: {{adminTenentId}}
48 tenant-id: {{adminTenentId}} 48 tenant-id: {{adminTenentId}}
@@ -50,19 +50,19 @@ tenant-id: {{adminTenentId}} @@ -50,19 +50,19 @@ tenant-id: {{adminTenentId}}
50 50
51 # == 5. 客户成交周期 == 51 # == 5. 客户成交周期 ==
52 ### 5.1 客户成交周期(按日) 52 ### 5.1 客户成交周期(按日)
53 -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&times[0]=2024-01-01 00:00:00&times[1]=2024-01-29 23:59:59 53 +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&intervalType=11&times[0]=2024-01-01 00:00:00&times[1]=2024-01-29 23:59:59
54 Authorization: Bearer {{token}} 54 Authorization: Bearer {{token}}
55 tenant-id: {{adminTenentId}} 55 tenant-id: {{adminTenentId}}
56 tenant-id: {{adminTenentId}} 56 tenant-id: {{adminTenentId}}
57 57
58 ### 5.2 客户成交周期(按月) 58 ### 5.2 客户成交周期(按月)
59 -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 59 +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
60 Authorization: Bearer {{token}} 60 Authorization: Bearer {{token}}
61 tenant-id: {{adminTenentId}} 61 tenant-id: {{adminTenentId}}
62 tenant-id: {{adminTenentId}} 62 tenant-id: {{adminTenentId}}
63 63
64 ### 5.3 获取客户成交周期(按用户) 64 ### 5.3 获取客户成交周期(按用户)
65 -GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59 65 +GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100&intervalType=11&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
66 Authorization: Bearer {{token}} 66 Authorization: Bearer {{token}}
67 tenant-id: {{adminTenentId}} 67 tenant-id: {{adminTenentId}}
68 tenant-id: {{adminTenentId}} 68 tenant-id: {{adminTenentId}}
69 \ No newline at end of file 69 \ No newline at end of file
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java
1 package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; 1 package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
2 2
3 -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 3 +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
4 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
5 -import jakarta.validation.constraints.NotEmpty;  
6 import jakarta.validation.constraints.NotNull; 6 import jakarta.validation.constraints.NotNull;
7 import lombok.Data; 7 import lombok.Data;
8 import org.springframework.format.annotation.DateTimeFormat; 8 import org.springframework.format.annotation.DateTimeFormat;
@@ -28,31 +28,28 @@ public class CrmStatisticsCustomerReqVO { @@ -28,31 +28,28 @@ public class CrmStatisticsCustomerReqVO {
28 28
29 /** 29 /**
30 * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 30 * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来
31 - * <p>  
32 * 后续,可能会支持选择部分用户进行查询 31 * 后续,可能会支持选择部分用户进行查询
33 */ 32 */
34 @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2") 33 @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2")
35 private List<Long> userIds; 34 private List<Long> userIds;
36 35
37 - @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) 36 + @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  37 + @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}")
  38 + private Integer intervalType;
  39 +
  40 + /**
  41 + * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间
  42 + * 并作为参数传递给Mapper
  43 + */
  44 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
38 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 45 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
39 - @NotEmpty(message = "时间范围不能为空")  
40 private LocalDateTime[] times; 46 private LocalDateTime[] times;
41 47
42 - // TODO @dhb52:这个时间间隔,建议前端传递;例如说:字段叫 interval,枚举有天、周、月、季度、年。因为一般分析类的系统,都是交给用户选择筛选时间间隔,而我们这里是默认根据日期选项,默认对应的 interval 而已  
43 - // 然后实现上,可以在 common 包的 enums 加个 DateIntervalEnum,里面一个是 interval 字段,枚举过去,然后有个 pattern 字段,用于格式化时间格式;  
44 - // 这样的话,可以通过 interval 获取到 pattern,然后前端就可以根据 pattern 格式化时间,计算还是交给数据库  
45 /** 48 /**
46 * group by DATE_FORMAT(field, #{dateFormat}) 49 * group by DATE_FORMAT(field, #{dateFormat})
  50 + * 非前端传递, 由Service计算后传递给Mapper的参数
47 */ 51 */
48 @Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m") 52 @Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m")
49 private String sqlDateFormat; 53 private String sqlDateFormat;
50 54
51 - // TODO @dhb52:这个字段,目前是不是没啥用呀?  
52 - /**  
53 - * 数据类型 {@link CrmBizTypeEnum}  
54 - */  
55 - @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2")  
56 - private Integer bizType;  
57 -  
58 } 55 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
@@ -13,33 +13,32 @@ import java.util.List; @@ -13,33 +13,32 @@ import java.util.List;
13 @Mapper 13 @Mapper
14 public interface CrmStatisticsCustomerMapper { 14 public interface CrmStatisticsCustomerMapper {
15 15
16 - // TODO @dhb52:拼写,GroupBy。一般 idea 如果出现绿色的警告,可能是单词拼写错误,建议是要修改的哈;  
17 - List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review 16 + List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerCreateCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
18 17
19 - List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review 18 + List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerDealCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
20 19
21 - List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review 20 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerCreateCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review
22 21
23 - List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review 22 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerDealCountGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
24 23
25 - List<CrmStatisticsCustomerSummaryByUserRespVO> selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review 24 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectContractPriceGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
26 25
27 - List<CrmStatisticsCustomerSummaryByUserRespVO> selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review 26 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectReceivablePriceGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
28 27
29 - List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); 28 + List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupRecordCountGroupByDate(CrmStatisticsCustomerReqVO reqVO);
30 29
31 - List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); 30 + List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupCustomerCountGroupByDate(CrmStatisticsCustomerReqVO reqVO);
32 31
33 - List<CrmStatisticsFollowupSummaryByUserRespVO> selectFollowupRecordCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); 32 + List<CrmStatisticsFollowupSummaryByUserRespVO> selectFollowupRecordCountGroupByUser(CrmStatisticsCustomerReqVO reqVO);
34 33
35 - List<CrmStatisticsFollowupSummaryByUserRespVO> selectFollowupCustomerCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); 34 + List<CrmStatisticsFollowupSummaryByUserRespVO> selectFollowupCustomerCountGroupByUser(CrmStatisticsCustomerReqVO reqVO);
36 35
37 List<CrmStatisticsCustomerContractSummaryRespVO> selectContractSummary(CrmStatisticsCustomerReqVO reqVO); 36 List<CrmStatisticsCustomerContractSummaryRespVO> selectContractSummary(CrmStatisticsCustomerReqVO reqVO);
38 37
39 - List<CrmStatisticsFollowupSummaryByTypeRespVO> selectFollowupRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO); 38 + List<CrmStatisticsFollowupSummaryByTypeRespVO> selectFollowupRecordCountGroupByType(CrmStatisticsCustomerReqVO reqVO);
40 39
41 - List<CrmStatisticsCustomerDealCycleByDateRespVO> selectCustomerDealCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO); 40 + List<CrmStatisticsCustomerDealCycleByDateRespVO> selectCustomerDealCycleGroupByDate(CrmStatisticsCustomerReqVO reqVO);
42 41
43 - List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO); 42 + List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO);
44 43
45 } 44 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
1 package cn.iocoder.yudao.module.crm.service.statistics; 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.date.DateTime;
  5 +import cn.hutool.core.date.DateUtil;
4 import cn.hutool.core.date.LocalDateTimeUtil; 6 import cn.hutool.core.date.LocalDateTimeUtil;
5 import cn.hutool.core.util.ObjUtil; 7 import cn.hutool.core.util.ObjUtil;
  8 +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 9 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
8 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; 11 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
9 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; 12 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper;
10 -import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;  
11 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 13 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
12 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 14 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
13 import cn.iocoder.yudao.module.system.api.dict.DictDataApi; 15 import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
@@ -20,14 +22,15 @@ import org.springframework.validation.annotation.Validated; @@ -20,14 +22,15 @@ import org.springframework.validation.annotation.Validated;
20 22
21 import java.math.BigDecimal; 23 import java.math.BigDecimal;
22 import java.time.LocalDateTime; 24 import java.time.LocalDateTime;
23 -import java.util.ArrayList;  
24 import java.util.Collections; 25 import java.util.Collections;
25 import java.util.List; 26 import java.util.List;
26 import java.util.Map; 27 import java.util.Map;
27 import java.util.stream.Stream; 28 import java.util.stream.Stream;
28 29
  30 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
29 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
30 import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; 32 import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
  33 +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.STATISTICS_CUSTOMER_TIMES_NOT_SET;
31 34
32 /** 35 /**
33 * CRM 客户分析 Service 实现类 36 * CRM 客户分析 Service 实现类
@@ -58,114 +61,107 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -58,114 +61,107 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
58 @Override 61 @Override
59 public List<CrmStatisticsCustomerSummaryByDateRespVO> getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { 62 public List<CrmStatisticsCustomerSummaryByDateRespVO> getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
60 // 1. 获得用户编号数组 63 // 1. 获得用户编号数组
61 - final List<Long> userIds = getUserIds(reqVO); 64 + List<Long> userIds = getUserIds(reqVO);
62 if (CollUtil.isEmpty(userIds)) { 65 if (CollUtil.isEmpty(userIds)) {
63 return Collections.emptyList(); 66 return Collections.emptyList();
64 } 67 }
65 reqVO.setUserIds(userIds); 68 reqVO.setUserIds(userIds);
66 69
67 // 2. 获取分项统计数据 70 // 2. 获取分项统计数据
68 - // TODO @dhb52:如果是 list 变量,要么 List 要么 s 后缀  
69 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));  
70 - final List<CrmStatisticsCustomerSummaryByDateRespVO> customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyDate(reqVO);  
71 - final List<CrmStatisticsCustomerSummaryByDateRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupbyDate(reqVO);  
72 -  
73 - // 3. 获取时间序列  
74 - // TODO @dhb52:3 和 4 其实做的是一类事情,所以可以考虑 3.1 获取时间序列、3.2 合并统计数据 这样注释;然后中间就不空行了;就是说,一般空行的目的,是让逻辑分片,看着整体性更好,但是不能让逻辑感觉碎碎的;  
75 - final List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);  
76 -  
77 - // 4. 合并统计数据  
78 - // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...)  
79 - List<CrmStatisticsCustomerSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());  
80 - final Map<String, Integer> customerCreateCountMap = convertMap(customerCreateCount, 71 + initParams(reqVO);
  72 + List<CrmStatisticsCustomerSummaryByDateRespVO> customerCreateCountVoList = customerMapper.selectCustomerCreateCountGroupByDate(reqVO);
  73 + List<CrmStatisticsCustomerSummaryByDateRespVO> customerDealCountVoList = customerMapper.selectCustomerDealCountGroupByDate(reqVO);
  74 +
  75 + // 3. 合并数据
  76 + List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
  77 + Map<String, Integer> customerCreateCountMap = convertMap(customerCreateCountVoList,
81 CrmStatisticsCustomerSummaryByDateRespVO::getTime, 78 CrmStatisticsCustomerSummaryByDateRespVO::getTime,
82 CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); 79 CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount);
83 - final Map<String, Integer> customerDealCountMap = convertMap(customerDealCount, 80 + Map<String, Integer> customerDealCountMap = convertMap(customerDealCountVoList,
84 CrmStatisticsCustomerSummaryByDateRespVO::getTime, 81 CrmStatisticsCustomerSummaryByDateRespVO::getTime,
85 CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); 82 CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount);
86 - times.forEach(time -> respVoList.add(  
87 - new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time) 83 + List<CrmStatisticsCustomerSummaryByDateRespVO> respVoList = convertList(times,
  84 + time -> new CrmStatisticsCustomerSummaryByDateRespVO()
  85 + .setTime(time)
88 .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0)) 86 .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
89 - .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))  
90 - )); 87 + .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)));
  88 +
91 return respVoList; 89 return respVoList;
92 } 90 }
93 91
94 @Override 92 @Override
95 public List<CrmStatisticsCustomerSummaryByUserRespVO> getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { 93 public List<CrmStatisticsCustomerSummaryByUserRespVO> getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) {
96 // 1. 获得用户编号数组 94 // 1. 获得用户编号数组
97 - final List<Long> userIds = getUserIds(reqVO); 95 + List<Long> userIds = getUserIds(reqVO);
98 if (CollUtil.isEmpty(userIds)) { 96 if (CollUtil.isEmpty(userIds)) {
99 return Collections.emptyList(); 97 return Collections.emptyList();
100 } 98 }
101 reqVO.setUserIds(userIds); 99 reqVO.setUserIds(userIds);
102 100
103 // 2. 获取分项统计数据 101 // 2. 获取分项统计数据
104 - final List<CrmStatisticsCustomerSummaryByUserRespVO> customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyUser(reqVO);  
105 - final List<CrmStatisticsCustomerSummaryByUserRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO);  
106 - final List<CrmStatisticsCustomerSummaryByUserRespVO> contractPrice = customerMapper.selectContractPriceGroupbyUser(reqVO);  
107 - final List<CrmStatisticsCustomerSummaryByUserRespVO> receivablePrice = customerMapper.selectReceivablePriceGroupbyUser(reqVO); 102 + initParams(reqVO);
  103 + List<CrmStatisticsCustomerSummaryByUserRespVO> customerCreateCount = customerMapper.selectCustomerCreateCountGroupByUser(reqVO);
  104 + List<CrmStatisticsCustomerSummaryByUserRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO);
  105 + List<CrmStatisticsCustomerSummaryByUserRespVO> contractPrice = customerMapper.selectContractPriceGroupByUser(reqVO);
  106 + List<CrmStatisticsCustomerSummaryByUserRespVO> receivablePrice = customerMapper.selectReceivablePriceGroupByUser(reqVO);
108 107
109 // 3. 合并统计数据 108 // 3. 合并统计数据
110 - final Map<Long, Integer> customerCreateCountMap = convertMap(customerCreateCount, 109 + Map<Long, Integer> customerCreateCountMap = convertMap(customerCreateCount,
111 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, 110 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
112 CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); 111 CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount);
113 - final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount, 112 + Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
114 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, 113 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
115 CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); 114 CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
116 - final Map<Long, BigDecimal> contractPriceMap = convertMap(contractPrice, 115 + Map<Long, BigDecimal> contractPriceMap = convertMap(contractPrice,
117 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, 116 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
118 CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); 117 CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice);
119 - final Map<Long, BigDecimal> receivablePriceMap = convertMap(receivablePrice, 118 + Map<Long, BigDecimal> receivablePriceMap = convertMap(receivablePrice,
120 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, 119 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
121 CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); 120 CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice);
122 - List<CrmStatisticsCustomerSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());  
123 - userIds.forEach(userId -> {  
124 - final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO(); 121 + List<CrmStatisticsCustomerSummaryByUserRespVO> respVoList = convertList(userIds, userId -> {
  122 + CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO();
  123 + // ownerUserId 为基类属性
125 vo.setOwnerUserId(userId); 124 vo.setOwnerUserId(userId);
126 vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) 125 vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0))
127 .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)) 126 .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))
128 .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO)) 127 .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))
129 .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO)); 128 .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO));
130 - respVoList.add(vo); 129 + return vo;
131 }); 130 });
132 131
133 // 4. 拼接用户信息 132 // 4. 拼接用户信息
134 appendUserInfo(respVoList); 133 appendUserInfo(respVoList);
  134 +
135 return respVoList; 135 return respVoList;
136 } 136 }
137 137
138 @Override 138 @Override
139 public List<CrmStatisticsFollowupSummaryByDateRespVO> getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO) { 139 public List<CrmStatisticsFollowupSummaryByDateRespVO> getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
140 // 1. 获得用户编号数组 140 // 1. 获得用户编号数组
141 - final List<Long> userIds = getUserIds(reqVO); 141 + List<Long> userIds = getUserIds(reqVO);
142 if (CollUtil.isEmpty(userIds)) { 142 if (CollUtil.isEmpty(userIds)) {
143 return Collections.emptyList(); 143 return Collections.emptyList();
144 } 144 }
145 reqVO.setUserIds(userIds); 145 reqVO.setUserIds(userIds);
146 146
147 // 2. 获取分项统计数据 147 // 2. 获取分项统计数据
148 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));  
149 - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());  
150 - final List<CrmStatisticsFollowupSummaryByDateRespVO> followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyDate(reqVO);  
151 - final List<CrmStatisticsFollowupSummaryByDateRespVO> followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyDate(reqVO);  
152 -  
153 - // 3. 获取时间序列  
154 - final List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); 148 + initParams(reqVO);
  149 + List<CrmStatisticsFollowupSummaryByDateRespVO> followupRecordCount = customerMapper.selectFollowupRecordCountGroupByDate(reqVO);
  150 + List<CrmStatisticsFollowupSummaryByDateRespVO> followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByDate(reqVO);
155 151
156 - // 4. 合并统计数据  
157 - List<CrmStatisticsFollowupSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());  
158 - final Map<String, Integer> followupRecordCountMap = convertMap(followupRecordCount, 152 + // 3. 合并统计数据
  153 + List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
  154 + Map<String, Integer> followupRecordCountMap = convertMap(followupRecordCount,
159 CrmStatisticsFollowupSummaryByDateRespVO::getTime, 155 CrmStatisticsFollowupSummaryByDateRespVO::getTime,
160 CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); 156 CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount);
161 - final Map<String, Integer> followupCustomerCountMap = convertMap(followupCustomerCount, 157 + Map<String, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
162 CrmStatisticsFollowupSummaryByDateRespVO::getTime, 158 CrmStatisticsFollowupSummaryByDateRespVO::getTime,
163 CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); 159 CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount);
164 - times.forEach(time -> respVoList.add( 160 + List<CrmStatisticsFollowupSummaryByDateRespVO> respVoList = convertList(times, time ->
165 new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time) 161 new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)
166 .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0)) 162 .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))
167 .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) 163 .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0))
168 - )); 164 + );
169 165
170 return respVoList; 166 return respVoList;
171 } 167 }
@@ -173,31 +169,31 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -173,31 +169,31 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
173 @Override 169 @Override
174 public List<CrmStatisticsFollowupSummaryByUserRespVO> getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO) { 170 public List<CrmStatisticsFollowupSummaryByUserRespVO> getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO) {
175 // 1. 获得用户编号数组 171 // 1. 获得用户编号数组
176 - final List<Long> userIds = getUserIds(reqVO); 172 + List<Long> userIds = getUserIds(reqVO);
177 if (CollUtil.isEmpty(userIds)) { 173 if (CollUtil.isEmpty(userIds)) {
178 return Collections.emptyList(); 174 return Collections.emptyList();
179 } 175 }
180 reqVO.setUserIds(userIds); 176 reqVO.setUserIds(userIds);
181 177
182 // 2. 获取分项统计数据 178 // 2. 获取分项统计数据
183 - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());  
184 - final List<CrmStatisticsFollowupSummaryByUserRespVO> followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyUser(reqVO);  
185 - final List<CrmStatisticsFollowupSummaryByUserRespVO> followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyUser(reqVO); 179 + initParams(reqVO);
  180 + List<CrmStatisticsFollowupSummaryByUserRespVO> followupRecordCount = customerMapper.selectFollowupRecordCountGroupByUser(reqVO);
  181 + List<CrmStatisticsFollowupSummaryByUserRespVO> followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByUser(reqVO);
186 182
187 // 3. 合并统计数据 183 // 3. 合并统计数据
188 - final Map<Long, Integer> followupRecordCountMap = convertMap(followupRecordCount, 184 + Map<Long, Integer> followupRecordCountMap = convertMap(followupRecordCount,
189 CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, 185 CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
190 CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); 186 CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount);
191 - final Map<Long, Integer> followupCustomerCountMap = convertMap(followupCustomerCount, 187 + Map<Long, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
192 CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId, 188 CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
193 CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); 189 CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount);
194 - List<CrmStatisticsFollowupSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());  
195 - userIds.forEach(userId -> {  
196 - final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO() 190 + List<CrmStatisticsFollowupSummaryByUserRespVO> respVoList = convertList(userIds, userId -> {
  191 + CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO()
197 .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0)) 192 .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))
198 .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); 193 .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0));
  194 + // ownerUserId 为基类属性
199 vo.setOwnerUserId(userId); 195 vo.setOwnerUserId(userId);
200 - respVoList.add(vo); 196 + return vo;
201 }); 197 });
202 198
203 // 4. 拼接用户信息 199 // 4. 拼接用户信息
@@ -208,19 +204,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -208,19 +204,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
208 @Override 204 @Override
209 public List<CrmStatisticsFollowupSummaryByTypeRespVO> getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO) { 205 public List<CrmStatisticsFollowupSummaryByTypeRespVO> getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO) {
210 // 1. 获得用户编号数组 206 // 1. 获得用户编号数组
211 - final List<Long> userIds = getUserIds(reqVO); 207 + List<Long> userIds = getUserIds(reqVO);
212 if (CollUtil.isEmpty(userIds)) { 208 if (CollUtil.isEmpty(userIds)) {
213 return Collections.emptyList(); 209 return Collections.emptyList();
214 } 210 }
215 reqVO.setUserIds(userIds); 211 reqVO.setUserIds(userIds);
216 212
217 // 2. 获得排行数据 213 // 2. 获得排行数据
218 - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());  
219 - List<CrmStatisticsFollowupSummaryByTypeRespVO> respVoList = customerMapper.selectFollowupRecordCountGroupbyType(reqVO); 214 + initParams(reqVO);
  215 + List<CrmStatisticsFollowupSummaryByTypeRespVO> respVoList = customerMapper.selectFollowupRecordCountGroupByType(reqVO);
220 216
221 // 3. 获取字典数据 217 // 3. 获取字典数据
222 List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE); 218 List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE);
223 - final Map<String, String> followUpTypeMap = convertMap(followUpTypes, 219 + Map<String, String> followUpTypeMap = convertMap(followUpTypes,
224 DictDataRespDTO::getValue, DictDataRespDTO::getLabel); 220 DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
225 respVoList.forEach(vo -> { 221 respVoList.forEach(vo -> {
226 vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType())); 222 vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType()));
@@ -232,26 +228,27 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -232,26 +228,27 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
232 @Override 228 @Override
233 public List<CrmStatisticsCustomerContractSummaryRespVO> getContractSummary(CrmStatisticsCustomerReqVO reqVO) { 229 public List<CrmStatisticsCustomerContractSummaryRespVO> getContractSummary(CrmStatisticsCustomerReqVO reqVO) {
234 // 1. 获得用户编号数组 230 // 1. 获得用户编号数组
235 - final List<Long> userIds = getUserIds(reqVO); 231 + List<Long> userIds = getUserIds(reqVO);
236 if (CollUtil.isEmpty(userIds)) { 232 if (CollUtil.isEmpty(userIds)) {
237 return Collections.emptyList(); 233 return Collections.emptyList();
238 } 234 }
239 reqVO.setUserIds(userIds); 235 reqVO.setUserIds(userIds);
240 236
241 // 2. 获取统计数据 237 // 2. 获取统计数据
  238 + initParams(reqVO);
242 List<CrmStatisticsCustomerContractSummaryRespVO> respVoList = customerMapper.selectContractSummary(reqVO); 239 List<CrmStatisticsCustomerContractSummaryRespVO> respVoList = customerMapper.selectContractSummary(reqVO);
243 240
244 // 3. 设置 创建人、负责人、行业、来源 241 // 3. 设置 创建人、负责人、行业、来源
245 - // 获取客户所属行业 242 + // 3.1 获取客户所属行业
246 Map<String, String> industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY), 243 Map<String, String> industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY),
247 DictDataRespDTO::getValue, DictDataRespDTO::getLabel); 244 DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
248 - // 获取客户来源 245 + // 3.2 获取客户来源
249 Map<String, String> sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE), 246 Map<String, String> sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE),
250 DictDataRespDTO::getValue, DictDataRespDTO::getLabel); 247 DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
251 - // 获取创建人、负责人列表 248 + // 3.3 获取创建人、负责人列表
252 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList, 249 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList,
253 vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); 250 vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
254 - 251 + // 3.4 设置 创建人、负责人、行业、来源
255 respVoList.forEach(vo -> { 252 respVoList.forEach(vo -> {
256 MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); 253 MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
257 MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName); 254 MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
@@ -266,60 +263,57 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -266,60 +263,57 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
266 @Override 263 @Override
267 public List<CrmStatisticsCustomerDealCycleByDateRespVO> getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) { 264 public List<CrmStatisticsCustomerDealCycleByDateRespVO> getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) {
268 // 1. 获得用户编号数组 265 // 1. 获得用户编号数组
269 - final List<Long> userIds = getUserIds(reqVO); 266 + List<Long> userIds = getUserIds(reqVO);
270 if (CollUtil.isEmpty(userIds)) { 267 if (CollUtil.isEmpty(userIds)) {
271 return Collections.emptyList(); 268 return Collections.emptyList();
272 } 269 }
273 reqVO.setUserIds(userIds); 270 reqVO.setUserIds(userIds);
274 271
275 // 2. 获取分项统计数据 272 // 2. 获取分项统计数据
276 - reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));  
277 - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());  
278 - final List<CrmStatisticsCustomerDealCycleByDateRespVO> customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyDate(reqVO);  
279 -  
280 - // 3. 获取时间序列  
281 - final List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]); 273 + initParams(reqVO);
  274 + List<CrmStatisticsCustomerDealCycleByDateRespVO> customerDealCycle = customerMapper.selectCustomerDealCycleGroupByDate(reqVO);
282 275
283 - // 4. 合并统计数据  
284 - List<CrmStatisticsCustomerDealCycleByDateRespVO> respVoList = new ArrayList<>(times.size());  
285 - final Map<String, Double> customerDealCycleMap = convertMap(customerDealCycle, 276 + // 3. 合并统计数据
  277 + List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
  278 + Map<String, Double> customerDealCycleMap = convertMap(customerDealCycle,
286 CrmStatisticsCustomerDealCycleByDateRespVO::getTime, 279 CrmStatisticsCustomerDealCycleByDateRespVO::getTime,
287 CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); 280 CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle);
288 - times.forEach(time -> respVoList.add( 281 + List<CrmStatisticsCustomerDealCycleByDateRespVO> respVoList = convertList(times, time ->
289 new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time) 282 new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
290 .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) 283 .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
291 - )); 284 + );
  285 +
292 return respVoList; 286 return respVoList;
293 } 287 }
294 288
295 @Override 289 @Override
296 public List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) { 290 public List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) {
297 // 1. 获得用户编号数组 291 // 1. 获得用户编号数组
298 - final List<Long> userIds = getUserIds(reqVO); 292 + List<Long> userIds = getUserIds(reqVO);
299 if (CollUtil.isEmpty(userIds)) { 293 if (CollUtil.isEmpty(userIds)) {
300 return Collections.emptyList(); 294 return Collections.emptyList();
301 } 295 }
302 reqVO.setUserIds(userIds); 296 reqVO.setUserIds(userIds);
303 297
304 // 2. 获取分项统计数据 298 // 2. 获取分项统计数据
305 - reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());  
306 - final List<CrmStatisticsCustomerDealCycleByUserRespVO> customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyUser(reqVO);  
307 - final List<CrmStatisticsCustomerSummaryByUserRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO); 299 + initParams(reqVO);
  300 + List<CrmStatisticsCustomerDealCycleByUserRespVO> customerDealCycle = customerMapper.selectCustomerDealCycleGroupByUser(reqVO);
  301 + List<CrmStatisticsCustomerSummaryByUserRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO);
308 302
309 // 3. 合并统计数据 303 // 3. 合并统计数据
310 - final Map<Long, Double> customerDealCycleMap = convertMap(customerDealCycle, 304 + Map<Long, Double> customerDealCycleMap = convertMap(customerDealCycle,
311 CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId, 305 CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,
312 CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); 306 CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle);
313 - final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount, 307 + Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
314 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId, 308 CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
315 CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); 309 CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
316 - List<CrmStatisticsCustomerDealCycleByUserRespVO> respVoList = new ArrayList<>(userIds.size());  
317 - userIds.forEach(userId -> {  
318 - final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO() 310 + List<CrmStatisticsCustomerDealCycleByUserRespVO> respVoList = convertList(userIds, userId -> {
  311 + CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO()
319 .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0)) 312 .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))
320 .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); 313 .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0));
  314 + // ownerUserId 为基类属性
321 vo.setOwnerUserId(userId); 315 vo.setOwnerUserId(userId);
322 - respVoList.add(vo); 316 + return vo;
323 }); 317 });
324 318
325 // 4. 拼接用户信息 319 // 4. 拼接用户信息
@@ -335,8 +329,9 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -335,8 +329,9 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
335 */ 329 */
336 private <T extends CrmStatisticsCustomerByUserBaseRespVO> void appendUserInfo(List<T> respVoList) { 330 private <T extends CrmStatisticsCustomerByUserBaseRespVO> void appendUserInfo(List<T> respVoList) {
337 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(respVoList, 331 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(respVoList,
338 - CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));  
339 - respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); 332 + CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
  333 + respVoList.forEach(vo -> MapUtils.findAndThen(userMap,
  334 + vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
340 } 335 }
341 336
342 /** 337 /**
@@ -352,7 +347,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -352,7 +347,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
352 } 347 }
353 // 情况二:选中某个部门 348 // 情况二:选中某个部门
354 // 2.1 获得部门列表 349 // 2.1 获得部门列表
355 - final Long deptId = reqVO.getDeptId(); 350 + Long deptId = reqVO.getDeptId();
356 List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); 351 List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
357 deptIds.add(deptId); 352 deptIds.add(deptId);
358 // 2.2 获得用户编号 353 // 2.2 获得用户编号
@@ -378,7 +373,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -378,7 +373,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
378 * @param endTime 结束时间 373 * @param endTime 结束时间
379 * @return 时间序列 374 * @return 时间序列
380 */ 375 */
381 - // TODO @dhb52:可以抽象到 DateUtils 里,开始时间、结束时间,事件间隔,然后返回这个哈;  
382 private List<String> generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) { 376 private List<String> generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) {
383 boolean byMonth = queryByMonth(startTime, endTime); 377 boolean byMonth = queryByMonth(startTime, endTime);
384 List<String> times = CollUtil.newArrayList(); 378 List<String> times = CollUtil.newArrayList();
@@ -404,4 +398,62 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -404,4 +398,62 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
404 return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY; 398 return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY;
405 } 399 }
406 400
  401 + private void initParams(CrmStatisticsCustomerReqVO reqVO) {
  402 + final Integer intervalType = reqVO.getIntervalType();
  403 +
  404 + // 1. 自定义时间间隔,必须输入起始日期-结束日期
  405 + if (DateIntervalEnum.CUSTOMER.getType().equals(intervalType)) {
  406 + if (ObjUtil.isEmpty(reqVO.getTimes()) || reqVO.getTimes().length != 2) {
  407 + throw exception(STATISTICS_CUSTOMER_TIMES_NOT_SET);
  408 + }
  409 + // 设置 mapper sqlDateFormat 参数
  410 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
  411 + // 自定义日期无需计算日期参数
  412 + return;
  413 + }
  414 +
  415 + // 2. 根据时间区间类型计算时间段区间日期
  416 + DateTime beginDate = null;
  417 + DateTime endDate = null;
  418 + if (DateIntervalEnum.TODAY.getType().equals(intervalType)) {
  419 + beginDate = DateUtil.beginOfDay(DateUtil.date());
  420 + endDate = DateUtil.endOfDay(DateUtil.date());
  421 + } else if (DateIntervalEnum.YESTERDAY.getType().equals(intervalType)) {
  422 + beginDate = DateUtil.offsetDay(DateUtil.date(), -1);
  423 + endDate = DateUtil.offsetDay(DateUtil.date(), -1);
  424 + } else if (DateIntervalEnum.THIS_WEEK.getType().equals(intervalType)) {
  425 + beginDate = DateUtil.beginOfWeek(DateUtil.date());
  426 + endDate = DateUtil.endOfWeek(DateUtil.date());
  427 + } else if (DateIntervalEnum.LAST_WEEK.getType().equals(intervalType)) {
  428 + beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
  429 + endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
  430 + } else if (DateIntervalEnum.THIS_MONTH.getType().equals(intervalType)) {
  431 + beginDate = DateUtil.beginOfMonth(DateUtil.date());
  432 + endDate = DateUtil.endOfMonth(DateUtil.date());
  433 + } else if (DateIntervalEnum.LAST_MONTH.getType().equals(intervalType)) {
  434 + beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
  435 + endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
  436 + } else if (DateIntervalEnum.THIS_QUARTER.getType().equals(intervalType)) {
  437 + beginDate = DateUtil.beginOfQuarter(DateUtil.date());
  438 + endDate = DateUtil.endOfQuarter(DateUtil.date());
  439 + } else if (DateIntervalEnum.LAST_QUARTER.getType().equals(intervalType)) {
  440 + beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
  441 + endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
  442 + } else if (DateIntervalEnum.THIS_YEAR.getType().equals(intervalType)) {
  443 + beginDate = DateUtil.beginOfYear(DateUtil.date());
  444 + endDate = DateUtil.endOfYear(DateUtil.date());
  445 + } else if (DateIntervalEnum.LAST_YEAR.getType().equals(intervalType)) {
  446 + beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
  447 + endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
  448 + }
  449 +
  450 + // 3. 计算开始、结束日期时间,并设置reqVo
  451 + LocalDateTime[] times = new LocalDateTime[2];
  452 + times[0] = LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.of(beginDate));
  453 + times[1] = LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.of(endDate));
  454 + // 3.1 设置 mapper 时间区间 参数
  455 + reqVO.setTimes(times);
  456 + // 3.2 设置 mapper sqlDateFormat 参数
  457 + reqVO.setSqlDateFormat(getSqlDateFormat(times[0], times[1]));
  458 + }
407 } 459 }
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
@@ -2,251 +2,233 @@ @@ -2,251 +2,233 @@
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.CrmStatisticsCustomerMapper"> 3 <mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper">
4 4
5 - <!-- TODO @dhb52:数据库的关键字,进行大写。例如说,COUNT -->  
6 -  
7 - <select id="selectCustomerCreateCountGroupbyDate" 5 + <select id="selectCustomerCreateCountGroupByDate"
8 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO"> 6 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
9 SELECT 7 SELECT
10 - <!-- TODO @dhb52:下面这个,缩进一个 tab;这样可读性更好哈 -->  
11 - DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,  
12 - COUNT(*) AS customerCreateCount  
13 - FROM crm_customer  
14 - WHERE deleted = 0  
15 - AND owner_user_id IN  
16 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
17 - #{userId}  
18 - </foreach>  
19 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
20 - <!-- TODO @dhb52:这可以考虑不换行,直接跟在后面的 AND,更连贯哈; -->  
21 - #{times[1],javaType=java.time.LocalDateTime}  
22 - GROUP BY time 8 + DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,
  9 + COUNT(*) AS customerCreateCount
  10 + FROM crm_customer
  11 + WHERE deleted = 0
  12 + AND owner_user_id IN
  13 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  14 + #{userId}
  15 + </foreach>
  16 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  17 + GROUP BY time
23 </select> 18 </select>
24 19
25 - <select id="selectCustomerDealCountGroupbyDate" 20 + <select id="selectCustomerDealCountGroupByDate"
26 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO"> 21 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
27 SELECT 22 SELECT
28 - <!-- TODO @dhb52:下面这个,缩进一个 tab;这样可读性更好哈 -->  
29 - <!-- TODO @dhb52:表变量最好不要用 a、b;可以用 customer 和 constract;虽然长一点,但是一眼看的清楚哈 -->  
30 - DATE_FORMAT( b.order_date, #{sqlDateFormat} ) AS time,  
31 - count( DISTINCT a.id ) AS customerDealCount  
32 - FROM crm_customer AS a  
33 - LEFT JOIN crm_contract AS b ON b.customer_id = a.id  
34 - WHERE a.deleted = 0 AND b.deleted = 0  
35 - AND b.audit_status = 20  
36 - AND a.owner_user_id IN  
37 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
38 - #{userId}  
39 - </foreach>  
40 - <!-- TODO @dhb52:这个应该是 order_date 的范围哈;貌似如果改成这样,不需要查询 customer 表,只要 contract 表就 ok 拉 -->  
41 - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
42 - #{times[1],javaType=java.time.LocalDateTime} 23 + DATE_FORMAT( order_date, #{sqlDateFormat} ) AS time,
  24 + COUNT( DISTINCT customer_id ) AS customerDealCount
  25 + FROM crm_contract
  26 + WHERE deleted = 0
  27 + AND audit_status = 20
  28 + AND owner_user_id IN
  29 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  30 + #{userId}
  31 + </foreach>
  32 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
43 GROUP BY time 33 GROUP BY time
44 </select> 34 </select>
45 35
46 - <!-- TODO @dhb52:根据上面建议,进行优化 -->  
47 - <select id="selectCustomerCreateCountGroupbyUser" 36 + <select id="selectCustomerCreateCountGroupByUser"
48 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO"> 37 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
49 - SELECT owner_user_id, COUNT(1) AS customer_create_count  
50 - FROM crm_customer  
51 - WHERE deleted = 0  
52 - AND owner_user_id in  
53 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
54 - #{userId}  
55 - </foreach>  
56 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
57 - #{times[1],javaType=java.time.LocalDateTime} 38 + SELECT
  39 + owner_user_id,
  40 + COUNT(1) AS customer_create_count
  41 + FROM crm_customer
  42 + WHERE deleted = 0
  43 + AND owner_user_id in
  44 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  45 + #{userId}
  46 + </foreach>
  47 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
58 GROUP BY owner_user_id 48 GROUP BY owner_user_id
59 </select> 49 </select>
60 50
61 - <!-- TODO @dhb52:根据上面建议,进行优化 -->  
62 - <select id="selectCustomerDealCountGroupbyUser" 51 + <select id="selectCustomerDealCountGroupByUser"
63 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO"> 52 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
64 - SELECT a.owner_user_id, count( DISTINCT a.id ) AS customer_deal_count  
65 - FROM crm_customer AS a  
66 - LEFT JOIN crm_contract AS b ON b.customer_id = a.id  
67 - WHERE a.deleted = 0 AND b.deleted = 0  
68 - AND b.audit_status = 20  
69 - AND a.owner_user_id IN  
70 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
71 - #{userId}  
72 - </foreach>  
73 - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
74 - #{times[1],javaType=java.time.LocalDateTime}  
75 - GROUP BY a.owner_user_id 53 + SELECT
  54 + customer.owner_user_id,
  55 + COUNT( DISTINCT customer.id ) AS customer_deal_count
  56 + FROM crm_customer AS customer
  57 + LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
  58 + WHERE customer.deleted = 0 AND contract.deleted = 0
  59 + AND contract.audit_status = 20
  60 + AND customer.owner_user_id IN
  61 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  62 + #{userId}
  63 + </foreach>
  64 + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  65 + GROUP BY customer.owner_user_id
76 </select> 66 </select>
77 67
78 - <!-- TODO @dhb52:根据上面建议,进行优化 -->  
79 - <select id="selectContractPriceGroupbyUser" 68 + <select id="selectContractPriceGroupByUser"
80 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO"> 69 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
81 - SELECT owner_user_id, IFNULL(SUM(total_price), 0) AS contract_price  
82 - FROM crm_contract  
83 - WHERE deleted = 0  
84 - AND audit_status = 20  
85 - AND owner_user_id in  
86 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
87 - #{userId}  
88 - </foreach>  
89 - AND order_date BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
90 - #{times[1],javaType=java.time.LocalDateTime}  
91 - GROUP BY owner_user_id 70 + SELECT
  71 + owner_user_id,
  72 + IFNULL(SUM(total_price), 0) AS contract_price
  73 + FROM crm_contract
  74 + WHERE deleted = 0
  75 + AND audit_status = 20
  76 + AND owner_user_id in
  77 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  78 + #{userId}
  79 + </foreach>
  80 + AND order_date BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  81 + GROUP BY owner_user_id
92 </select> 82 </select>
93 83
94 -  
95 - <!-- TODO @dhb52:根据上面建议,进行优化 -->  
96 - <select id="selectReceivablePriceGroupbyUser" 84 + <select id="selectReceivablePriceGroupByUser"
97 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO"> 85 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
98 - SELECT owner_user_id,  
99 - IFNULL(SUM(price), 0) AS receivable_price  
100 - FROM crm_receivable  
101 - WHERE deleted = 0  
102 - AND audit_status = 20  
103 - AND owner_user_id IN  
104 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
105 - #{userId}  
106 - </foreach>  
107 - AND return_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
108 - #{times[1],javaType=java.time.LocalDateTime}  
109 - GROUP BY owner_user_id 86 + SELECT
  87 + owner_user_id,
  88 + IFNULL(SUM(price), 0) AS receivable_price
  89 + FROM crm_receivable
  90 + WHERE deleted = 0
  91 + AND audit_status = 20
  92 + AND owner_user_id IN
  93 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  94 + #{userId}
  95 + </foreach>
  96 + AND return_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  97 + GROUP BY owner_user_id
110 </select> 98 </select>
111 99
112 - <select id="selectFollowupRecordCountGroupbyDate" 100 + <select id="selectFollowupRecordCountGroupByDate"
113 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByDateRespVO"> 101 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByDateRespVO">
114 - SELECT DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,  
115 - count(*) AS followup_record_count  
116 - FROM crm_follow_up_record  
117 - WHERE creator IN  
118 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
119 - #{userId}  
120 - </foreach>  
121 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
122 - #{times[1],javaType=java.time.LocalDateTime}  
123 - AND biz_type = #{bizType}  
124 - GROUP BY time 102 + SELECT
  103 + DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,
  104 + COUNT(*) AS followup_record_count
  105 + FROM crm_follow_up_record
  106 + WHERE creator IN
  107 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  108 + #{userId}
  109 + </foreach>
  110 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  111 + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type}
  112 + GROUP BY time
125 </select> 113 </select>
126 114
127 - <select id="selectFollowupCustomerCountGroupbyDate" 115 + <select id="selectFollowupCustomerCountGroupByDate"
128 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByDateRespVO"> 116 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByDateRespVO">
129 SELECT 117 SELECT
130 - DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,  
131 - count(DISTINCT biz_id) AS followup_customer_count  
132 - FROM crm_follow_up_record  
133 - WHERE creator IN  
134 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
135 - #{userId}  
136 - </foreach>  
137 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
138 - #{times[1],javaType=java.time.LocalDateTime}  
139 - AND biz_type = #{bizType}  
140 - GROUP BY time 118 + DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,
  119 + COUNT(DISTINCT biz_id) AS followup_customer_count
  120 + FROM crm_follow_up_record
  121 + WHERE creator IN
  122 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  123 + #{userId}
  124 + </foreach>
  125 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  126 + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type}
  127 + GROUP BY time
141 </select> 128 </select>
142 129
143 - <select id="selectFollowupRecordCountGroupbyUser" 130 + <select id="selectFollowupRecordCountGroupByUser"
144 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByUserRespVO"> 131 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByUserRespVO">
145 - SELECT creator as owner_user_id,  
146 - count(*) AS followup_record_count  
147 - FROM crm_follow_up_record  
148 - WHERE creator IN  
149 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
150 - #{userId}  
151 - </foreach>  
152 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
153 - #{times[1],javaType=java.time.LocalDateTime}  
154 - AND biz_type = #{bizType}  
155 - GROUP BY creator 132 + SELECT
  133 + creator as owner_user_id,
  134 + COUNT(*) AS followup_record_count
  135 + FROM crm_follow_up_record
  136 + WHERE creator IN
  137 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  138 + #{userId}
  139 + </foreach>
  140 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  141 + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type}
  142 + GROUP BY creator
156 </select> 143 </select>
157 144
158 - <select id="selectFollowupCustomerCountGroupbyUser" 145 + <select id="selectFollowupCustomerCountGroupByUser"
159 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByUserRespVO"> 146 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByUserRespVO">
160 - SELECT creator as owner_user_id,  
161 - count(DISTINCT biz_id) AS followup_customer_count  
162 - FROM crm_follow_up_record  
163 - WHERE creator IN  
164 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
165 - #{userId}  
166 - </foreach>  
167 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
168 - #{times[1],javaType=java.time.LocalDateTime}  
169 - AND biz_type = #{bizType}  
170 - GROUP BY creator 147 + SELECT
  148 + creator as owner_user_id,
  149 + COUNT(DISTINCT biz_id) AS followup_customer_count
  150 + FROM crm_follow_up_record
  151 + WHERE creator IN
  152 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  153 + #{userId}
  154 + </foreach>
  155 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  156 + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type}
  157 + GROUP BY creator
171 </select> 158 </select>
172 159
173 - <select id="selectFollowupRecordCountGroupbyType" 160 + <select id="selectFollowupRecordCountGroupByType"
174 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByTypeRespVO"> 161 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByTypeRespVO">
175 SELECT 162 SELECT
176 - type AS followupType,  
177 - count(*) AS followup_record_count  
178 - FROM crm_follow_up_record  
179 - WHERE creator IN  
180 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
181 - #{userId}  
182 - </foreach>  
183 - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
184 - #{times[1],javaType=java.time.LocalDateTime}  
185 - AND biz_type = #{bizType}  
186 - GROUP BY followupType 163 + type AS followupType,
  164 + COUNT(*) AS followup_record_count
  165 + FROM crm_follow_up_record
  166 + WHERE creator IN
  167 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  168 + #{userId}
  169 + </foreach>
  170 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  171 + AND biz_type = ${@cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum@CRM_CUSTOMER.type}
  172 + GROUP BY followupType
187 </select> 173 </select>
188 174
189 <select id="selectContractSummary" 175 <select id="selectContractSummary"
190 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerContractSummaryRespVO"> 176 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerContractSummaryRespVO">
191 SELECT 177 SELECT
192 - a.`name` AS customer_name,  
193 - b.`name` AS contract_name,  
194 - b.total_price,  
195 - IFNULL( c.price, 0 ) AS receivable_price,  
196 - a.industry_id,  
197 - a.source,  
198 - a.owner_user_id,  
199 - a.creator AS creator_user_id,  
200 - a.create_time,  
201 - b.order_date  
202 - FROM  
203 - crm_customer AS a  
204 - INNER JOIN crm_contract AS b ON a.id = b.customer_id  
205 - LEFT JOIN crm_receivable AS c ON b.id = c.contract_id  
206 - WHERE a.deleted = 0 AND b.deleted = 0 AND c.deleted = 0  
207 - AND b.audit_status = 20  
208 - AND a.owner_user_id IN  
209 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
210 - #{userId}  
211 - </foreach>  
212 - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
213 - #{times[1],javaType=java.time.LocalDateTime} 178 + customer.`name` AS customer_name,
  179 + contract.`name` AS contract_name,
  180 + contract.total_price,
  181 + IFNULL( receivable.price, 0 ) AS receivable_price,
  182 + customer.industry_id,
  183 + customer.source,
  184 + customer.owner_user_id,
  185 + customer.creator AS creator_user_id,
  186 + customer.create_time,
  187 + contract.order_date
  188 + FROM crm_customer AS customer
  189 + INNER JOIN crm_contract AS contract ON customer.id = contract.customer_id
  190 + LEFT JOIN crm_receivable AS receivable ON contract.id = receivable.contract_id
  191 + WHERE customer.deleted = 0 AND contract.deleted = 0 AND receivable.deleted = 0
  192 + AND contract.audit_status = 20
  193 + AND customer.owner_user_id IN
  194 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  195 + #{userId}
  196 + </foreach>
  197 + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
214 </select> 198 </select>
215 199
216 - <select id="selectCustomerDealCycleGroupbyDate" 200 + <select id="selectCustomerDealCycleGroupByDate"
217 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByDateRespVO"> 201 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByDateRespVO">
218 SELECT 202 SELECT
219 - DATE_FORMAT( b.order_date, #{sqlDateFormat} ) AS time,  
220 - IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS customer_deal_cycle  
221 - FROM crm_customer AS a  
222 - LEFT JOIN crm_contract AS b ON b.customer_id = a.id  
223 - WHERE a.deleted = 0 AND b.deleted = 0  
224 - AND b.audit_status = 20  
225 - AND a.owner_user_id IN  
226 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
227 - #{userId}  
228 - </foreach>  
229 - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
230 - #{times[1],javaType=java.time.LocalDateTime}  
231 - GROUP BY time 203 + DATE_FORMAT( contract.order_date, #{sqlDateFormat} ) AS time,
  204 + IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, customer.create_time, contract.order_date )), 1 ), 0 ) AS customer_deal_cycle
  205 + FROM crm_customer AS customer
  206 + LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
  207 + WHERE customer.deleted = 0 AND contract.deleted = 0
  208 + AND contract.audit_status = 20
  209 + AND customer.owner_user_id IN
  210 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  211 + #{userId}
  212 + </foreach>
  213 + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  214 + GROUP BY time
232 </select> 215 </select>
233 216
234 - <select id="selectCustomerDealCycleGroupbyUser" 217 + <select id="selectCustomerDealCycleGroupByUser"
235 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByUserRespVO"> 218 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByUserRespVO">
236 SELECT 219 SELECT
237 - a.owner_user_id,  
238 - IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS customer_deal_cycle  
239 - FROM crm_customer AS a  
240 - LEFT JOIN crm_contract AS b ON b.customer_id = a.id  
241 - WHERE a.deleted = 0 AND b.deleted = 0  
242 - AND b.audit_status = 20  
243 - AND a.owner_user_id IN  
244 - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">  
245 - #{userId}  
246 - </foreach>  
247 - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND  
248 - #{times[1],javaType=java.time.LocalDateTime}  
249 - GROUP BY a.owner_user_id 220 + customer.owner_user_id,
  221 + IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, customer.create_time, contract.order_date )), 1 ), 0 ) AS customer_deal_cycle
  222 + FROM crm_customer AS customer
  223 + LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
  224 + WHERE customer.deleted = 0 AND contract.deleted = 0
  225 + AND contract.audit_status = 20
  226 + AND customer.owner_user_id IN
  227 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  228 + #{userId}
  229 + </foreach>
  230 + AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
  231 + GROUP BY customer.owner_user_id
250 </select> 232 </select>
251 233
252 </mapper> 234 </mapper>