Commit cc82e471ea58b7b1da953a023b5afbfc08c15fc3

Authored by 芋道源码
Committed by Gitee
2 parents 1d239c98 bb25f071

!949 CRM: 新增商机赢单转化率分析

Merge pull request !949 from puhui999/develop
Showing 18 changed files with 190 additions and 322 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java
@@ -5,10 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -5,10 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.crm.controller.admin.business.CrmBusinessController; 6 import cn.iocoder.yudao.module.crm.controller.admin.business.CrmBusinessController;
7 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO;
8 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;  
9 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;  
10 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;  
11 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; 8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.*;
12 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 9 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
13 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService; 10 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService;
14 import io.swagger.v3.oas.annotations.Operation; 11 import io.swagger.v3.oas.annotations.Operation;
@@ -31,37 +28,42 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -31,37 +28,42 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
31 @Validated 28 @Validated
32 public class CrmStatisticsFunnelController { 29 public class CrmStatisticsFunnelController {
33 30
34 - // TODO @puhui999:crmStatisticsFunnelService 改成 funnelService 更好点哈  
35 @Resource 31 @Resource
36 - private CrmStatisticsFunnelService crmStatisticsFunnelService; 32 + private CrmStatisticsFunnelService funnelService;
37 33
38 @GetMapping("/get-funnel-summary") 34 @GetMapping("/get-funnel-summary")
39 @Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面的【销售漏斗分析】") 35 @Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面的【销售漏斗分析】")
40 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") 36 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
41 - public CommonResult<CrmStatisticFunnelRespVO> getFunnelSummary(@Valid CrmStatisticsFunnelReqVO reqVO) {  
42 - return success(crmStatisticsFunnelService.getFunnelSummary(reqVO)); 37 + public CommonResult<CrmStatisticFunnelSummaryRespVO> getFunnelSummary(@Valid CrmStatisticsFunnelReqVO reqVO) {
  38 + return success(funnelService.getFunnelSummary(reqVO));
43 } 39 }
44 40
45 - // TODO @puhui:这个接口,应该是 getBusinessSummaryByEndStatus?这样更统一哈;  
46 - @GetMapping("/get-business-end-status-summary") 41 + @GetMapping("/get-business-summary-by-end-status")
47 @Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面的【销售漏斗分析】") 42 @Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面的【销售漏斗分析】")
48 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") 43 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
49 - public CommonResult<List<CrmStatisticBusinessEndStatusRespVO>> getBusinessEndStatusSummary(@Valid CrmStatisticsFunnelReqVO reqVO) {  
50 - return success(crmStatisticsFunnelService.getBusinessEndStatusSummary(reqVO)); 44 + public CommonResult<List<CrmStatisticsBusinessSummaryByEndStatusRespVO>> getBusinessSummaryByEndStatus(@Valid CrmStatisticsFunnelReqVO reqVO) {
  45 + return success(funnelService.getBusinessSummaryByEndStatus(reqVO));
51 } 46 }
52 47
53 @GetMapping("/get-business-summary-by-date") 48 @GetMapping("/get-business-summary-by-date")
54 @Operation(summary = "获取新增商机分析(按日期)", description = "用于【销售漏斗】页面") 49 @Operation(summary = "获取新增商机分析(按日期)", description = "用于【销售漏斗】页面")
55 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") 50 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
56 public CommonResult<List<CrmStatisticsBusinessSummaryByDateRespVO>> getBusinessSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) { 51 public CommonResult<List<CrmStatisticsBusinessSummaryByDateRespVO>> getBusinessSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) {
57 - return success(crmStatisticsFunnelService.getBusinessSummaryByDate(reqVO)); 52 + return success(funnelService.getBusinessSummaryByDate(reqVO));
  53 + }
  54 +
  55 + @GetMapping("/get-business-inversion-rate-summary-by-date")
  56 + @Operation(summary = "获取商机转化率分析(按日期)", description = "用于【销售漏斗】页面")
  57 + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
  58 + public CommonResult<List<CrmStatisticsBusinessInversionRateSummaryByDateRespVO>> getBusinessInversionRateSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) {
  59 + return success(funnelService.getBusinessInversionRateSummaryByDate(reqVO));
58 } 60 }
59 61
60 @GetMapping("/get-business-page-by-date") 62 @GetMapping("/get-business-page-by-date")
61 @Operation(summary = "获得商机分页(按日期)", description = "用于【销售漏斗】页面的【新增商机分析】") 63 @Operation(summary = "获得商机分页(按日期)", description = "用于【销售漏斗】页面的【新增商机分析】")
62 @PreAuthorize("@ss.hasPermission('crm:business:query')") 64 @PreAuthorize("@ss.hasPermission('crm:business:query')")
63 public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByDate(@Valid CrmStatisticsFunnelReqVO pageVO) { 65 public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByDate(@Valid CrmStatisticsFunnelReqVO pageVO) {
64 - PageResult<CrmBusinessDO> pageResult = crmStatisticsFunnelService.getBusinessPageByDate(pageVO); 66 + PageResult<CrmBusinessDO> pageResult = funnelService.getBusinessPageByDate(pageVO);
65 return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); 67 return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal()));
66 } 68 }
67 69
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticFunnelRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticFunnelSummaryRespVO.java
@@ -5,12 +5,11 @@ import lombok.AllArgsConstructor; @@ -5,12 +5,11 @@ import lombok.AllArgsConstructor;
5 import lombok.Data; 5 import lombok.Data;
6 import lombok.NoArgsConstructor; 6 import lombok.NoArgsConstructor;
7 7
8 -// TODO @puhui999:改成 CrmStatisticFunnelSummaryRespVO 更有统计的味道  
9 @Schema(description = "管理后台 - CRM 销售漏斗 Response VO") 8 @Schema(description = "管理后台 - CRM 销售漏斗 Response VO")
10 @NoArgsConstructor 9 @NoArgsConstructor
11 @AllArgsConstructor 10 @AllArgsConstructor
12 @Data 11 @Data
13 -public class CrmStatisticFunnelRespVO { 12 +public class CrmStatisticFunnelSummaryRespVO {
14 13
15 @Schema(description = "客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 14 @Schema(description = "客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 private Long customerCount; 15 private Long customerCount;
@@ -18,8 +17,7 @@ public class CrmStatisticFunnelRespVO { @@ -18,8 +17,7 @@ public class CrmStatisticFunnelRespVO {
18 @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 17 @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
19 private Long businessCount; 18 private Long businessCount;
20 19
21 - // TODO @puhui999:这个改成 businessWinCount 可能会更合适点哈;  
22 @Schema(description = "赢单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 20 @Schema(description = "赢单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
23 - private Long winCount; 21 + private Long businessWinCount;
24 22
25 } 23 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessInversionRateSummaryByDateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +
  8 +@Schema(description = "管理后台 - CRM 商机转化率分析(按日期) VO")
  9 +@Data
  10 +public class CrmStatisticsBusinessInversionRateSummaryByDateRespVO {
  11 +
  12 + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
  13 + private String time;
  14 +
  15 + @Schema(description = "商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Long businessCount;
  17 +
  18 + @Schema(description = "赢单商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Long businessWinCount;
  20 +
  21 +}
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessRespVO.java deleted
1 -package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;  
2 -  
3 -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;  
4 -import com.alibaba.excel.annotation.ExcelProperty;  
5 -import io.swagger.v3.oas.annotations.media.Schema;  
6 -import lombok.Data;  
7 -  
8 -import java.math.BigDecimal;  
9 -import java.time.LocalDateTime;  
10 -  
11 -// TODO @puhui999:是不是可以删除哈?  
12 -@Schema(description = "管理后台 - CRM 商机 Response VO")  
13 -@Data  
14 -@ExcelIgnoreUnannotated  
15 -public class CrmStatisticsBusinessRespVO {  
16 -  
17 - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129")  
18 - @ExcelProperty("编号")  
19 - private Long id;  
20 -  
21 - @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")  
22 - @ExcelProperty("商机名称")  
23 - private String name;  
24 -  
25 - @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299")  
26 - private Long customerId;  
27 - @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")  
28 - @ExcelProperty("客户名称")  
29 - private String customerName;  
30 -  
31 - @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true")  
32 - @ExcelProperty("跟进状态")  
33 - private Boolean followUpStatus;  
34 -  
35 - @Schema(description = "最后跟进时间")  
36 - @ExcelProperty("最后跟进时间")  
37 - private LocalDateTime contactLastTime;  
38 -  
39 - @Schema(description = "下次联系时间")  
40 - @ExcelProperty("下次联系时间")  
41 - private LocalDateTime contactNextTime;  
42 -  
43 - @Schema(description = "负责人的用户编号", example = "25682")  
44 - @ExcelProperty("负责人的用户编号")  
45 - private Long ownerUserId;  
46 - @Schema(description = "负责人名字", example = "25682")  
47 - @ExcelProperty("负责人名字")  
48 - private String ownerUserName;  
49 - @Schema(description = "负责人部门")  
50 - @ExcelProperty("负责人部门")  
51 - private String ownerUserDeptName;  
52 -  
53 - @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714")  
54 - private Long statusTypeId;  
55 - @Schema(description = "商机状组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中")  
56 - @ExcelProperty("商机状态组")  
57 - private String statusTypeName;  
58 -  
59 - @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")  
60 - private Long statusId;  
61 - @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中")  
62 - @ExcelProperty("商机状态")  
63 - private String statusName;  
64 -  
65 - @Schema  
66 - @ExcelProperty("结束状态")  
67 - private Integer endStatus;  
68 -  
69 - @ExcelProperty("结束时的备注")  
70 - private String endRemark;  
71 -  
72 - @Schema(description = "预计成交日期")  
73 - @ExcelProperty("预计成交日期")  
74 - private LocalDateTime dealTime;  
75 -  
76 - @Schema(description = "产品总金额", example = "12025")  
77 - @ExcelProperty("产品总金额")  
78 - private BigDecimal totalProductPrice;  
79 -  
80 - @Schema(description = "整单折扣")  
81 - @ExcelProperty("整单折扣")  
82 - private BigDecimal discountPercent;  
83 -  
84 - @Schema(description = "商机总金额", example = "12371")  
85 - @ExcelProperty("商机总金额")  
86 - private BigDecimal totalPrice;  
87 -  
88 - @Schema(description = "备注", example = "随便")  
89 - @ExcelProperty("备注")  
90 - private String remark;  
91 -  
92 - @Schema(description = "创建人", example = "1024")  
93 - @ExcelProperty("创建人")  
94 - private String creator;  
95 - @Schema(description = "创建人名字", example = "芋道源码")  
96 - @ExcelProperty("创建人名字")  
97 - private String creatorName;  
98 -  
99 - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)  
100 - @ExcelProperty("创建时间")  
101 - private LocalDateTime createTime;  
102 -  
103 - @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)  
104 - @ExcelProperty("更新时间")  
105 - private LocalDateTime updateTime;  
106 -  
107 -}  
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByDateRespVO.java
@@ -13,10 +13,9 @@ public class CrmStatisticsBusinessSummaryByDateRespVO { @@ -13,10 +13,9 @@ public class CrmStatisticsBusinessSummaryByDateRespVO {
13 private String time; 13 private String time;
14 14
15 @Schema(description = "新增商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 15 @Schema(description = "新增商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 - private Integer businessCreateCount; 16 + private Long businessCreateCount;
17 17
18 - // TODO @puhui999:是不是金额哈,不是数量  
19 @Schema(description = "新增商机金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 18 @Schema(description = "新增商机金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 - private BigDecimal businessDealCount; 19 + private BigDecimal totalPrice;
21 20
22 } 21 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticBusinessEndStatusRespVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByEndStatusRespVO.java
@@ -7,12 +7,11 @@ import lombok.NoArgsConstructor; @@ -7,12 +7,11 @@ import lombok.NoArgsConstructor;
7 7
8 import java.math.BigDecimal; 8 import java.math.BigDecimal;
9 9
10 -// TODO @puhui999:改成 CrmStatisticsBusinessSummaryByEndStatusRespVO,按照结束状态  
11 @Schema(description = "管理后台 - CRM 商机结束状态统计 Response VO") 10 @Schema(description = "管理后台 - CRM 商机结束状态统计 Response VO")
12 @NoArgsConstructor 11 @NoArgsConstructor
13 @AllArgsConstructor 12 @AllArgsConstructor
14 @Data 13 @Data
15 -public class CrmStatisticBusinessEndStatusRespVO { 14 +public class CrmStatisticsBusinessSummaryByEndStatusRespVO {
16 15
17 @Schema(description = "结束状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 16 @Schema(description = "结束状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
18 private Integer endStatus; 17 private Integer endStatus;
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java
@@ -5,9 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; @@ -5,9 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 import cn.iocoder.yudao.framework.common.validation.InEnum; 5 import cn.iocoder.yudao.framework.common.validation.InEnum;
6 import io.swagger.v3.oas.annotations.media.Schema; 6 import io.swagger.v3.oas.annotations.media.Schema;
7 import jakarta.validation.constraints.NotNull; 7 import jakarta.validation.constraints.NotNull;
  8 +import jakarta.validation.constraints.Size;
8 import lombok.Data; 9 import lombok.Data;
9 -import lombok.EqualsAndHashCode;  
10 -import lombok.ToString;  
11 import org.springframework.format.annotation.DateTimeFormat; 10 import org.springframework.format.annotation.DateTimeFormat;
12 11
13 import java.time.LocalDateTime; 12 import java.time.LocalDateTime;
@@ -17,9 +16,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @@ -17,9 +16,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
17 16
18 @Schema(description = "管理后台 - CRM 销售漏斗 Request VO") 17 @Schema(description = "管理后台 - CRM 销售漏斗 Request VO")
19 @Data 18 @Data
20 -// TODO @puhui999:不用写 EqualsAndHashCode、ToString,已经全局 lombok 啦  
21 -@EqualsAndHashCode(callSuper = true)  
22 -@ToString(callSuper = true)  
23 public class CrmStatisticsFunnelReqVO extends PageParam { 19 public class CrmStatisticsFunnelReqVO extends PageParam {
24 20
25 @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 21 @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -43,13 +39,9 @@ public class CrmStatisticsFunnelReqVO extends PageParam { @@ -43,13 +39,9 @@ public class CrmStatisticsFunnelReqVO extends PageParam {
43 @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}") 39 @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}")
44 private Integer interval; 40 private Integer interval;
45 41
46 - // TODO @puhui999:这个全部前端传递哈;参考 CrmStatisticsCustomerReqVO  
47 - /**  
48 - * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间  
49 - * 并作为参数传递给Mapper  
50 - */  
51 @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) 42 @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
52 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 43 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  44 + @Size(min = 2, max = 2, message = "请选择时间范围")
53 private LocalDateTime[] times; 45 private LocalDateTime[] times;
54 46
55 } 47 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/portrait/CrmStatisticsPortraitReqVO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotNull; 4 import jakarta.validation.constraints.NotNull;
  5 +import jakarta.validation.constraints.Size;
5 import lombok.Data; 6 import lombok.Data;
6 import org.springframework.format.annotation.DateTimeFormat; 7 import org.springframework.format.annotation.DateTimeFormat;
7 8
@@ -31,12 +32,9 @@ public class CrmStatisticsPortraitReqVO { @@ -31,12 +32,9 @@ public class CrmStatisticsPortraitReqVO {
31 @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") 32 @Schema(description = "负责人用户 id 集合", hidden = true, example = "2")
32 private List<Long> userIds; 33 private List<Long> userIds;
33 34
34 - /**  
35 - * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间  
36 - * 并作为参数传递给Mapper  
37 - */  
38 @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) 35 @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
39 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 36 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  37 + @Size(min = 2, max = 2, message = "请选择时间范围")
40 private LocalDateTime[] times; 38 private LocalDateTime[] times;
41 39
42 } 40 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
1 package cn.iocoder.yudao.module.crm.dal.mysql.business; 1 package cn.iocoder.yudao.module.crm.dal.mysql.business;
2 2
3 -import cn.iocoder.yudao.framework.common.pojo.PageParam;  
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
8 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO;
  8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
9 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 9 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
10 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 10 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
11 import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; 11 import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils;
12 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 12 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
13 import org.apache.ibatis.annotations.Mapper; 13 import org.apache.ibatis.annotations.Mapper;
14 14
15 -import java.time.LocalDateTime;  
16 import java.util.Collection; 15 import java.util.Collection;
17 import java.util.List; 16 import java.util.List;
18 17
@@ -66,32 +65,10 @@ public interface CrmBusinessMapper extends BaseMapperX&lt;CrmBusinessDO&gt; { @@ -66,32 +65,10 @@ public interface CrmBusinessMapper extends BaseMapperX&lt;CrmBusinessDO&gt; {
66 .eq(CrmBusinessDO::getOwnerUserId, ownerUserId)); 65 .eq(CrmBusinessDO::getOwnerUserId, ownerUserId));
67 } 66 }
68 67
69 - default Long selectCountByOwnerUserIdsAndEndStatus(Collection<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus) {  
70 - return selectCount(new LambdaQueryWrapperX<CrmBusinessDO>()  
71 - .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)  
72 - .eqIfPresent(CrmBusinessDO::getEndStatus, endStatus)  
73 - .betweenIfPresent(CrmBusinessDO::getCreateTime, times));  
74 - }  
75 -  
76 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
77 - default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times) {  
78 - return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()  
79 - .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)  
80 - .betweenIfPresent(CrmBusinessDO::getCreateTime, times)  
81 - .isNotNull(CrmBusinessDO::getEndStatus));  
82 - }  
83 -  
84 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
85 - default List<CrmBusinessDO> selectListByOwnerUserIdsAndDate(Collection<Long> ownerUserIds, LocalDateTime[] times) {  
86 - return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()  
87 - .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)  
88 - .betweenIfPresent(CrmBusinessDO::getCreateTime, times));  
89 - }  
90 -  
91 - default PageResult<CrmBusinessDO> selectPage(Collection<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize) {  
92 - return selectPage(new PageParam().setPageNo(pageNo).setPageSize(pageSize), new LambdaQueryWrapperX<CrmBusinessDO>()  
93 - .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)  
94 - .betweenIfPresent(CrmBusinessDO::getCreateTime, times)); 68 + default PageResult<CrmBusinessDO> selectPage(CrmStatisticsFunnelReqVO pageVO) {
  69 + return selectPage(pageVO, new LambdaQueryWrapperX<CrmBusinessDO>()
  70 + .in(CrmBusinessDO::getOwnerUserId, pageVO.getUserIds())
  71 + .betweenIfPresent(CrmBusinessDO::getCreateTime, pageVO.getTimes()));
95 } 72 }
96 73
97 } 74 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java
@@ -186,11 +186,4 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; { @@ -186,11 +186,4 @@ public interface CrmCustomerMapper extends BaseMapperX&lt;CrmCustomerDO&gt; {
186 return selectCount(query); 186 return selectCount(query);
187 } 187 }
188 188
189 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
190 - default Long selectCountByOwnerUserIds(Collection<Long> ownerUserIds, LocalDateTime[] times){  
191 - return selectCount(new LambdaQueryWrapperX<CrmCustomerDO>()  
192 - .in(CrmCustomerDO::getOwnerUserId, ownerUserIds)  
193 - .betweenIfPresent(CrmCustomerDO::getCreateTime, times));  
194 - }  
195 -  
196 } 189 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java
1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics; 1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
2 2
3 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO; 3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessInversionRateSummaryByDateRespVO;
4 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO; 4 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO;
5 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; 6 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
6 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
  8 +import org.apache.ibatis.annotations.Param;
7 9
8 import java.util.List; 10 import java.util.List;
9 11
@@ -15,6 +17,14 @@ import java.util.List; @@ -15,6 +17,14 @@ import java.util.List;
15 @Mapper 17 @Mapper
16 public interface CrmStatisticsFunnelMapper { 18 public interface CrmStatisticsFunnelMapper {
17 19
18 - List<CrmStatisticsBusinessSummaryByDateRespVO> selectBusinessCreateCountGroupByDate(CrmStatisticsFunnelReqVO reqVO); 20 + Long selectCustomerCountByDate(CrmStatisticsFunnelReqVO reqVO);
  21 +
  22 + Long selectBusinessCountByDateAndEndStatus(@Param("reqVO") CrmStatisticsFunnelReqVO reqVO, @Param("status") Integer status);
  23 +
  24 + List<CrmStatisticsBusinessSummaryByEndStatusRespVO> selectBusinessSummaryListGroupByEndStatus(CrmStatisticsFunnelReqVO reqVO);
  25 +
  26 + List<CrmStatisticsBusinessSummaryByDateRespVO> selectBusinessSummaryGroupByDate(CrmStatisticsFunnelReqVO reqVO);
  27 +
  28 + List<CrmStatisticsBusinessInversionRateSummaryByDateRespVO> selectBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO);
19 29
20 } 30 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi
5 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; 5 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO;
6 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; 6 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO;
7 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO;
  8 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
8 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 9 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
9 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; 10 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
10 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; 11 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
@@ -195,44 +196,11 @@ public interface CrmBusinessService { @@ -195,44 +196,11 @@ public interface CrmBusinessService {
195 List<CrmBusinessDO> getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); 196 List<CrmBusinessDO> getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId);
196 197
197 /** 198 /**
198 - * 获得商机数  
199 - *  
200 - * @param ownerUserIds 负责人编号  
201 - * @param times 时间范围  
202 - * @param endStatus 商机结束状态,允许为空  
203 - * @return 商机数  
204 - */  
205 - Long getBusinessCountByOwnerUserIdsAndEndStatus(List<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus);  
206 -  
207 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
208 - /**  
209 - * 获得商机列表【数据统计】  
210 - *  
211 - * @param ownerUserIds 负责人编号  
212 - * @param times 时间范围  
213 - * @return 商机列表  
214 - */  
215 - List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times);  
216 -  
217 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
218 - /**  
219 - * 获得商机列表【数据统计】  
220 - *  
221 - * @param ownerUserIds 负责人编号  
222 - * @param times 时间范围  
223 - * @return 商机列表  
224 - */  
225 - List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times);  
226 -  
227 - /**  
228 * 获得商机分页,目前用于【数据统计】 199 * 获得商机分页,目前用于【数据统计】
229 * 200 *
230 - * @param ownerUserIds 负责人编号  
231 - * @param times 时间范围  
232 - * @param pageNo 页码 TODO @puhui999:直接传递 CrmStatisticsFunnelReqVO 吧,虽然有点耦合,但是更清晰一点;  
233 - * @param pageSize 数量 201 + * @param pageVO 请求
234 * @return 商机分页 202 * @return 商机分页
235 */ 203 */
236 - PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize); 204 + PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO);
237 205
238 } 206 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
@@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi
10 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; 10 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO;
11 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO; 11 import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO;
12 import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; 12 import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO;
  13 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
13 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 14 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
14 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO; 15 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
15 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; 16 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
@@ -376,35 +377,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { @@ -376,35 +377,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
376 } 377 }
377 378
378 @Override 379 @Override
379 - public Long getBusinessCountByOwnerUserIdsAndEndStatus(List<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus) {  
380 - if (CollUtil.isEmpty(ownerUserIds)) {  
381 - return 0L;  
382 - }  
383 - return businessMapper.selectCountByOwnerUserIdsAndEndStatus(convertSet(ownerUserIds), times, endStatus);  
384 - }  
385 -  
386 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
387 - @Override  
388 - public List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times) {  
389 - if (CollUtil.isEmpty(ownerUserIds)) {  
390 - return Collections.emptyList();  
391 - }  
392 - return businessMapper.selectListByOwnerUserIdsAndEndStatusNotNull(convertSet(ownerUserIds), times);  
393 - }  
394 -  
395 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
396 - @Override  
397 - public List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times) {  
398 - if (CollUtil.isEmpty(ownerUserIds)) {  
399 - return Collections.emptyList();  
400 - }  
401 -  
402 - return businessMapper.selectListByOwnerUserIdsAndDate(convertSet(ownerUserIds), times);  
403 - }  
404 -  
405 - @Override  
406 - public PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize) {  
407 - return businessMapper.selectPage(ownerUserIds, times, pageNo, pageSize); 380 + public PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) {
  381 + return businessMapper.selectPage(pageVO);
408 } 382 }
409 383
410 } 384 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java
@@ -195,13 +195,4 @@ public interface CrmCustomerService { @@ -195,13 +195,4 @@ public interface CrmCustomerService {
195 */ 195 */
196 int autoPutCustomerPool(); 196 int autoPutCustomerPool();
197 197
198 - /**  
199 - * 获得客户数  
200 - *  
201 - * @param ownerUserIds 负责人编号  
202 - * @param times 时间范围  
203 - * @return 客户数  
204 - */  
205 - Long getCustomerCountByOwnerUserIds(List<Long> ownerUserIds, LocalDateTime[] times);  
206 -  
207 } 198 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java
@@ -651,14 +651,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @@ -651,14 +651,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
651 } 651 }
652 } 652 }
653 653
654 - @Override  
655 - public Long getCustomerCountByOwnerUserIds(List<Long> ownerUserIds, LocalDateTime[] times) {  
656 - if (CollUtil.isEmpty(ownerUserIds)) {  
657 - return 0L;  
658 - }  
659 - return customerMapper.selectCountByOwnerUserIds(convertSet(ownerUserIds), times);  
660 - }  
661 -  
662 /** 654 /**
663 * 获得自身的代理对象,解决 AOP 生效问题 655 * 获得自身的代理对象,解决 AOP 生效问题
664 * 656 *
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java
1 package cn.iocoder.yudao.module.crm.service.statistics; 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;  
5 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;  
6 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;  
7 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; 4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.*;
8 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 5 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
9 6
10 import java.util.List; 7 import java.util.List;
@@ -22,7 +19,7 @@ public interface CrmStatisticsFunnelService { @@ -22,7 +19,7 @@ public interface CrmStatisticsFunnelService {
22 * @param reqVO 请求 19 * @param reqVO 请求
23 * @return 销售漏斗数据 20 * @return 销售漏斗数据
24 */ 21 */
25 - CrmStatisticFunnelRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO); 22 + CrmStatisticFunnelSummaryRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO);
26 23
27 /** 24 /**
28 * 获得商机结束状态统计 25 * 获得商机结束状态统计
@@ -30,7 +27,7 @@ public interface CrmStatisticsFunnelService { @@ -30,7 +27,7 @@ public interface CrmStatisticsFunnelService {
30 * @param reqVO 请求 27 * @param reqVO 请求
31 * @return 商机结束状态统计 28 * @return 商机结束状态统计
32 */ 29 */
33 - List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO); 30 + List<CrmStatisticsBusinessSummaryByEndStatusRespVO> getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO);
34 31
35 /** 32 /**
36 * 获取新增商机分析(按日期) 33 * 获取新增商机分析(按日期)
@@ -41,6 +38,14 @@ public interface CrmStatisticsFunnelService { @@ -41,6 +38,14 @@ public interface CrmStatisticsFunnelService {
41 List<CrmStatisticsBusinessSummaryByDateRespVO> getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO); 38 List<CrmStatisticsBusinessSummaryByDateRespVO> getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO);
42 39
43 /** 40 /**
  41 + * 获得商机转化率分析(按日期)
  42 + *
  43 + * @param reqVO 请求
  44 + * @return 商机转化率分析
  45 + */
  46 + List<CrmStatisticsBusinessInversionRateSummaryByDateRespVO> getBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO);
  47 +
  48 + /**
44 * 获得商机分页(按日期) 49 * 获得商机分页(按日期)
45 * 50 *
46 * @param pageVO 请求 51 * @param pageVO 请求
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java
@@ -4,15 +4,11 @@ import cn.hutool.core.collection.CollUtil; @@ -4,15 +4,11 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; 6 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
7 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;  
8 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;  
9 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;  
10 -import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; 7 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.*;
11 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; 8 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
12 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper; 9 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper;
13 import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; 10 import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum;
14 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; 11 import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
15 -import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;  
16 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 12 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
17 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 13 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
18 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 14 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -22,14 +18,10 @@ import org.springframework.stereotype.Service; @@ -22,14 +18,10 @@ import org.springframework.stereotype.Service;
22 18
23 import java.math.BigDecimal; 19 import java.math.BigDecimal;
24 import java.time.LocalDateTime; 20 import java.time.LocalDateTime;
25 -import java.time.format.DateTimeFormatter;  
26 import java.util.Collections; 21 import java.util.Collections;
27 import java.util.List; 22 import java.util.List;
28 -import java.util.Map;  
29 -import java.util.stream.Collectors;  
30 23
31 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;  
32 -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; 24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
33 25
34 /** 26 /**
35 * CRM 销售漏斗分析 Service 实现类 27 * CRM 销售漏斗分析 Service 实现类
@@ -45,15 +37,12 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic @@ -45,15 +37,12 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
45 @Resource 37 @Resource
46 private AdminUserApi adminUserApi; 38 private AdminUserApi adminUserApi;
47 @Resource 39 @Resource
48 - private CrmCustomerService customerService;  
49 - @Resource  
50 private CrmBusinessService businessService; 40 private CrmBusinessService businessService;
51 @Resource 41 @Resource
52 private DeptApi deptApi; 42 private DeptApi deptApi;
53 43
54 - // TODO @puhui999:貌似想了下,可能还是得按照;;;  
55 @Override 44 @Override
56 - public CrmStatisticFunnelRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO) { 45 + public CrmStatisticFunnelSummaryRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO) {
57 // 1. 获得用户编号数组 46 // 1. 获得用户编号数组
58 List<Long> userIds = getUserIds(reqVO); 47 List<Long> userIds = getUserIds(reqVO);
59 if (CollUtil.isEmpty(userIds)) { 48 if (CollUtil.isEmpty(userIds)) {
@@ -62,34 +51,22 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic @@ -62,34 +51,22 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
62 reqVO.setUserIds(userIds); 51 reqVO.setUserIds(userIds);
63 52
64 // 2. 获得漏斗数据 53 // 2. 获得漏斗数据
65 - return new CrmStatisticFunnelRespVO(  
66 - customerService.getCustomerCountByOwnerUserIds(userIds, reqVO.getTimes()),  
67 - businessService.getBusinessCountByOwnerUserIdsAndEndStatus(userIds, reqVO.getTimes(), null),  
68 - businessService.getBusinessCountByOwnerUserIdsAndEndStatus(userIds, reqVO.getTimes(), CrmBusinessEndStatusEnum.WIN.getStatus())  
69 - ); 54 + Long customerCount = funnelMapper.selectCustomerCountByDate(reqVO);
  55 + Long businessCount = funnelMapper.selectBusinessCountByDateAndEndStatus(reqVO, null);
  56 + Long businessWinCount = funnelMapper.selectBusinessCountByDateAndEndStatus(reqVO, CrmBusinessEndStatusEnum.WIN.getStatus());
  57 + return new CrmStatisticFunnelSummaryRespVO(customerCount, businessCount, businessWinCount);
70 } 58 }
71 59
72 @Override 60 @Override
73 - public List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO) { 61 + public List<CrmStatisticsBusinessSummaryByEndStatusRespVO> getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO) {
74 // 1. 获得用户编号数组 62 // 1. 获得用户编号数组
75 reqVO.setUserIds(getUserIds(reqVO)); 63 reqVO.setUserIds(getUserIds(reqVO));
76 if (CollUtil.isEmpty(reqVO.getUserIds())) { 64 if (CollUtil.isEmpty(reqVO.getUserIds())) {
77 return Collections.emptyList(); 65 return Collections.emptyList();
78 } 66 }
79 67
80 - // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算;  
81 - // 2.1 获得用户负责的商机  
82 - List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(reqVO.getUserIds(), reqVO.getTimes());  
83 - // 2.2 统计各阶段数据  
84 - Map<Integer, List<CrmBusinessDO>> businessMap = convertMultiMap(businessList, CrmBusinessDO::getEndStatus);  
85 - return convertList(CrmBusinessEndStatusEnum.values(), endStatusEnum -> {  
86 - List<CrmBusinessDO> list = businessMap.get(endStatusEnum.getStatus());  
87 - if (CollUtil.isEmpty(list)) {  
88 - return new CrmStatisticBusinessEndStatusRespVO(endStatusEnum.getStatus(), 0L, BigDecimal.ZERO);  
89 - }  
90 - return new CrmStatisticBusinessEndStatusRespVO(endStatusEnum.getStatus(), (long) list.size(),  
91 - getSumValue(list, CrmBusinessDO::getTotalPrice, BigDecimal::add));  
92 - }); 68 + // 2. 获得统计数据
  69 + return funnelMapper.selectBusinessSummaryListGroupByEndStatus(reqVO);
93 } 70 }
94 71
95 @Override 72 @Override
@@ -101,26 +78,45 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic @@ -101,26 +78,45 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
101 } 78 }
102 79
103 // 2. 按天统计,获取分项统计数据 80 // 2. 按天统计,获取分项统计数据
104 - // TODO @puhui999:可以这个统计,返回的时候,就把数量、金额一起统计好;  
105 - List<CrmStatisticsBusinessSummaryByDateRespVO> businessCreateCountList = funnelMapper.selectBusinessCreateCountGroupByDate(reqVO);  
106 - List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndDate(reqVO.getUserIds(), reqVO.getTimes());  
107 - Map<String, BigDecimal> businessDealCountMap = businessList.stream().collect(Collectors.groupingBy(business ->  
108 - business.getCreateTime().format(DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY)),  
109 - Collectors.reducing(BigDecimal.ZERO, CrmBusinessDO::getTotalPrice, BigDecimal::add)));  
110 - 81 + List<CrmStatisticsBusinessSummaryByDateRespVO> businessSummaryList = funnelMapper.selectBusinessSummaryGroupByDate(reqVO);
111 // 3. 按照日期间隔,合并数据 82 // 3. 按照日期间隔,合并数据
112 List<LocalDateTime[]> timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); 83 List<LocalDateTime[]> timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval());
113 return convertList(timeRanges, times -> { 84 return convertList(timeRanges, times -> {
114 - Integer businessCreateCount = businessCreateCountList.stream() 85 + Long businessCreateCount = businessSummaryList.stream()
115 .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) 86 .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime()))
116 - .mapToInt(CrmStatisticsBusinessSummaryByDateRespVO::getBusinessCreateCount).sum();  
117 - BigDecimal businessDealCount = businessDealCountMap.entrySet().stream()  
118 - .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getKey()))  
119 - .map(Map.Entry::getValue) 87 + .mapToLong(CrmStatisticsBusinessSummaryByDateRespVO::getBusinessCreateCount).sum();
  88 + BigDecimal businessDealCount = businessSummaryList.stream()
  89 + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime()))
  90 + .map(CrmStatisticsBusinessSummaryByDateRespVO::getTotalPrice)
120 .reduce(BigDecimal.ZERO, BigDecimal::add); 91 .reduce(BigDecimal.ZERO, BigDecimal::add);
121 return new CrmStatisticsBusinessSummaryByDateRespVO() 92 return new CrmStatisticsBusinessSummaryByDateRespVO()
122 .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) 93 .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval()))
123 - .setBusinessCreateCount(businessCreateCount).setBusinessDealCount(businessDealCount); 94 + .setBusinessCreateCount(businessCreateCount).setTotalPrice(businessDealCount);
  95 + });
  96 + }
  97 +
  98 + @Override
  99 + public List<CrmStatisticsBusinessInversionRateSummaryByDateRespVO> getBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO) {
  100 + // 1. 获得用户编号数组
  101 + reqVO.setUserIds(getUserIds(reqVO));
  102 + if (CollUtil.isEmpty(reqVO.getUserIds())) {
  103 + return Collections.emptyList();
  104 + }
  105 +
  106 + // 2. 按天统计,获取分项统计数据
  107 + List<CrmStatisticsBusinessInversionRateSummaryByDateRespVO> businessSummaryList = funnelMapper.selectBusinessInversionRateSummaryByDate(reqVO);
  108 + // 3. 按照日期间隔,合并数据
  109 + List<LocalDateTime[]> timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval());
  110 + return convertList(timeRanges, times -> {
  111 + Long businessCount = businessSummaryList.stream()
  112 + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime()))
  113 + .mapToLong(CrmStatisticsBusinessInversionRateSummaryByDateRespVO::getBusinessCount).sum();
  114 + Long businessWinCount = businessSummaryList.stream()
  115 + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime()))
  116 + .mapToLong(CrmStatisticsBusinessInversionRateSummaryByDateRespVO::getBusinessWinCount).sum();
  117 + return new CrmStatisticsBusinessInversionRateSummaryByDateRespVO()
  118 + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval()))
  119 + .setBusinessCount(businessCount).setBusinessWinCount(businessWinCount);
124 }); 120 });
125 } 121 }
126 122
@@ -132,7 +128,7 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic @@ -132,7 +128,7 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
132 return PageResult.empty(); 128 return PageResult.empty();
133 } 129 }
134 // 2. 执行查询 130 // 2. 执行查询
135 - return businessService.getBusinessPageByDate(pageVO.getUserIds(), pageVO.getTimes(), pageVO.getPageNo(), pageVO.getPageSize()); 131 + return businessService.getBusinessPageByDate(pageVO);
136 } 132 }
137 133
138 /** 134 /**
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml
@@ -2,18 +2,78 @@ @@ -2,18 +2,78 @@
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.CrmStatisticsFunnelMapper"> 3 <mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper">
4 4
5 - <select id="selectBusinessCreateCountGroupByDate" 5 + <select id="selectCustomerCountByDate" resultType="java.lang.Long">
  6 + SELECT COUNT(*)
  7 + FROM crm_customer
  8 + WHERE deleted = 0
  9 + AND owner_user_id IN
  10 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  11 + #{userId}
  12 + </foreach>
  13 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  14 + #{times[1],javaType=java.time.LocalDateTime}
  15 + </select>
  16 +
  17 + <select id="selectBusinessCountByDateAndEndStatus" resultType="java.lang.Long">
  18 + SELECT COUNT(*)
  19 + FROM crm_business
  20 + WHERE deleted = 0
  21 + <if test="status != null">
  22 + AND end_status = #{status}
  23 + </if>
  24 + AND owner_user_id IN
  25 + <foreach collection="reqVO.userIds" item="userId" open="(" close=")" separator=",">
  26 + #{userId}
  27 + </foreach>
  28 + AND create_time BETWEEN #{reqVO.times[0],javaType=java.time.LocalDateTime} AND
  29 + #{reqVO.times[1],javaType=java.time.LocalDateTime}
  30 + </select>
  31 +
  32 + <select id="selectBusinessSummaryListGroupByEndStatus"
  33 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO">
  34 + SELECT end_status AS endStatus,COUNT(*) AS businessCount, SUM(total_price) AS totalPrice
  35 + FROM crm_business
  36 + WHERE deleted = 0 AND end_status IS NOT NULL
  37 + AND owner_user_id IN
  38 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  39 + #{userId}
  40 + </foreach>
  41 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  42 + #{times[1],javaType=java.time.LocalDateTime}
  43 + GROUP BY end_status
  44 + </select>
  45 +
  46 + <select id="selectBusinessSummaryGroupByDate"
6 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO"> 47 resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO">
7 SELECT 48 SELECT
8 - DATE_FORMAT(create_time, '%Y-%m-%d') AS time,  
9 - COUNT(*) AS businessCreateCount 49 + DATE_FORMAT(create_time, '%Y-%m-%d') AS time,
  50 + COUNT(*) AS businessCreateCount,
  51 + SUM(total_price) AS totalPrice
  52 + FROM crm_business
  53 + WHERE deleted = 0
  54 + AND owner_user_id IN
  55 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  56 + #{userId}
  57 + </foreach>
  58 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  59 + #{times[1],javaType=java.time.LocalDateTime}
  60 + GROUP BY time
  61 + </select>
  62 +
  63 + <select id="selectBusinessInversionRateSummaryByDate"
  64 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessInversionRateSummaryByDateRespVO">
  65 + SELECT
  66 + DATE_FORMAT(create_time, '%Y-%m-%d') AS time,
  67 + COUNT(*) AS businessCount,
  68 + SUM(IF(end_status = 1, 1, 0)) AS businessWinCount
10 FROM crm_business 69 FROM crm_business
11 WHERE deleted = 0 70 WHERE deleted = 0
12 AND owner_user_id IN 71 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} 72 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  73 + #{userId}
  74 + </foreach>
  75 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  76 + #{times[1],javaType=java.time.LocalDateTime}
17 GROUP BY time 77 GROUP BY time
18 </select> 78 </select>
19 79