Commit 85817a2426de151d1f1c33353533ee963ce53d09

Authored by 芋道源码
Committed by Gitee
2 parents 89fc83c4 0386820a

!902 fix: [CRM-客户统计]根据Code-Review 修改

Merge pull request !902 from dhb52/develop
Showing 16 changed files with 890 additions and 283 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http
1   -### 新建客户总量分析(按日)
2   -GET {{baseUrl}}/crm/statistics-customer/get-total-customer-count?deptId=100&times[0]=2024-12-01 00:00:00&times[1]=2024-12-12 23:59:59
  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 4 Authorization: Bearer {{token}}
4 5 tenant-id: {{adminTenentId}}
5 6  
6   -### 新建客户总量分析(按月)
7   -GET {{baseUrl}}/crm/statistics-customer/get-total-customer-count?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
  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 9 Authorization: Bearer {{token}}
9 10 tenant-id: {{adminTenentId}}
10 11  
11   -### 成交客户总量分析(按日)
12   -GET {{baseUrl}}/crm/statistics-customer/get-deal-total-customer-count?deptId=100&times[0]=2024-12-01 00:00:00&times[1]=2024-12-12 23:59:59
  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 14 Authorization: Bearer {{token}}
14 15 tenant-id: {{adminTenentId}}
15 16  
16   -### 成交客户总量分析(按月)
17   -GET {{baseUrl}}/crm/statistics-customer/get-deal-total-customer-count?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
  17 +
  18 +# == 2. 客户跟进次数分析 ==
  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
  21 +Authorization: Bearer {{token}}
  22 +tenant-id: {{adminTenentId}}
  23 +
  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
  26 +Authorization: Bearer {{token}}
  27 +tenant-id: {{adminTenentId}}
  28 +
  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
  31 +Authorization: Bearer {{token}}
  32 +tenant-id: {{adminTenentId}}
  33 +
  34 +
  35 +# == 3. 客户跟进方式分析 ==
  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
18 38 Authorization: Bearer {{token}}
19 39 tenant-id: {{adminTenentId}}
  40 +tenant-id: {{adminTenentId}}
20 41  
21   -### 获取客户跟进次数(按日)
22   -GET {{baseUrl}}/crm/statistics-customer/get-record-count?deptId=100&times[0]=2024-12-01 00:00:00&times[1]=2024-12-12 23:59:59
  42 +
  43 +# == 4. 客户成交周期 ==
  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
23 46 Authorization: Bearer {{token}}
24 47 tenant-id: {{adminTenentId}}
  48 +tenant-id: {{adminTenentId}}
25 49  
26   -### 获取客户跟进次数(按月)
27   -GET {{baseUrl}}/crm/statistics-customer/get-record-count?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
  50 +
  51 +# == 5. 客户成交周期 ==
  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
28 54 Authorization: Bearer {{token}}
29 55 tenant-id: {{adminTenentId}}
  56 +tenant-id: {{adminTenentId}}
30 57  
31   -### 获取已跟进客户数(按日)
32   -GET {{baseUrl}}/crm/statistics-customer/get-distinct-record-count?deptId=100&times[0]=2024-12-01 00:00:00&times[1]=2024-12-12 23:59:59
  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
33 60 Authorization: Bearer {{token}}
34 61 tenant-id: {{adminTenentId}}
  62 +tenant-id: {{adminTenentId}}
35 63  
36   -### 获取已跟进客户数(按月)
37   -GET {{baseUrl}}/crm/statistics-customer/get-distinct-record-count?deptId=100&times[0]=2023-01-01 00:00:00&times[1]=2024-12-12 23:59:59
  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
38 66 Authorization: Bearer {{token}}
  67 +tenant-id: {{adminTenentId}}
39 68 tenant-id: {{adminTenentId}}
40 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/CrmStatisticsCustomerController.java
1 1 package cn.iocoder.yudao.module.crm.controller.admin.statistics;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO;
5   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
6 5 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService;
7 6 import io.swagger.v3.oas.annotations.Operation;
8 7 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -18,8 +17,7 @@ import java.util.List;
18 17  
19 18 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
20 19  
21   -// TODO @dhb52:数据统计 员工客户分析,改成“客户统计”
22   -@Tag(name = "管理后台 - CRM 数据统计 员工客户分析")
  20 +@Tag(name = "管理后台 - CRM 客户统计")
23 21 @RestController
24 22 @RequestMapping("/crm/statistics-customer")
25 23 @Validated
... ... @@ -28,50 +26,60 @@ public class CrmStatisticsCustomerController {
28 26 @Resource
29 27 private CrmStatisticsCustomerService customerService;
30 28  
31   - // TODO @dhb52:建议 getCustomerCount 和 getDealTotalCustomerCount 搞成一个接口;
32   - // 1. 数量接口:【方法:getCustomerSummaryByDate】,VO:CrmStatisticsCustomerSummaryByDateRespVO,然后里面是 time、customerCreateCount customerDealCount
33   - // 2. 按人统计:【方法:getCustomerSummaryByUser】,VO:CrmStatisticsCustomerSummaryByOwnerRespVO,然后里面是 ownerUserId、ownerUserName、customerCreateCount customerDealCount、contractPrice、receivablePrice;客户成交率、未回款金额、回款完成率,交给前端计算;
  29 + @GetMapping("/get-customer-summary-by-date")
  30 + @Operation(summary = "获取客户总量分析(按日期)")
  31 + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
  32 + public CommonResult<List<CrmStatisticsCustomerSummaryByDateRespVO>> getCustomerSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) {
  33 + return success(customerService.getCustomerSummaryByDate(reqVO));
  34 + }
  35 +
  36 + @GetMapping("/get-customer-summary-by-user")
  37 + @Operation(summary = "获取客户总量分析(按用户)")
  38 + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
  39 + public CommonResult<List<CrmStatisticsCustomerSummaryByUserRespVO>> getCustomerSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) {
  40 + return success(customerService.getCustomerSummaryByUser(reqVO));
  41 + }
34 42  
35   - @GetMapping("/get-total-customer-count")
36   - @Operation(summary = "获得新建客户数量")
  43 + @GetMapping("/get-followup-summary-by-date")
  44 + @Operation(summary = "获取客户跟进次数分析(按日期)")
37 45 @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
38   - public CommonResult<List<CrmStatisticsCustomerCountVO>> getTotalCustomerCount(@Valid CrmStatisticsCustomerReqVO reqVO) {
39   - return success(customerService.getTotalCustomerCount(reqVO));
  46 + public CommonResult<List<CrmStatisticsFollowupSummaryByDateRespVO>> getFollowupSummaryByDate(@Valid CrmStatisticsCustomerReqVO reqVO) {
  47 + return success(customerService.getFollowupSummaryByDate(reqVO));
40 48 }
41 49  
42   - @GetMapping("/get-deal-total-customer-count")
43   - @Operation(summary = "获得成交客户数量")
  50 + @GetMapping("/get-followup-summary-by-user")
  51 + @Operation(summary = "获取客户跟进次数分析(按用户)")
44 52 @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
45   - public CommonResult<List<CrmStatisticsCustomerCountVO>> getDealTotalCustomerCount(@Valid CrmStatisticsCustomerReqVO reqVO) {
46   - return success(customerService.getDealTotalCustomerCount(reqVO));
  53 + public CommonResult<List<CrmStatisticsFollowupSummaryByUserRespVO>> getFollowupSummaryByUser(@Valid CrmStatisticsCustomerReqVO reqVO) {
  54 + return success(customerService.getFollowupSummaryByUser(reqVO));
47 55 }
48 56  
49   - @GetMapping("/get-record-count")
50   - @Operation(summary = "获取客户跟进次数")
  57 + @GetMapping("/get-followup-summary-by-type")
  58 + @Operation(summary = "获取客户跟进次数分析(按类型)")
51 59 @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
52   - public CommonResult<List<CrmStatisticsCustomerCountVO>> getRecordCount(@Valid CrmStatisticsCustomerReqVO reqVO) {
53   - return success(customerService.getRecordCount(reqVO));
  60 + public CommonResult<List<CrmStatisticsFollowupSummaryByTypeRespVO>> getFollowupSummaryByType(@Valid CrmStatisticsCustomerReqVO reqVO) {
  61 + return success(customerService.getFollowupSummaryByType(reqVO));
54 62 }
55 63  
56   - @GetMapping("/get-distinct-record-count")
57   - @Operation(summary = "获取已跟进客户数")
  64 + @GetMapping("/get-contract-summary")
  65 + @Operation(summary = "获取合同摘要信息(客户转化率页面)")
58 66 @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
59   - public CommonResult<List<CrmStatisticsCustomerCountVO>> getDistinctRecordCount(@Valid CrmStatisticsCustomerReqVO reqVO) {
60   - return success(customerService.getDistinctRecordCount(reqVO));
  67 + public CommonResult<List<CrmStatisticsCustomerContractSummaryRespVO>> getContractSummary(@Valid CrmStatisticsCustomerReqVO reqVO) {
  68 + return success(customerService.getContractSummary(reqVO));
61 69 }
62 70  
63   - @GetMapping("/get-record-type-count")
64   - @Operation(summary = "获取客户跟进方式统计数")
  71 + @GetMapping("/get-customer-deal-cycle-by-date")
  72 + @Operation(summary = "获取客户成交周期(按日期)")
65 73 @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
66   - public CommonResult<List<CrmStatisticsCustomerCountVO>> getRecordTypeCount(@Valid CrmStatisticsCustomerReqVO reqVO) {
67   - return success(customerService.getRecordTypeCount(reqVO));
  74 + public CommonResult<List<CrmStatisticsCustomerDealCycleByDateRespVO>> getCustomerDealCycleByDate(@Valid CrmStatisticsCustomerReqVO reqVO) {
  75 + return success(customerService.getCustomerDealCycleByDate(reqVO));
68 76 }
69 77  
70   - @GetMapping("/get-customer-cycle")
71   - @Operation(summary = "获取客户成交周期")
  78 + @GetMapping("/get-customer-deal-cycle-by-user")
  79 + @Operation(summary = "获取客户成交周期(按用户)")
72 80 @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
73   - public CommonResult<List<CrmStatisticsCustomerCountVO>> getCustomerCycle(@Valid CrmStatisticsCustomerReqVO reqVO) {
74   - return success(customerService.getCustomerCycle(reqVO));
  81 + public CommonResult<List<CrmStatisticsCustomerDealCycleByUserRespVO>> getCustomerDealCycleByUser(@Valid CrmStatisticsCustomerReqVO reqVO) {
  82 + return success(customerService.getCustomerDealCycleByUser(reqVO));
75 83 }
76 84  
77 85 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerByUserBaseRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +/**
  8 + * 用户客户统计响应 Base VO
  9 + */
  10 +@Data
  11 +public class CrmStatisticsCustomerByUserBaseRespVO {
  12 +
  13 + @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + @JsonIgnore
  15 + private Long ownerUserId;
  16 +
  17 + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  18 + private String ownerUserName;
  19 +
  20 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerContractSummaryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +
  4 +import com.fasterxml.jackson.annotation.JsonFormat;
  5 +import com.fasterxml.jackson.annotation.JsonIgnore;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import lombok.Data;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.math.BigDecimal;
  11 +import java.time.LocalDate;
  12 +import java.time.LocalDateTime;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  15 +
  16 +@Schema(description = "管理后台 - CRM 客户转化率分析 VO")
  17 +@Data
  18 +public class CrmStatisticsCustomerContractSummaryRespVO {
  19 +
  20 + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  21 + private String customerName;
  22 +
  23 + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示合同")
  24 + private String contractName;
  25 +
  26 + @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00")
  27 + private BigDecimal totalPrice;
  28 +
  29 + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1200.00")
  30 + private BigDecimal receivablePrice;
  31 +
  32 + @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  33 + @JsonIgnore
  34 + private String industryId;
  35 +
  36 + @Schema(description = "客户行业", requiredMode = Schema.RequiredMode.REQUIRED, example = "金融")
  37 + private String industryName;
  38 +
  39 + @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  40 + @JsonIgnore
  41 + private String source;
  42 +
  43 + @Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "外呼")
  44 + private String sourceName;
  45 +
  46 + @Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  47 + @JsonIgnore
  48 + private Long ownerUserId;
  49 +
  50 + @Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  51 + private String ownerUserName;
  52 +
  53 + @Schema(description = "创建人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  54 + @JsonIgnore
  55 + private String creatorUserId;
  56 +
  57 + @Schema(description = "创建人", requiredMode = Schema.RequiredMode.REQUIRED, example = "源码")
  58 + private String creatorUserName;
  59 +
  60 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-01 13:24:26")
  61 + private LocalDateTime createTime;
  62 +
  63 + @Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-02-02 00:00:00")
  64 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY, timezone = TIME_ZONE_DEFAULT)
  65 + private LocalDate orderDate;
  66 +
  67 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerCountVO.java deleted
1   -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -
7   -@Schema(description = "管理后台 - CRM 数据统计 员工客户分析 VO")
8   -@Data
9   -public class CrmStatisticsCustomerCountVO {
10   -
11   - /**
12   - * 时间轴
13   - * <p>
14   - * group by DATE_FORMAT(create_date, '%Y%m')
15   - */
16   - @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
17   - private String category;
18   -
19   - /**
20   - * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义
21   - * <p>
22   - * 1. 金额:合同金额排行、回款金额排行
23   - * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行
24   - */
25   - @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
26   - private Integer count = 0;
27   -
28   - /**
29   - * 成交周期(天)
30   - */
31   - @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0")
32   - private Double cycle = 0.0;
33   -
34   -}
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByDateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - CRM 客户成交周期分析(按日期) VO")
  7 +@Data
  8 +public class CrmStatisticsCustomerDealCycleByDateRespVO {
  9 +
  10 + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
  11 + private String time;
  12 +
  13 + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0")
  14 + private Double customerDealCycle = 0.0;
  15 +
  16 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerDealCycleByUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - CRM 成交周期分析(按用户) VO")
  7 +@Data
  8 +public class CrmStatisticsCustomerDealCycleByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO {
  9 +
  10 + @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0")
  11 + private Double customerDealCycle = 0.0;
  12 +
  13 + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + private Integer customerDealCount = 0;
  15 +
  16 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByDateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - CRM 客户总量分析(按日期) VO")
  7 +@Data
  8 +public class CrmStatisticsCustomerSummaryByDateRespVO {
  9 +
  10 + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
  11 + private String time;
  12 +
  13 + @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + private Integer customerCreateCount = 0;
  15 +
  16 + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + private Integer customerDealCount = 0;
  18 +
  19 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerSummaryByUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +
  8 +@Schema(description = "管理后台 - CRM 客户总量分析(按用户) VO")
  9 +@Data
  10 +public class CrmStatisticsCustomerSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO {
  11 +
  12 + @Schema(description = "新建客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  13 + private Integer customerCreateCount = 0;
  14 +
  15 + @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer customerDealCount = 0;
  17 +
  18 + @Schema(description = "合同总金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  19 + private BigDecimal contractPrice = BigDecimal.ZERO;
  20 +
  21 + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
  22 + private BigDecimal receivablePrice = BigDecimal.ZERO;
  23 +
  24 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByDateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - CRM 跟进次数分析(按日期) VO")
  7 +@Data
  8 +public class CrmStatisticsFollowupSummaryByDateRespVO {
  9 +
  10 + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
  11 + private String time;
  12 +
  13 + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + private Integer followupRecordCount = 0;
  15 +
  16 + @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + private Integer followupCustomerCount = 0;
  18 +
  19 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByTypeRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - CRM 跟进次数分析(按类型) VO")
  8 +@Data
  9 +public class CrmStatisticsFollowupSummaryByTypeRespVO {
  10 +
  11 + @Schema(description = "跟进类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  12 + private String followupType;
  13 +
  14 + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  15 + private Integer followupRecordCount = 0;
  16 +
  17 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsFollowupSummaryByUserRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - CRM 跟进次数分析(按用户) VO")
  7 +@Data
  8 +public class CrmStatisticsFollowupSummaryByUserRespVO extends CrmStatisticsCustomerByUserBaseRespVO {
  9 +
  10 + @Schema(description = "跟进次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  11 + private Integer followupRecordCount = 0;
  12 +
  13 + @Schema(description = "跟进客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + private Integer followupCustomerCount = 0;
  15 +
  16 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
1 1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
2 2  
3   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO;
4   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO;
  3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
5 4 import org.apache.ibatis.annotations.Mapper;
6 5  
7 6 import java.util.List;
... ... @@ -14,16 +13,32 @@ import java.util.List;
14 13 @Mapper
15 14 public interface CrmStatisticsCustomerMapper {
16 15  
17   - List<CrmStatisticsCustomerCountVO> selectCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  16 + List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
18 17  
19   - List<CrmStatisticsCustomerCountVO> selectDealCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  18 + List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
20 19  
21   - List<CrmStatisticsCustomerCountVO> selectRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  20 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
22 21  
23   - List<CrmStatisticsCustomerCountVO> selectDistinctRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  22 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO);
24 23  
25   - List<CrmStatisticsCustomerCountVO> selectRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO);
  24 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO);
26 25  
27   - List<CrmStatisticsCustomerCountVO> selectCustomerCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  26 + List<CrmStatisticsCustomerSummaryByUserRespVO> selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO);
  27 +
  28 + List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  29 +
  30 + List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  31 +
  32 + List<CrmStatisticsFollowupSummaryByUserRespVO> selectFollowupRecordCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
  33 +
  34 + List<CrmStatisticsFollowupSummaryByUserRespVO> selectFollowupCustomerCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
  35 +
  36 + List<CrmStatisticsCustomerContractSummaryRespVO> selectContractSummary(CrmStatisticsCustomerReqVO reqVO);
  37 +
  38 + List<CrmStatisticsFollowupSummaryByTypeRespVO> selectFollowupRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO);
  39 +
  40 + List<CrmStatisticsCustomerDealCycleByDateRespVO> selectCustomerDealCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
  41 +
  42 + List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
28 43  
29 44 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java
1 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 2  
3   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO;
4   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO;
  3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
5 4  
6 5 import java.util.List;
7 6  
8 7 /**
9   - * CRM 数据统计 员工客户分析 Service 接口
  8 + * CRM 客户分析 Service 接口
10 9 *
11 10 * @author dhb52
12 11 */
13 12 public interface CrmStatisticsCustomerService {
14 13  
15 14 /**
16   - * 获取新建客户数量
  15 + * 总量分析(按日期)
17 16 *
18 17 * @param reqVO 请求参数
19   - * @return 新建客户数量统计
  18 + * @return 统计数据
20 19 */
21   - List<CrmStatisticsCustomerCountVO> getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO);
  20 + List<CrmStatisticsCustomerSummaryByDateRespVO> getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO);
22 21  
23 22 /**
24   - * 获取成交客户数量
  23 + * 总量分析(按用户)
25 24 *
26 25 * @param reqVO 请求参数
27   - * @return 成交客户数量统计
  26 + * @return 统计数据
28 27 */
29   - List<CrmStatisticsCustomerCountVO> getDealTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO);
  28 + List<CrmStatisticsCustomerSummaryByUserRespVO> getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO);
30 29  
31 30  
32 31 /**
33   - * 获取客户跟进次数
  32 + * 跟进次数分析(按日期)
34 33 *
35 34 * @param reqVO 请求参数
36   - * @return 客户跟进次数
  35 + * @return 统计数据
37 36 */
38   - List<CrmStatisticsCustomerCountVO> getRecordCount(CrmStatisticsCustomerReqVO reqVO);
  37 + List<CrmStatisticsFollowupSummaryByDateRespVO> getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO);
39 38  
40 39 /**
41   - * 获取已跟进客户数
  40 + * 跟进次数分析(按用户)
42 41 *
43 42 * @param reqVO 请求参数
44   - * @return 已跟进客户数
  43 + * @return 统计数据
45 44 */
46   - List<CrmStatisticsCustomerCountVO> getDistinctRecordCount(CrmStatisticsCustomerReqVO reqVO);
  45 + List<CrmStatisticsFollowupSummaryByUserRespVO> getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO);
47 46  
48 47 /**
49   - * 获取客户跟进方式统计数
  48 + * 客户跟进次数分析(按类型)
50 49 *
51 50 * @param reqVO 请求参数
52   - * @return 客户跟进方式统计数
  51 + * @return 统计数据
53 52 */
54   - List<CrmStatisticsCustomerCountVO> getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO);
  53 + List<CrmStatisticsFollowupSummaryByTypeRespVO> getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO);
  54 +
  55 +
  56 + /**
  57 + * 获取合同摘要信息(客户转化率页面)
  58 + *
  59 + * @param reqVO 请求参数
  60 + * @return 合同摘要列表
  61 + */
  62 + List<CrmStatisticsCustomerContractSummaryRespVO> getContractSummary(CrmStatisticsCustomerReqVO reqVO);
  63 +
  64 + /**
  65 + * 客户成交周期(按日期)
  66 + *
  67 + * @param reqVO 请求参数
  68 + * @return 统计数据
  69 + */
  70 + List<CrmStatisticsCustomerDealCycleByDateRespVO> getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO);
55 71  
56 72 /**
57   - * 获取客户成交周期
  73 + * 客户成交周期(按用户)
58 74 *
59 75 * @param reqVO 请求参数
60   - * @return 客户成交周期
  76 + * @return 统计数据
61 77 */
62   - List<CrmStatisticsCustomerCountVO> getCustomerCycle(CrmStatisticsCustomerReqVO reqVO);
  78 + List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO);
63 79  
64 80 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
... ... @@ -3,8 +3,9 @@ package cn.iocoder.yudao.module.crm.service.statistics;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.date.LocalDateTimeUtil;
5 5 import cn.hutool.core.util.ObjUtil;
6   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO;
7   -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
8 9 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper;
9 10 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
10 11 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
... ... @@ -17,17 +18,19 @@ import jakarta.annotation.Resource;
17 18 import org.springframework.stereotype.Service;
18 19 import org.springframework.validation.annotation.Validated;
19 20  
  21 +import java.math.BigDecimal;
20 22 import java.time.LocalDateTime;
  23 +import java.util.ArrayList;
21 24 import java.util.Collections;
22 25 import java.util.List;
23 26 import java.util.Map;
24   -import java.util.function.Function;
  27 +import java.util.stream.Stream;
25 28  
26   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
27   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  30 +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
28 31  
29 32 /**
30   - * CRM 数据统计 员工客户分析 Service 实现类
  33 + * CRM 客户分析 Service 实现类
31 34 *
32 35 * @author dhb52
33 36 */
... ... @@ -35,6 +38,13 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
35 38 @Validated
36 39 public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerService {
37 40  
  41 + private static final String SQL_DATE_FORMAT_BY_MONTH = "%Y%m";
  42 + private static final String SQL_DATE_FORMAT_BY_DAY = "%Y%m%d";
  43 +
  44 + private static final String TIME_FORMAT_BY_MONTH = "yyyyMM";
  45 + private static final String TIME_FORMAT_BY_DAY = "yyyyMMdd";
  46 +
  47 +
38 48 @Resource
39 49 private CrmStatisticsCustomerMapper customerMapper;
40 50  
... ... @@ -45,130 +55,354 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
45 55 @Resource
46 56 private DictDataApi dictDataApi;
47 57  
  58 +
48 59 @Override
49   - public List<CrmStatisticsCustomerCountVO> getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) {
50   - return getStat(reqVO, customerMapper::selectCustomerCountGroupbyDate);
  60 + public List<CrmStatisticsCustomerSummaryByDateRespVO> getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
  61 + // 1. 获得用户编号数组
  62 + final List<Long> userIds = getUserIds(reqVO);
  63 + if (CollUtil.isEmpty(userIds)) {
  64 + return Collections.emptyList();
  65 + }
  66 + reqVO.setUserIds(userIds);
  67 +
  68 + // 2. 获取分项统计数据
  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 + final List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
  75 +
  76 + // 4. 合并统计数据
  77 + List<CrmStatisticsCustomerSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());
  78 + final Map<String, Integer> customerCreateCountMap = convertMap(customerCreateCount,
  79 + CrmStatisticsCustomerSummaryByDateRespVO::getTime,
  80 + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount);
  81 + final Map<String, Integer> customerDealCountMap = convertMap(customerDealCount,
  82 + CrmStatisticsCustomerSummaryByDateRespVO::getTime,
  83 + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount);
  84 + times.forEach(time -> respVoList.add(
  85 + new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time)
  86 + .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
  87 + .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))
  88 + ));
  89 +
  90 + return respVoList;
51 91 }
52 92  
53 93 @Override
54   - public List<CrmStatisticsCustomerCountVO> getDealTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) {
55   - return getStat(reqVO, customerMapper::selectDealCustomerCountGroupbyDate);
  94 + public List<CrmStatisticsCustomerSummaryByUserRespVO> getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) {
  95 + // 1. 获得用户编号数组
  96 + final List<Long> userIds = getUserIds(reqVO);
  97 + if (CollUtil.isEmpty(userIds)) {
  98 + return Collections.emptyList();
  99 + }
  100 + reqVO.setUserIds(userIds);
  101 +
  102 + // 2. 获取分项统计数据
  103 + final List<CrmStatisticsCustomerSummaryByUserRespVO> customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyUser(reqVO);
  104 + final List<CrmStatisticsCustomerSummaryByUserRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO);
  105 + final List<CrmStatisticsCustomerSummaryByUserRespVO> contractPrice = customerMapper.selectContractPriceGroupbyUser(reqVO);
  106 + final List<CrmStatisticsCustomerSummaryByUserRespVO> receivablePrice = customerMapper.selectReceivablePriceGroupbyUser(reqVO);
  107 +
  108 + // 3. 合并统计数据
  109 + final Map<Long, Integer> customerCreateCountMap = convertMap(customerCreateCount,
  110 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  111 + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount);
  112 + final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
  113 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  114 + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
  115 + final Map<Long, BigDecimal> contractPriceMap = convertMap(contractPrice,
  116 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  117 + CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice);
  118 + final Map<Long, BigDecimal> receivablePriceMap = convertMap(receivablePrice,
  119 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  120 + CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice);
  121 + List<CrmStatisticsCustomerSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());
  122 + userIds.forEach(userId -> {
  123 + final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO();
  124 + vo.setOwnerUserId(userId);
  125 + vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0))
  126 + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))
  127 + .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))
  128 + .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO));
  129 + respVoList.add(vo);
  130 + });
  131 +
  132 + // 4. 拼接用户信息
  133 + appendUserInfo(respVoList);
  134 +
  135 + return respVoList;
56 136 }
57 137  
58 138 @Override
59   - public List<CrmStatisticsCustomerCountVO> getRecordCount(CrmStatisticsCustomerReqVO reqVO) {
  139 + public List<CrmStatisticsFollowupSummaryByDateRespVO> getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
  140 + // 1. 获得用户编号数组
  141 + final List<Long> userIds = getUserIds(reqVO);
  142 + if (CollUtil.isEmpty(userIds)) {
  143 + return Collections.emptyList();
  144 + }
  145 + reqVO.setUserIds(userIds);
  146 +
  147 + // 2. 获取分项统计数据
  148 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
60 149 reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
61   - return getStat(reqVO, customerMapper::selectRecordCountGroupbyDate);
  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]);
  155 +
  156 + // 4. 合并统计数据
  157 + List<CrmStatisticsFollowupSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());
  158 + final Map<String, Integer> followupRecordCountMap = convertMap(followupRecordCount,
  159 + CrmStatisticsFollowupSummaryByDateRespVO::getTime,
  160 + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount);
  161 + final Map<String, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
  162 + CrmStatisticsFollowupSummaryByDateRespVO::getTime,
  163 + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount);
  164 + times.forEach(time -> respVoList.add(
  165 + new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)
  166 + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))
  167 + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0))
  168 + ));
  169 +
  170 + return respVoList;
62 171 }
63 172  
64 173 @Override
65   - public List<CrmStatisticsCustomerCountVO> getDistinctRecordCount(CrmStatisticsCustomerReqVO reqVO) {
  174 + public List<CrmStatisticsFollowupSummaryByUserRespVO> getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO) {
  175 + // 1. 获得用户编号数组
  176 + final List<Long> userIds = getUserIds(reqVO);
  177 + if (CollUtil.isEmpty(userIds)) {
  178 + return Collections.emptyList();
  179 + }
  180 + reqVO.setUserIds(userIds);
  181 +
  182 + // 2. 获取分项统计数据
66 183 reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
67   - return getStat(reqVO, customerMapper::selectDistinctRecordCountGroupbyDate);
  184 + final List<CrmStatisticsFollowupSummaryByUserRespVO> followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyUser(reqVO);
  185 + final List<CrmStatisticsFollowupSummaryByUserRespVO> followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyUser(reqVO);
  186 +
  187 + // 3. 合并统计数据
  188 + final Map<Long, Integer> followupRecordCountMap = convertMap(followupRecordCount,
  189 + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
  190 + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount);
  191 + final Map<Long, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
  192 + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
  193 + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount);
  194 + List<CrmStatisticsFollowupSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());
  195 + userIds.forEach(userId -> {
  196 + final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO()
  197 + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))
  198 + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0));
  199 + vo.setOwnerUserId(userId);
  200 + respVoList.add(vo);
  201 + });
  202 +
  203 + // 4. 拼接用户信息
  204 + appendUserInfo(respVoList);
  205 +
  206 + return respVoList;
68 207 }
69 208  
70 209 @Override
71   - public List<CrmStatisticsCustomerCountVO> getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO) {
72   - // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组
73   - if (ObjUtil.isNotNull(reqVO.getUserId())) {
74   - reqVO.setUserIds(List.of(reqVO.getUserId()));
75   - } else {
76   - reqVO.setUserIds(getUserIds(reqVO.getDeptId()));
77   - }
78   - if (CollUtil.isEmpty(reqVO.getUserIds())) {
  210 + public List<CrmStatisticsFollowupSummaryByTypeRespVO> getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO) {
  211 + // 1. 获得用户编号数组
  212 + final List<Long> userIds = getUserIds(reqVO);
  213 + if (CollUtil.isEmpty(userIds)) {
79 214 return Collections.emptyList();
80 215 }
  216 + reqVO.setUserIds(userIds);
81 217  
82 218 // 2. 获得排行数据
83 219 reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
84   - List<CrmStatisticsCustomerCountVO> stats = customerMapper.selectRecordCountGroupbyType(reqVO);
  220 + List<CrmStatisticsFollowupSummaryByTypeRespVO> respVoList = customerMapper.selectFollowupRecordCountGroupbyType(reqVO);
85 221  
86 222 // 3. 获取字典数据
87   - List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList("crm_follow_up_type");
88   - final Map<String, String> followUpTypeMap = convertMap(followUpTypes, DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
89   - stats.forEach(stat -> {
90   - stat.setCategory(followUpTypeMap.get(stat.getCategory()));
  223 + List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE);
  224 + final Map<String, String> followUpTypeMap = convertMap(followUpTypes,
  225 + DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
  226 + respVoList.forEach(vo -> {
  227 + vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType()));
  228 + });
  229 +
  230 + return respVoList;
  231 + }
  232 +
  233 + @Override
  234 + public List<CrmStatisticsCustomerContractSummaryRespVO> getContractSummary(CrmStatisticsCustomerReqVO reqVO) {
  235 + // 1. 获得用户编号数组
  236 + final List<Long> userIds = getUserIds(reqVO);
  237 + if (CollUtil.isEmpty(userIds)) {
  238 + return Collections.emptyList();
  239 + }
  240 + reqVO.setUserIds(userIds);
  241 +
  242 + // 2. 获取统计数据
  243 + List<CrmStatisticsCustomerContractSummaryRespVO> respVoList = customerMapper.selectContractSummary(reqVO);
  244 +
  245 + // 3. 设置 创建人、负责人、行业、来源
  246 + // 获取客户所属行业
  247 + Map<String, String> industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY),
  248 + DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
  249 + // 获取客户来源
  250 + Map<String, String> sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE),
  251 + DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
  252 + // 获取创建人、负责人列表
  253 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList,
  254 + vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
  255 +
  256 + respVoList.forEach(vo -> {
  257 + MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
  258 + MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
  259 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()),
  260 + user -> vo.setCreatorUserName(user.getNickname()));
  261 + MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
91 262 });
92 263  
93   - return stats;
  264 + return respVoList;
  265 + }
  266 +
  267 + @Override
  268 + public List<CrmStatisticsCustomerDealCycleByDateRespVO> getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) {
  269 + // 1. 获得用户编号数组
  270 + final List<Long> userIds = getUserIds(reqVO);
  271 + if (CollUtil.isEmpty(userIds)) {
  272 + return Collections.emptyList();
  273 + }
  274 + reqVO.setUserIds(userIds);
  275 +
  276 + // 2. 获取分项统计数据
  277 + reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
  278 + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
  279 + final List<CrmStatisticsCustomerDealCycleByDateRespVO> customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyDate(reqVO);
  280 +
  281 + // 3. 获取时间序列
  282 + final List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
  283 +
  284 + // 4. 合并统计数据
  285 + List<CrmStatisticsCustomerDealCycleByDateRespVO> respVoList = new ArrayList<>(times.size());
  286 + final Map<String, Double> customerDealCycleMap = convertMap(customerDealCycle,
  287 + CrmStatisticsCustomerDealCycleByDateRespVO::getTime,
  288 + CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle);
  289 + times.forEach(time -> respVoList.add(
  290 + new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
  291 + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
  292 + ));
  293 +
  294 + return respVoList;
94 295 }
95 296  
96 297 @Override
97   - public List<CrmStatisticsCustomerCountVO> getCustomerCycle(CrmStatisticsCustomerReqVO reqVO) {
98   - return getStat(reqVO, customerMapper::selectCustomerCycleGroupbyDate);
  298 + public List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) {
  299 + // 1. 获得用户编号数组
  300 + final List<Long> userIds = getUserIds(reqVO);
  301 + if (CollUtil.isEmpty(userIds)) {
  302 + return Collections.emptyList();
  303 + }
  304 + reqVO.setUserIds(userIds);
  305 +
  306 + // 2. 获取分项统计数据
  307 + reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
  308 + final List<CrmStatisticsCustomerDealCycleByUserRespVO> customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyUser(reqVO);
  309 + final List<CrmStatisticsCustomerSummaryByUserRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO);
  310 +
  311 + // 3. 合并统计数据
  312 + final Map<Long, Double> customerDealCycleMap = convertMap(customerDealCycle,
  313 + CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,
  314 + CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle);
  315 + final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
  316 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  317 + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
  318 + List<CrmStatisticsCustomerDealCycleByUserRespVO> respVoList = new ArrayList<>(userIds.size());
  319 + userIds.forEach(userId -> {
  320 + final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO()
  321 + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))
  322 + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0));
  323 + vo.setOwnerUserId(userId);
  324 + respVoList.add(vo);
  325 + });
  326 +
  327 + // 4. 拼接用户信息
  328 + appendUserInfo(respVoList);
  329 +
  330 + return respVoList;
  331 + }
  332 +
  333 + /**
  334 + * 拼接用户信息(昵称)
  335 + *
  336 + * @param respVoList 统计数据
  337 + */
  338 + private <T extends CrmStatisticsCustomerByUserBaseRespVO> void appendUserInfo(List<T> respVoList) {
  339 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(respVoList,
  340 + CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
  341 + respVoList.forEach(vo -> MapUtils.findAndThen(userMap,
  342 + vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
99 343 }
100 344  
101 345 /**
102   - * 获得统计数据
  346 + * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号
103 347 *
104   - * @param reqVO 参数
105   - * @param statFunction 统计方法
106   - * @return 统计数据
  348 + * @param reqVO 请求参数
  349 + * @return 用户编号数组
107 350 */
108   - private List<CrmStatisticsCustomerCountVO> getStat(CrmStatisticsCustomerReqVO reqVO, Function<CrmStatisticsCustomerReqVO, List<CrmStatisticsCustomerCountVO>> statFunction) {
109   - // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组
  351 + private List<Long> getUserIds(CrmStatisticsCustomerReqVO reqVO) {
110 352 if (ObjUtil.isNotNull(reqVO.getUserId())) {
111   - reqVO.setUserIds(List.of(reqVO.getUserId()));
  353 + return List.of(reqVO.getUserId());
112 354 } else {
113   - reqVO.setUserIds(getUserIds(reqVO.getDeptId()));
114   - }
115   - if (CollUtil.isEmpty(reqVO.getUserIds())) {
116   - return Collections.emptyList();
  355 + // 1. 获得部门列表
  356 + final Long deptId = reqVO.getDeptId();
  357 + List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
  358 + deptIds.add(deptId);
  359 + // 2. 获得用户编号
  360 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
117 361 }
  362 + }
118 363  
119   - // 2. 生成日期格式
120   - LocalDateTime startTime = reqVO.getTimes()[0];
121   - final LocalDateTime endTime = reqVO.getTimes()[1];
122   - final long days = LocalDateTimeUtil.between(startTime, endTime).toDays();
123   - boolean byMonth = days > 31;
124   - if (byMonth) {
125   - // 按月
126   - reqVO.setSqlDateFormat("%Y%m");
127   - } else {
128   - // 按日
129   - reqVO.setSqlDateFormat("%Y%m%d");
130   - }
131 364  
132   - // 3. 获得排行数据
133   - List<CrmStatisticsCustomerCountVO> stats = statFunction.apply(reqVO);
  365 + /**
  366 + * 判断是否按照 月粒度 统计
  367 + *
  368 + * @param startTime 开始时间
  369 + * @param endTime 结束时间
  370 + * @return 是, 按月粒度, 否则按天粒度统计。
  371 + */
  372 + private boolean queryByMonth(LocalDateTime startTime, LocalDateTime endTime) {
  373 + return LocalDateTimeUtil.between(startTime, endTime).toDays() > 31;
  374 + }
134 375  
135   - // 4. 生成时间序列
136   - List<CrmStatisticsCustomerCountVO> result = CollUtil.newArrayList();
  376 + /**
  377 + * 生成时间序列
  378 + *
  379 + * @param startTime 开始时间
  380 + * @param endTime 结束时间
  381 + * @return 时间序列
  382 + */
  383 + private List<String> generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) {
  384 + boolean byMonth = queryByMonth(startTime, endTime);
  385 + List<String> times = CollUtil.newArrayList();
137 386 while (!startTime.isAfter(endTime)) {
138   - final String category = LocalDateTimeUtil.format(startTime, byMonth ? "yyyyMM" : "yyyyMMdd");
139   - result.add(new CrmStatisticsCustomerCountVO().setCategory(category));
  387 + times.add(LocalDateTimeUtil.format(startTime, byMonth ? TIME_FORMAT_BY_MONTH : TIME_FORMAT_BY_DAY));
140 388 if (byMonth)
141 389 startTime = startTime.plusMonths(1);
142 390 else
143 391 startTime = startTime.plusDays(1);
144 392 }
145 393  
146   - // 5. 使用时间序列填充结果
147   - final Map<String, CrmStatisticsCustomerCountVO> statMap = convertMap(stats,
148   - CrmStatisticsCustomerCountVO::getCategory,
149   - Function.identity());
150   - result.forEach(r -> {
151   - if (statMap.containsKey(r.getCategory())) {
152   - r.setCount(statMap.get(r.getCategory()).getCount())
153   - .setCycle(statMap.get(r.getCategory()).getCycle());
154   - }
155   - });
156   -
157   - return result;
  394 + return times;
158 395 }
159 396  
160   -
161 397 /**
162   - * 获得部门下的用户编号数组,包括子部门的
  398 + * 获取 SQL 查询 GROUP BY 的时间格式
163 399 *
164   - * @param deptId 部门编号
165   - * @return 用户编号数组
  400 + * @param startTime 开始时间
  401 + * @param endTime 结束时间
  402 + * @return SQL 查询 GROUP BY 的时间格式
166 403 */
167   - public List<Long> getUserIds(Long deptId) {
168   - // 1. 获得部门列表
169   - List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
170   - deptIds.add(deptId);
171   - // 2. 获得用户编号
172   - return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
  404 + private String getSqlDateFormat(LocalDateTime startTime, LocalDateTime endTime) {
  405 + return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY;
173 406 }
  407 +
174 408 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
... ... @@ -2,115 +2,240 @@
2 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 3 <mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper">
4 4  
  5 + <select id="selectCustomerCreateCountGroupbyDate"
  6 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
  7 + SELECT
  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
  17 + #{times[1],javaType=java.time.LocalDateTime}
  18 + GROUP BY time
  19 + </select>
5 20  
6   - <select id="selectCustomerCountGroupbyDate"
7   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO">
  21 + <select id="selectCustomerDealCountGroupbyDate"
  22 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
8 23 SELECT
9   - DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category,
10   - count(*) AS count
11   - FROM
12   - crm_customer
13   - WHERE
14   - 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   - #{times[1],javaType=java.time.LocalDateTime}
21   - GROUP BY category
  24 + DATE_FORMAT( b.order_date, #{sqlDateFormat} ) AS time,
  25 + count( DISTINCT a.id ) AS customerDealCount
  26 + FROM crm_customer AS a
  27 + LEFT JOIN crm_contract AS b ON b.customer_id = a.id
  28 + WHERE a.deleted = 0 AND b.deleted = 0
  29 + AND b.audit_status = 20
  30 + AND a.owner_user_id IN
  31 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  32 + #{userId}
  33 + </foreach>
  34 + AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  35 + #{times[1],javaType=java.time.LocalDateTime}
  36 + GROUP BY time
  37 + </select>
  38 +
  39 + <select id="selectCustomerCreateCountGroupbyUser"
  40 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
  41 + SELECT owner_user_id, COUNT(1) AS customer_create_count
  42 + FROM crm_customer
  43 + WHERE deleted = 0
  44 + AND owner_user_id in
  45 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  46 + #{userId}
  47 + </foreach>
  48 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  49 + #{times[1],javaType=java.time.LocalDateTime}
  50 + GROUP BY owner_user_id
  51 + </select>
  52 +
  53 + <select id="selectCustomerDealCountGroupbyUser"
  54 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
  55 + SELECT a.owner_user_id, count( DISTINCT a.id ) AS customer_deal_count
  56 + FROM crm_customer AS a
  57 + LEFT JOIN crm_contract AS b ON b.customer_id = a.id
  58 + WHERE a.deleted = 0 AND b.deleted = 0
  59 + AND b.audit_status = 20
  60 + AND a.owner_user_id IN
  61 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  62 + #{userId}
  63 + </foreach>
  64 + AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  65 + #{times[1],javaType=java.time.LocalDateTime}
  66 + GROUP BY a.owner_user_id
  67 + </select>
  68 +
  69 + <select id="selectContractPriceGroupbyUser"
  70 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
  71 + SELECT owner_user_id, IFNULL(SUM(total_price), 0) AS contract_price
  72 + FROM crm_contract
  73 + WHERE deleted = 0
  74 + AND audit_status = 20
  75 + AND owner_user_id in
  76 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  77 + #{userId}
  78 + </foreach>
  79 + AND order_date BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  80 + #{times[1],javaType=java.time.LocalDateTime}
  81 + GROUP BY owner_user_id
  82 + </select>
  83 +
  84 +
  85 + <select id="selectReceivablePriceGroupbyUser"
  86 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
  87 + SELECT 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
  97 + #{times[1],javaType=java.time.LocalDateTime}
  98 + GROUP BY owner_user_id
22 99 </select>
23 100  
24   - <select id="selectDealCustomerCountGroupbyDate"
25   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO">
  101 + <select id="selectFollowupRecordCountGroupbyDate"
  102 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByDateRespVO">
  103 + SELECT 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
  111 + #{times[1],javaType=java.time.LocalDateTime}
  112 + AND biz_type = #{bizType}
  113 + GROUP BY time
  114 + </select>
  115 +
  116 + <select id="selectFollowupCustomerCountGroupbyDate"
  117 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByDateRespVO">
26 118 SELECT
27   - DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) AS category,
28   - count( DISTINCT a.id ) AS count
29   - FROM
30   - crm_customer AS a
31   - LEFT JOIN crm_contract AS b ON b.customer_id = a.id
32   - WHERE
33   - a.deleted = 0 AND b.deleted = 0
34   - AND b.audit_status = 20
35   - AND a.owner_user_id IN
36   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
37   - #{userId}
38   - </foreach>
39   - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
40   - #{times[1],javaType=java.time.LocalDateTime}
41   - GROUP BY category
  119 + DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,
  120 + count(DISTINCT biz_id) AS followup_customer_count
  121 + FROM crm_follow_up_record
  122 + WHERE creator IN
  123 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  124 + #{userId}
  125 + </foreach>
  126 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  127 + #{times[1],javaType=java.time.LocalDateTime}
  128 + AND biz_type = #{bizType}
  129 + GROUP BY time
42 130 </select>
43 131  
44   - <select id="selectRecordCountGroupbyDate"
45   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO">
  132 + <select id="selectFollowupRecordCountGroupbyUser"
  133 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByUserRespVO">
  134 + SELECT creator as owner_user_id,
  135 + count(*) AS followup_record_count
  136 + FROM crm_follow_up_record
  137 + WHERE creator IN
  138 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  139 + #{userId}
  140 + </foreach>
  141 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  142 + #{times[1],javaType=java.time.LocalDateTime}
  143 + AND biz_type = #{bizType}
  144 + GROUP BY creator
  145 + </select>
  146 +
  147 + <select id="selectFollowupCustomerCountGroupbyUser"
  148 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByUserRespVO">
  149 + SELECT creator as owner_user_id,
  150 + count(DISTINCT biz_id) AS followup_customer_count
  151 + FROM crm_follow_up_record
  152 + WHERE creator IN
  153 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  154 + #{userId}
  155 + </foreach>
  156 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  157 + #{times[1],javaType=java.time.LocalDateTime}
  158 + AND biz_type = #{bizType}
  159 + GROUP BY creator
  160 + </select>
  161 +
  162 + <select id="selectFollowupRecordCountGroupbyType"
  163 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsFollowupSummaryByTypeRespVO">
46 164 SELECT
47   - DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category,
48   - count(*) AS count
49   - FROM
50   - crm_follow_up_record
51   - WHERE
52   - creator 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}
58   - AND biz_type = #{bizType,javaType=java.lang.Integer}
59   - GROUP BY category
  165 + type AS followupType,
  166 + count(*) AS followup_record_count
  167 + FROM crm_follow_up_record
  168 + WHERE creator IN
  169 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  170 + #{userId}
  171 + </foreach>
  172 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  173 + #{times[1],javaType=java.time.LocalDateTime}
  174 + AND biz_type = #{bizType}
  175 + GROUP BY followupType
60 176 </select>
61 177  
62   - <select id="selectDistinctRecordCountGroupbyDate"
63   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO">
  178 + <select id="selectContractSummary"
  179 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerContractSummaryRespVO">
64 180 SELECT
65   - DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category,
66   - count(DISTINCT biz_id) AS count
67   - FROM
68   - crm_follow_up_record
69   - WHERE
70   - creator IN
71   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
72   - #{userId}
73   - </foreach>
74   - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
75   - #{times[1],javaType=java.time.LocalDateTime}
76   - AND biz_type = #{bizType,javaType=java.lang.Integer}
77   - GROUP BY category
  181 + a.`name` AS customer_name,
  182 + b.`name` AS contract_name,
  183 + b.total_price,
  184 + IFNULL( c.price, 0 ) AS receivable_price,
  185 + a.industry_id,
  186 + a.source,
  187 + a.owner_user_id,
  188 + a.creator AS creator_user_id,
  189 + a.create_time,
  190 + b.order_date
  191 + FROM
  192 + crm_customer AS a
  193 + INNER JOIN crm_contract AS b ON a.id = b.customer_id
  194 + LEFT JOIN crm_receivable AS c ON b.id = c.contract_id
  195 + WHERE a.deleted = 0 AND b.deleted = 0 AND c.deleted = 0
  196 + AND b.audit_status = 20
  197 + AND a.owner_user_id IN
  198 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  199 + #{userId}
  200 + </foreach>
  201 + AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  202 + #{times[1],javaType=java.time.LocalDateTime}
78 203 </select>
79 204  
80   - <select id="selectRecordCountGroupbyType"
81   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO">
  205 + <select id="selectCustomerDealCycleGroupbyDate"
  206 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByDateRespVO">
82 207 SELECT
83   - type AS category,
84   - count(*) AS count
85   - FROM crm_follow_up_record
86   - WHERE
87   - creator IN
88   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
89   - #{userId}
90   - </foreach>
91   - AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
92   - #{times[1],javaType=java.time.LocalDateTime}
93   - AND biz_type = #{bizType,javaType=java.lang.Integer}
94   - GROUP BY category
  208 + DATE_FORMAT( b.order_date, #{sqlDateFormat} ) AS time,
  209 + IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS customer_deal_cycle
  210 + FROM crm_customer AS a
  211 + LEFT JOIN crm_contract AS b ON b.customer_id = a.id
  212 + WHERE a.deleted = 0 AND b.deleted = 0
  213 + AND b.audit_status = 20
  214 + AND a.owner_user_id IN
  215 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  216 + #{userId}
  217 + </foreach>
  218 + AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  219 + #{times[1],javaType=java.time.LocalDateTime}
  220 + GROUP BY time
95 221 </select>
96 222  
97   - <select id="selectCustomerCycleGroupbyDate"
98   - resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO">
  223 + <select id="selectCustomerDealCycleGroupbyUser"
  224 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByUserRespVO">
99 225 SELECT
100   - DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) AS category,
101   - IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS cycle
102   - FROM crm_customer AS a
103   - LEFT JOIN crm_contract AS b ON b.customer_id = a.id
104   - WHERE
105   - a.deleted = 0 AND b.deleted = 0
106   - AND b.audit_status = 20
107   - AND a.owner_user_id IN
108   - <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
109   - #{userId}
110   - </foreach>
111   - AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
112   - #{times[1],javaType=java.time.LocalDateTime}
113   - GROUP BY category
  226 + a.owner_user_id,
  227 + IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS customer_deal_cycle
  228 + FROM crm_customer AS a
  229 + LEFT JOIN crm_contract AS b ON b.customer_id = a.id
  230 + WHERE a.deleted = 0 AND b.deleted = 0
  231 + AND b.audit_status = 20
  232 + AND a.owner_user_id IN
  233 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  234 + #{userId}
  235 + </foreach>
  236 + AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  237 + #{times[1],javaType=java.time.LocalDateTime}
  238 + GROUP BY a.owner_user_id
114 239 </select>
115 240  
116 241 </mapper>
... ...