diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java
new file mode 100644
index 000000000..9a614ddc9
--- /dev/null
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DateIntervalEnum.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.framework.common.enums;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 时间间隔类型枚举
+ *
+ * @author dhb52
+ */
+@Getter
+@AllArgsConstructor
+public enum DateIntervalEnum implements IntArrayValuable {
+
+ TODAY(1, "今天"),
+ YESTERDAY(2, "昨天"),
+ THIS_WEEK(3, "本周"),
+ LAST_WEEK(4, "上周"),
+ THIS_MONTH(5, "本月"),
+ LAST_MONTH(6, "上月"),
+ THIS_QUARTER(7, "本季度"),
+ LAST_QUARTER(8, "上季度"),
+ THIS_YEAR(9, "本年"),
+ LAST_YEAR(10, "去年"),
+ CUSTOMER(11, "自定义"),
+ ;
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DateIntervalEnum::getType).toArray();
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+
+ /**
+ * 名称
+ */
+ private final String name;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
index 4a0976bb1..d49f6068c 100644
--- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
+++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -103,4 +103,7 @@ public interface ErrorCodeConstants {
ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在");
ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限");
+ // ========== 数据统计 1_020_014_000 ==========
+ ErrorCode STATISTICS_CUSTOMER_TIMES_NOT_SET = new ErrorCode(1_020_014_000, "自定义时间间隔,必须输入时间区间");
+
}
diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http
index 0c422f986..9d96e159a 100644
--- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http
+++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.http
@@ -1,40 +1,40 @@
# == 1. 客户总量分析 ==
### 1.1 客户总量分析(按日)
-GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 1.2 客户总量分析(按月)
-GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-date?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 1.3 客户总量统计(按用户)
-GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-customer-summary-by-user?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
# == 2. 客户跟进次数分析 ==
### 2.1 客户跟进次数分析(按日)
-GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 2.2 客户跟进次数分析(按月)
-GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-date?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 2.3 客户总量统计(按用户)
-GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-user?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
# == 3. 客户跟进方式分析 ==
### 3.1 客户跟进方式分析
-GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-followup-summary-by-type?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
tenant-id: {{adminTenentId}}
@@ -42,7 +42,7 @@ tenant-id: {{adminTenentId}}
# == 4. 客户成交周期 ==
### 4.1 合同摘要信息(客户转化率页面)
-GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-contract-summary?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
tenant-id: {{adminTenentId}}
@@ -50,19 +50,19 @@ tenant-id: {{adminTenentId}}
# == 5. 客户成交周期 ==
### 5.1 客户成交周期(按日)
-GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&intervalType=11×[0]=2024-01-01 00:00:00×[1]=2024-01-29 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
tenant-id: {{adminTenentId}}
### 5.2 客户成交周期(按月)
-GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-date?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
tenant-id: {{adminTenentId}}
### 5.3 获取客户成交周期(按用户)
-GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
+GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100&intervalType=11×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
tenant-id: {{adminTenentId}}
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java
index c5d5acbc3..38f15cf03 100644
--- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java
+++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/CrmStatisticsCustomerReqVO.java
@@ -1,8 +1,8 @@
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
-import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
+import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@@ -28,31 +28,28 @@ public class CrmStatisticsCustomerReqVO {
/**
* userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来
- *
* 后续,可能会支持选择部分用户进行查询
*/
@Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2")
private List userIds;
- @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED)
+ @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}")
+ private Integer intervalType;
+
+ /**
+ * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间
+ * 并作为参数传递给Mapper
+ */
+ @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
- @NotEmpty(message = "时间范围不能为空")
private LocalDateTime[] times;
- // TODO @dhb52:这个时间间隔,建议前端传递;例如说:字段叫 interval,枚举有天、周、月、季度、年。因为一般分析类的系统,都是交给用户选择筛选时间间隔,而我们这里是默认根据日期选项,默认对应的 interval 而已
- // 然后实现上,可以在 common 包的 enums 加个 DateIntervalEnum,里面一个是 interval 字段,枚举过去,然后有个 pattern 字段,用于格式化时间格式;
- // 这样的话,可以通过 interval 获取到 pattern,然后前端就可以根据 pattern 格式化时间,计算还是交给数据库
/**
* group by DATE_FORMAT(field, #{dateFormat})
+ * 非前端传递, 由Service计算后传递给Mapper的参数
*/
@Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m")
private String sqlDateFormat;
- // TODO @dhb52:这个字段,目前是不是没啥用呀?
- /**
- * 数据类型 {@link CrmBizTypeEnum}
- */
- @Schema(description = "数据类型", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2")
- private Integer bizType;
-
}
diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
index 19bd76fc3..7c8ed7e93 100644
--- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
+++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
@@ -13,33 +13,32 @@ import java.util.List;
@Mapper
public interface CrmStatisticsCustomerMapper {
- // TODO @dhb52:拼写,GroupBy。一般 idea 如果出现绿色的警告,可能是单词拼写错误,建议是要修改的哈;
- List selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
+ List selectCustomerCreateCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
- List selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
+ List selectCustomerDealCountGroupByDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
- List selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review
+ List selectCustomerCreateCountGroupByUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review
- List selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
+ List selectCustomerDealCountGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
- List selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
+ List selectContractPriceGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
- List selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
+ List selectReceivablePriceGroupByUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
- List selectFollowupRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
+ List selectFollowupRecordCountGroupByDate(CrmStatisticsCustomerReqVO reqVO);
- List selectFollowupCustomerCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
+ List selectFollowupCustomerCountGroupByDate(CrmStatisticsCustomerReqVO reqVO);
- List selectFollowupRecordCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
+ List selectFollowupRecordCountGroupByUser(CrmStatisticsCustomerReqVO reqVO);
- List selectFollowupCustomerCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
+ List selectFollowupCustomerCountGroupByUser(CrmStatisticsCustomerReqVO reqVO);
List selectContractSummary(CrmStatisticsCustomerReqVO reqVO);
- List selectFollowupRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO);
+ List selectFollowupRecordCountGroupByType(CrmStatisticsCustomerReqVO reqVO);
- List selectCustomerDealCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
+ List selectCustomerDealCycleGroupByDate(CrmStatisticsCustomerReqVO reqVO);
- List selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
+ List selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO);
}
diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
index c9654a68e..f951e25f5 100644
--- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
+++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
@@ -1,13 +1,15 @@
package cn.iocoder.yudao.module.crm.service.statistics;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper;
-import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
@@ -20,14 +22,15 @@ import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.time.LocalDateTime;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
+import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.STATISTICS_CUSTOMER_TIMES_NOT_SET;
/**
* CRM 客户分析 Service 实现类
@@ -58,114 +61,107 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
@Override
public List getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取分项统计数据
- // TODO @dhb52:如果是 list 变量,要么 List 要么 s 后缀
- reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
- final List customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyDate(reqVO);
- final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyDate(reqVO);
+ initParams(reqVO);
+ List customerCreateCountVoList = customerMapper.selectCustomerCreateCountGroupByDate(reqVO);
+ List customerDealCountVoList = customerMapper.selectCustomerDealCountGroupByDate(reqVO);
- // 3. 获取时间序列
- // TODO @dhb52:3 和 4 其实做的是一类事情,所以可以考虑 3.1 获取时间序列、3.2 合并统计数据 这样注释;然后中间就不空行了;就是说,一般空行的目的,是让逻辑分片,看着整体性更好,但是不能让逻辑感觉碎碎的;
- final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
-
- // 4. 合并统计数据
- // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...)
- List respVoList = new ArrayList<>(times.size());
- final Map customerCreateCountMap = convertMap(customerCreateCount,
+ // 3. 合并数据
+ List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
+ Map customerCreateCountMap = convertMap(customerCreateCountVoList,
CrmStatisticsCustomerSummaryByDateRespVO::getTime,
CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount);
- final Map customerDealCountMap = convertMap(customerDealCount,
+ Map customerDealCountMap = convertMap(customerDealCountVoList,
CrmStatisticsCustomerSummaryByDateRespVO::getTime,
CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount);
- times.forEach(time -> respVoList.add(
- new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time)
+ List respVoList = convertList(times,
+ time -> new CrmStatisticsCustomerSummaryByDateRespVO()
+ .setTime(time)
.setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
- .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))
- ));
+ .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)));
+
return respVoList;
}
@Override
public List getCustomerSummaryByUser(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取分项统计数据
- final List customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyUser(reqVO);
- final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO);
- final List contractPrice = customerMapper.selectContractPriceGroupbyUser(reqVO);
- final List receivablePrice = customerMapper.selectReceivablePriceGroupbyUser(reqVO);
+ initParams(reqVO);
+ List customerCreateCount = customerMapper.selectCustomerCreateCountGroupByUser(reqVO);
+ List customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO);
+ List contractPrice = customerMapper.selectContractPriceGroupByUser(reqVO);
+ List receivablePrice = customerMapper.selectReceivablePriceGroupByUser(reqVO);
// 3. 合并统计数据
- final Map customerCreateCountMap = convertMap(customerCreateCount,
+ Map customerCreateCountMap = convertMap(customerCreateCount,
CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount);
- final Map customerDealCountMap = convertMap(customerDealCount,
+ Map customerDealCountMap = convertMap(customerDealCount,
CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
- final Map contractPriceMap = convertMap(contractPrice,
+ Map contractPriceMap = convertMap(contractPrice,
CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice);
- final Map receivablePriceMap = convertMap(receivablePrice,
+ Map receivablePriceMap = convertMap(receivablePrice,
CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice);
- List respVoList = new ArrayList<>(userIds.size());
- userIds.forEach(userId -> {
- final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO();
+ List respVoList = convertList(userIds, userId -> {
+ CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO();
+ // ownerUserId 为基类属性
vo.setOwnerUserId(userId);
vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0))
.setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))
.setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))
.setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO));
- respVoList.add(vo);
+ return vo;
});
// 4. 拼接用户信息
appendUserInfo(respVoList);
+
return respVoList;
}
@Override
public List getFollowupSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取分项统计数据
- reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
- reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
- final List followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyDate(reqVO);
- final List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyDate(reqVO);
+ initParams(reqVO);
+ List followupRecordCount = customerMapper.selectFollowupRecordCountGroupByDate(reqVO);
+ List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByDate(reqVO);
- // 3. 获取时间序列
- final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
-
- // 4. 合并统计数据
- List respVoList = new ArrayList<>(times.size());
- final Map followupRecordCountMap = convertMap(followupRecordCount,
+ // 3. 合并统计数据
+ List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
+ Map followupRecordCountMap = convertMap(followupRecordCount,
CrmStatisticsFollowupSummaryByDateRespVO::getTime,
CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount);
- final Map followupCustomerCountMap = convertMap(followupCustomerCount,
+ Map followupCustomerCountMap = convertMap(followupCustomerCount,
CrmStatisticsFollowupSummaryByDateRespVO::getTime,
CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount);
- times.forEach(time -> respVoList.add(
+ List respVoList = convertList(times, time ->
new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)
.setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))
.setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0))
- ));
+ );
return respVoList;
}
@@ -173,31 +169,31 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
@Override
public List getFollowupSummaryByUser(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取分项统计数据
- reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
- final List followupRecordCount = customerMapper.selectFollowupRecordCountGroupbyUser(reqVO);
- final List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupbyUser(reqVO);
+ initParams(reqVO);
+ List followupRecordCount = customerMapper.selectFollowupRecordCountGroupByUser(reqVO);
+ List followupCustomerCount = customerMapper.selectFollowupCustomerCountGroupByUser(reqVO);
// 3. 合并统计数据
- final Map followupRecordCountMap = convertMap(followupRecordCount,
+ Map followupRecordCountMap = convertMap(followupRecordCount,
CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount);
- final Map followupCustomerCountMap = convertMap(followupCustomerCount,
+ Map followupCustomerCountMap = convertMap(followupCustomerCount,
CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount);
- List respVoList = new ArrayList<>(userIds.size());
- userIds.forEach(userId -> {
- final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO()
+ List respVoList = convertList(userIds, userId -> {
+ CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO()
.setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))
.setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0));
+ // ownerUserId 为基类属性
vo.setOwnerUserId(userId);
- respVoList.add(vo);
+ return vo;
});
// 4. 拼接用户信息
@@ -208,19 +204,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
@Override
public List getFollowupSummaryByType(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获得排行数据
- reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
- List respVoList = customerMapper.selectFollowupRecordCountGroupbyType(reqVO);
+ initParams(reqVO);
+ List respVoList = customerMapper.selectFollowupRecordCountGroupByType(reqVO);
// 3. 获取字典数据
List followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE);
- final Map followUpTypeMap = convertMap(followUpTypes,
+ Map followUpTypeMap = convertMap(followUpTypes,
DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
respVoList.forEach(vo -> {
vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType()));
@@ -232,26 +228,27 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
@Override
public List getContractSummary(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取统计数据
+ initParams(reqVO);
List respVoList = customerMapper.selectContractSummary(reqVO);
// 3. 设置 创建人、负责人、行业、来源
- // 获取客户所属行业
+ // 3.1 获取客户所属行业
Map industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY),
DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
- // 获取客户来源
+ // 3.2 获取客户来源
Map sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE),
DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
- // 获取创建人、负责人列表
+ // 3.3 获取创建人、负责人列表
Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList,
vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
-
+ // 3.4 设置 创建人、负责人、行业、来源
respVoList.forEach(vo -> {
MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
@@ -266,60 +263,57 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
@Override
public List getCustomerDealCycleByDate(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取分项统计数据
- reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
- reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
- final List customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyDate(reqVO);
+ initParams(reqVO);
+ List customerDealCycle = customerMapper.selectCustomerDealCycleGroupByDate(reqVO);
- // 3. 获取时间序列
- final List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
-
- // 4. 合并统计数据
- List respVoList = new ArrayList<>(times.size());
- final Map customerDealCycleMap = convertMap(customerDealCycle,
+ // 3. 合并统计数据
+ List times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
+ Map customerDealCycleMap = convertMap(customerDealCycle,
CrmStatisticsCustomerDealCycleByDateRespVO::getTime,
CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle);
- times.forEach(time -> respVoList.add(
+ List respVoList = convertList(times, time ->
new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
.setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
- ));
+ );
+
return respVoList;
}
@Override
public List getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO) {
// 1. 获得用户编号数组
- final List userIds = getUserIds(reqVO);
+ List userIds = getUserIds(reqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
reqVO.setUserIds(userIds);
// 2. 获取分项统计数据
- reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType());
- final List customerDealCycle = customerMapper.selectCustomerDealCycleGroupbyUser(reqVO);
- final List customerDealCount = customerMapper.selectCustomerDealCountGroupbyUser(reqVO);
+ initParams(reqVO);
+ List customerDealCycle = customerMapper.selectCustomerDealCycleGroupByUser(reqVO);
+ List customerDealCount = customerMapper.selectCustomerDealCountGroupByUser(reqVO);
// 3. 合并统计数据
- final Map customerDealCycleMap = convertMap(customerDealCycle,
+ Map customerDealCycleMap = convertMap(customerDealCycle,
CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,
CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle);
- final Map customerDealCountMap = convertMap(customerDealCount,
+ Map customerDealCountMap = convertMap(customerDealCount,
CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
- List respVoList = new ArrayList<>(userIds.size());
- userIds.forEach(userId -> {
- final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO()
+ List respVoList = convertList(userIds, userId -> {
+ CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO()
.setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))
.setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0));
+ // ownerUserId 为基类属性
vo.setOwnerUserId(userId);
- respVoList.add(vo);
+ return vo;
});
// 4. 拼接用户信息
@@ -335,8 +329,9 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
*/
private void appendUserInfo(List respVoList) {
Map userMap = adminUserApi.getUserMap(convertSet(respVoList,
- CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
- respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
+ CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
+ respVoList.forEach(vo -> MapUtils.findAndThen(userMap,
+ vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
}
/**
@@ -352,7 +347,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
}
// 情况二:选中某个部门
// 2.1 获得部门列表
- final Long deptId = reqVO.getDeptId();
+ Long deptId = reqVO.getDeptId();
List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
deptIds.add(deptId);
// 2.2 获得用户编号
@@ -378,7 +373,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
* @param endTime 结束时间
* @return 时间序列
*/
- // TODO @dhb52:可以抽象到 DateUtils 里,开始时间、结束时间,事件间隔,然后返回这个哈;
private List generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) {
boolean byMonth = queryByMonth(startTime, endTime);
List times = CollUtil.newArrayList();
@@ -404,4 +398,62 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
return queryByMonth(startTime, endTime) ? SQL_DATE_FORMAT_BY_MONTH : SQL_DATE_FORMAT_BY_DAY;
}
+ private void initParams(CrmStatisticsCustomerReqVO reqVO) {
+ final Integer intervalType = reqVO.getIntervalType();
+
+ // 1. 自定义时间间隔,必须输入起始日期-结束日期
+ if (DateIntervalEnum.CUSTOMER.getType().equals(intervalType)) {
+ if (ObjUtil.isEmpty(reqVO.getTimes()) || reqVO.getTimes().length != 2) {
+ throw exception(STATISTICS_CUSTOMER_TIMES_NOT_SET);
+ }
+ // 设置 mapper sqlDateFormat 参数
+ reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
+ // 自定义日期无需计算日期参数
+ return;
+ }
+
+ // 2. 根据时间区间类型计算时间段区间日期
+ DateTime beginDate = null;
+ DateTime endDate = null;
+ if (DateIntervalEnum.TODAY.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfDay(DateUtil.date());
+ endDate = DateUtil.endOfDay(DateUtil.date());
+ } else if (DateIntervalEnum.YESTERDAY.getType().equals(intervalType)) {
+ beginDate = DateUtil.offsetDay(DateUtil.date(), -1);
+ endDate = DateUtil.offsetDay(DateUtil.date(), -1);
+ } else if (DateIntervalEnum.THIS_WEEK.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfWeek(DateUtil.date());
+ endDate = DateUtil.endOfWeek(DateUtil.date());
+ } else if (DateIntervalEnum.LAST_WEEK.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
+ endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
+ } else if (DateIntervalEnum.THIS_MONTH.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfMonth(DateUtil.date());
+ endDate = DateUtil.endOfMonth(DateUtil.date());
+ } else if (DateIntervalEnum.LAST_MONTH.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
+ endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
+ } else if (DateIntervalEnum.THIS_QUARTER.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfQuarter(DateUtil.date());
+ endDate = DateUtil.endOfQuarter(DateUtil.date());
+ } else if (DateIntervalEnum.LAST_QUARTER.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
+ endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
+ } else if (DateIntervalEnum.THIS_YEAR.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfYear(DateUtil.date());
+ endDate = DateUtil.endOfYear(DateUtil.date());
+ } else if (DateIntervalEnum.LAST_YEAR.getType().equals(intervalType)) {
+ beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
+ endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
+ }
+
+ // 3. 计算开始、结束日期时间,并设置reqVo
+ LocalDateTime[] times = new LocalDateTime[2];
+ times[0] = LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.of(beginDate));
+ times[1] = LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.of(endDate));
+ // 3.1 设置 mapper 时间区间 参数
+ reqVO.setTimes(times);
+ // 3.2 设置 mapper sqlDateFormat 参数
+ reqVO.setSqlDateFormat(getSqlDateFormat(times[0], times[1]));
+ }
}
diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
index fce255651..32a1d425e 100644
--- a/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
+++ b/yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
@@ -2,251 +2,233 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-