Commit ce013a2562883f22884ce267ac8f980dd86c73d4

Authored by puhui999
1 parent 0dd36f6c

CRM: 新增客户行业、来源、级别统计数据统计

yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java
@@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; 4 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
  7 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
5 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; 8 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService;
6 import io.swagger.v3.oas.annotations.Operation; 9 import io.swagger.v3.oas.annotations.Operation;
7 import io.swagger.v3.oas.annotations.tags.Tag; 10 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -82,4 +85,25 @@ public class CrmStatisticsCustomerController { @@ -82,4 +85,25 @@ public class CrmStatisticsCustomerController {
82 return success(customerService.getCustomerDealCycleByUser(reqVO)); 85 return success(customerService.getCustomerDealCycleByUser(reqVO));
83 } 86 }
84 87
  88 + @GetMapping("/get-customer-industry-summary")
  89 + @Operation(summary = "获取客户行业统计数据")
  90 + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
  91 + public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) {
  92 + return success(customerService.getCustomerIndustry(reqVO));
  93 + }
  94 +
  95 + @GetMapping("/get-customer-source-summary")
  96 + @Operation(summary = "获取客户来源统计数据")
  97 + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
  98 + public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) {
  99 + return success(customerService.getCustomerSource(reqVO));
  100 + }
  101 +
  102 + @GetMapping("/get-customer-level-summary")
  103 + @Operation(summary = "获取客户级别统计数据")
  104 + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
  105 + public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) {
  106 + return success(customerService.getCustomerLevel(reqVO));
  107 + }
  108 +
85 } 109 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  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 CrmStatisticCustomerIndustryRespVO {
  9 +
  10 + @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  11 + private Integer industryId;
  12 + @Schema(description = "客户行业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  13 + private String industryName;
  14 +
  15 + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer customerCount;
  17 +
  18 + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer dealCount;
  20 +
  21 + @Schema(description = "行业占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + private Double industryPortion;
  23 +
  24 + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + private Double dealPortion;
  26 +
  27 +}
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  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 CrmStatisticCustomerLevelRespVO {
  9 +
  10 + @Schema(description = "客户级别ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  11 + private Integer level;
  12 + @Schema(description = "客户级别名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  13 + private String levelName;
  14 +
  15 + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer customerCount;
  17 +
  18 + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer dealCount;
  20 +
  21 + @Schema(description = "级别占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + private Double levelPortion;
  23 +
  24 + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + private Double dealPortion;
  26 +
  27 +}
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze;
  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 CrmStatisticCustomerSourceRespVO {
  9 +
  10 + @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  11 + private Integer source;
  12 + @Schema(description = "客户来源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  13 + private String sourceName;
  14 +
  15 + @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer customerCount;
  17 +
  18 + @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer dealCount;
  20 +
  21 + @Schema(description = "来源占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + private Double sourcePortion;
  23 +
  24 + @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + private Double dealPortion;
  26 +
  27 +}
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.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.*; 3 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
4 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
5 8
6 import java.util.List; 9 import java.util.List;
@@ -42,4 +45,10 @@ public interface CrmStatisticsCustomerMapper { @@ -42,4 +45,10 @@ public interface CrmStatisticsCustomerMapper {
42 45
43 List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO); 46 List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
44 47
  48 + List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO);
  49 +
  50 + List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO);
  51 +
  52 + List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);
  53 +
45 } 54 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java
1 package cn.iocoder.yudao.module.crm.service.statistics; 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 2
3 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; 3 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
4 7
5 import java.util.List; 8 import java.util.List;
6 9
@@ -77,4 +80,28 @@ public interface CrmStatisticsCustomerService { @@ -77,4 +80,28 @@ public interface CrmStatisticsCustomerService {
77 */ 80 */
78 List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); 81 List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO);
79 82
  83 + /**
  84 + * 获取客户行业统计数据
  85 + *
  86 + * @param reqVO 请求参数
  87 + * @return 统计数据
  88 + */
  89 + List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO);
  90 +
  91 + /**
  92 + * 获取客户来源统计数据
  93 + *
  94 + * @param reqVO 请求参数
  95 + * @return 统计数据
  96 + */
  97 + List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO);
  98 +
  99 + /**
  100 + * 获取客户级别统计数据
  101 + *
  102 + * @param reqVO 请求参数
  103 + * @return 统计数据
  104 + */
  105 + List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO);
  106 +
80 } 107 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
@@ -6,6 +6,9 @@ import cn.hutool.core.util.ObjUtil; @@ -6,6 +6,9 @@ import cn.hutool.core.util.ObjUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
8 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; 8 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
  9 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO;
  10 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO;
  11 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
9 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; 12 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper;
10 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 13 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
11 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 14 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
@@ -78,15 +81,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -78,15 +81,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
78 // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...) 81 // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...)
79 List<CrmStatisticsCustomerSummaryByDateRespVO> respVoList = new ArrayList<>(times.size()); 82 List<CrmStatisticsCustomerSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());
80 final Map<String, Integer> customerCreateCountMap = convertMap(customerCreateCount, 83 final Map<String, Integer> customerCreateCountMap = convertMap(customerCreateCount,
81 - CrmStatisticsCustomerSummaryByDateRespVO::getTime,  
82 - CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount); 84 + CrmStatisticsCustomerSummaryByDateRespVO::getTime,
  85 + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount);
83 final Map<String, Integer> customerDealCountMap = convertMap(customerDealCount, 86 final Map<String, Integer> customerDealCountMap = convertMap(customerDealCount,
84 - CrmStatisticsCustomerSummaryByDateRespVO::getTime,  
85 - CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount); 87 + CrmStatisticsCustomerSummaryByDateRespVO::getTime,
  88 + CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount);
86 times.forEach(time -> respVoList.add( 89 times.forEach(time -> respVoList.add(
87 - new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time)  
88 - .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))  
89 - .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0)) 90 + new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time)
  91 + .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
  92 + .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))
90 )); 93 ));
91 return respVoList; 94 return respVoList;
92 } 95 }
@@ -108,25 +111,25 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -108,25 +111,25 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
108 111
109 // 3. 合并统计数据 112 // 3. 合并统计数据
110 final Map<Long, Integer> customerCreateCountMap = convertMap(customerCreateCount, 113 final Map<Long, Integer> customerCreateCountMap = convertMap(customerCreateCount,
111 - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,  
112 - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount); 114 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  115 + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount);
113 final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount, 116 final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
114 - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,  
115 - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); 117 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  118 + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
116 final Map<Long, BigDecimal> contractPriceMap = convertMap(contractPrice, 119 final Map<Long, BigDecimal> contractPriceMap = convertMap(contractPrice,
117 - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,  
118 - CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice); 120 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  121 + CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice);
119 final Map<Long, BigDecimal> receivablePriceMap = convertMap(receivablePrice, 122 final Map<Long, BigDecimal> receivablePriceMap = convertMap(receivablePrice,
120 - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,  
121 - CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice); 123 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  124 + CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice);
122 List<CrmStatisticsCustomerSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size()); 125 List<CrmStatisticsCustomerSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());
123 userIds.forEach(userId -> { 126 userIds.forEach(userId -> {
124 final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO(); 127 final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO();
125 vo.setOwnerUserId(userId); 128 vo.setOwnerUserId(userId);
126 vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0)) 129 vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0))
127 - .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))  
128 - .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))  
129 - .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO)); 130 + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))
  131 + .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))
  132 + .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO));
130 respVoList.add(vo); 133 respVoList.add(vo);
131 }); 134 });
132 135
@@ -156,15 +159,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -156,15 +159,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
156 // 4. 合并统计数据 159 // 4. 合并统计数据
157 List<CrmStatisticsFollowupSummaryByDateRespVO> respVoList = new ArrayList<>(times.size()); 160 List<CrmStatisticsFollowupSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());
158 final Map<String, Integer> followupRecordCountMap = convertMap(followupRecordCount, 161 final Map<String, Integer> followupRecordCountMap = convertMap(followupRecordCount,
159 - CrmStatisticsFollowupSummaryByDateRespVO::getTime,  
160 - CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount); 162 + CrmStatisticsFollowupSummaryByDateRespVO::getTime,
  163 + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount);
161 final Map<String, Integer> followupCustomerCountMap = convertMap(followupCustomerCount, 164 final Map<String, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
162 - CrmStatisticsFollowupSummaryByDateRespVO::getTime,  
163 - CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount); 165 + CrmStatisticsFollowupSummaryByDateRespVO::getTime,
  166 + CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount);
164 times.forEach(time -> respVoList.add( 167 times.forEach(time -> respVoList.add(
165 - new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)  
166 - .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))  
167 - .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0)) 168 + new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)
  169 + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))
  170 + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0))
168 )); 171 ));
169 172
170 return respVoList; 173 return respVoList;
@@ -186,16 +189,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -186,16 +189,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
186 189
187 // 3. 合并统计数据 190 // 3. 合并统计数据
188 final Map<Long, Integer> followupRecordCountMap = convertMap(followupRecordCount, 191 final Map<Long, Integer> followupRecordCountMap = convertMap(followupRecordCount,
189 - CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,  
190 - CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount); 192 + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
  193 + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount);
191 final Map<Long, Integer> followupCustomerCountMap = convertMap(followupCustomerCount, 194 final Map<Long, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
192 - CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,  
193 - CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount); 195 + CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
  196 + CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount);
194 List<CrmStatisticsFollowupSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size()); 197 List<CrmStatisticsFollowupSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());
195 userIds.forEach(userId -> { 198 userIds.forEach(userId -> {
196 final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO() 199 final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO()
197 - .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))  
198 - .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0)); 200 + .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))
  201 + .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0));
199 vo.setOwnerUserId(userId); 202 vo.setOwnerUserId(userId);
200 respVoList.add(vo); 203 respVoList.add(vo);
201 }); 204 });
@@ -221,7 +224,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -221,7 +224,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
221 // 3. 获取字典数据 224 // 3. 获取字典数据
222 List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE); 225 List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE);
223 final Map<String, String> followUpTypeMap = convertMap(followUpTypes, 226 final Map<String, String> followUpTypeMap = convertMap(followUpTypes,
224 - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); 227 + DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
225 respVoList.forEach(vo -> { 228 respVoList.forEach(vo -> {
226 vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType())); 229 vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType()));
227 }); 230 });
@@ -244,19 +247,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -244,19 +247,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
244 // 3. 设置 创建人、负责人、行业、来源 247 // 3. 设置 创建人、负责人、行业、来源
245 // 获取客户所属行业 248 // 获取客户所属行业
246 Map<String, String> industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY), 249 Map<String, String> industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY),
247 - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); 250 + DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
248 // 获取客户来源 251 // 获取客户来源
249 Map<String, String> sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE), 252 Map<String, String> sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE),
250 - DictDataRespDTO::getValue, DictDataRespDTO::getLabel); 253 + DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
251 // 获取创建人、负责人列表 254 // 获取创建人、负责人列表
252 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList, 255 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList,
253 - vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); 256 + vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
254 257
255 respVoList.forEach(vo -> { 258 respVoList.forEach(vo -> {
256 MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName); 259 MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
257 MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName); 260 MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
258 MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), 261 MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()),
259 - user -> vo.setCreatorUserName(user.getNickname())); 262 + user -> vo.setCreatorUserName(user.getNickname()));
260 MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); 263 MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
261 }); 264 });
262 265
@@ -283,11 +286,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -283,11 +286,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
283 // 4. 合并统计数据 286 // 4. 合并统计数据
284 List<CrmStatisticsCustomerDealCycleByDateRespVO> respVoList = new ArrayList<>(times.size()); 287 List<CrmStatisticsCustomerDealCycleByDateRespVO> respVoList = new ArrayList<>(times.size());
285 final Map<String, Double> customerDealCycleMap = convertMap(customerDealCycle, 288 final Map<String, Double> customerDealCycleMap = convertMap(customerDealCycle,
286 - CrmStatisticsCustomerDealCycleByDateRespVO::getTime,  
287 - CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle); 289 + CrmStatisticsCustomerDealCycleByDateRespVO::getTime,
  290 + CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle);
288 times.forEach(time -> respVoList.add( 291 times.forEach(time -> respVoList.add(
289 - new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)  
290 - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D)) 292 + new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
  293 + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
291 )); 294 ));
292 return respVoList; 295 return respVoList;
293 } 296 }
@@ -308,16 +311,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -308,16 +311,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
308 311
309 // 3. 合并统计数据 312 // 3. 合并统计数据
310 final Map<Long, Double> customerDealCycleMap = convertMap(customerDealCycle, 313 final Map<Long, Double> customerDealCycleMap = convertMap(customerDealCycle,
311 - CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,  
312 - CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle); 314 + CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,
  315 + CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle);
313 final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount, 316 final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
314 - CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,  
315 - CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount); 317 + CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
  318 + CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
316 List<CrmStatisticsCustomerDealCycleByUserRespVO> respVoList = new ArrayList<>(userIds.size()); 319 List<CrmStatisticsCustomerDealCycleByUserRespVO> respVoList = new ArrayList<>(userIds.size());
317 userIds.forEach(userId -> { 320 userIds.forEach(userId -> {
318 final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO() 321 final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO()
319 - .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))  
320 - .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0)); 322 + .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))
  323 + .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0));
321 vo.setOwnerUserId(userId); 324 vo.setOwnerUserId(userId);
322 respVoList.add(vo); 325 respVoList.add(vo);
323 }); 326 });
@@ -328,6 +331,75 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -328,6 +331,75 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
328 return respVoList; 331 return respVoList;
329 } 332 }
330 333
  334 + @Override
  335 + public List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) {
  336 + // 1. 获得用户编号数组
  337 + List<Long> userIds = getUserIds(reqVO);
  338 + if (CollUtil.isEmpty(userIds)) {
  339 + return Collections.emptyList();
  340 + }
  341 + reqVO.setUserIds(userIds);
  342 + // 2. 获取客户行业统计数据
  343 + List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = customerMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO);
  344 + if (CollUtil.isEmpty(industryRespVOList)) {
  345 + return Collections.emptyList();
  346 + }
  347 +
  348 + return convertList(industryRespVOList, item -> {
  349 + if (ObjUtil.isNull(item.getIndustryId())) {
  350 + return item;
  351 + }
  352 + item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId()));
  353 + return item;
  354 + });
  355 + }
  356 +
  357 + @Override
  358 + public List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO) {
  359 + // 1. 获得用户编号数组
  360 + List<Long> userIds = getUserIds(reqVO);
  361 + if (CollUtil.isEmpty(userIds)) {
  362 + return Collections.emptyList();
  363 + }
  364 + reqVO.setUserIds(userIds);
  365 + // 2. 获取客户行业统计数据
  366 + List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = customerMapper.selectCustomerSourceListGroupbySource(reqVO);
  367 + if (CollUtil.isEmpty(sourceRespVOList)) {
  368 + return Collections.emptyList();
  369 + }
  370 +
  371 + return convertList(sourceRespVOList, item -> {
  372 + if (ObjUtil.isNull(item.getSource())) {
  373 + return item;
  374 + }
  375 + item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource()));
  376 + return item;
  377 + });
  378 + }
  379 +
  380 + @Override
  381 + public List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) {
  382 + // 1. 获得用户编号数组
  383 + List<Long> userIds = getUserIds(reqVO);
  384 + if (CollUtil.isEmpty(userIds)) {
  385 + return Collections.emptyList();
  386 + }
  387 + reqVO.setUserIds(userIds);
  388 + // 2. 获取客户行业统计数据
  389 + List<CrmStatisticCustomerLevelRespVO> levelRespVOList = customerMapper.selectCustomerLevelListGroupbyLevel(reqVO);
  390 + if (CollUtil.isEmpty(levelRespVOList)) {
  391 + return Collections.emptyList();
  392 + }
  393 +
  394 + return convertList(levelRespVOList, item -> {
  395 + if (ObjUtil.isNull(item.getLevel())) {
  396 + return item;
  397 + }
  398 + item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel()));
  399 + return item;
  400 + });
  401 + }
  402 +
331 /** 403 /**
332 * 拼接用户信息(昵称) 404 * 拼接用户信息(昵称)
333 * 405 *
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
@@ -249,4 +249,68 @@ @@ -249,4 +249,68 @@
249 GROUP BY a.owner_user_id 249 GROUP BY a.owner_user_id
250 </select> 250 </select>
251 251
  252 + <select id="selectCustomerIndustryListGroupbyIndustryId"
  253 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO">
  254 + SELECT
  255 + industry_id,
  256 + COUNT(*) AS customerCount,
  257 + SUM(deal_status) AS dealCount,
  258 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS industryPortion,
  259 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  260 + FROM
  261 + crm_customer
  262 + WHERE
  263 + deleted = 0 AND industry_id IS NOT NULL
  264 + AND owner_user_id IN
  265 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  266 + #{userId}
  267 + </foreach>
  268 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  269 + #{times[1],javaType=java.time.LocalDateTime}
  270 + GROUP BY
  271 + industry_id;
  272 + </select>
  273 + <select id="selectCustomerSourceListGroupbySource"
  274 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO">
  275 + SELECT
  276 + source,
  277 + COUNT(*) AS customerCount,
  278 + SUM(deal_status) AS dealCount,
  279 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS sourcePortion,
  280 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  281 + FROM
  282 + crm_customer
  283 + WHERE
  284 + deleted = 0 AND source IS NOT NULL
  285 + AND owner_user_id IN
  286 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  287 + #{userId}
  288 + </foreach>
  289 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  290 + #{times[1],javaType=java.time.LocalDateTime}
  291 + GROUP BY
  292 + source;
  293 + </select>
  294 + <select id="selectCustomerLevelListGroupbyLevel"
  295 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO">
  296 + SELECT
  297 + level,
  298 + COUNT(*) AS customerCount,
  299 + SUM(deal_status) AS dealCount,
  300 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS levelPortion,
  301 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  302 + FROM
  303 + crm_customer
  304 + WHERE
  305 + deleted = 0 AND level IS NOT NULL
  306 + AND owner_user_id IN
  307 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  308 + #{userId}
  309 + </foreach>
  310 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  311 + #{times[1],javaType=java.time.LocalDateTime}
  312 + GROUP BY
  313 + level;
  314 + </select>
  315 +
252 </mapper> 316 </mapper>
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java
1 package cn.iocoder.yudao.module.system.api.dict; 1 package cn.iocoder.yudao.module.system.api.dict;
2 2
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; 5 import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
4 6
5 import java.util.Collection; 7 import java.util.Collection;
@@ -34,6 +36,21 @@ public interface DictDataApi { @@ -34,6 +36,21 @@ public interface DictDataApi {
34 DictDataRespDTO getDictData(String type, String value); 36 DictDataRespDTO getDictData(String type, String value);
35 37
36 /** 38 /**
  39 + * 获得指定的字典标签,从缓存中
  40 + *
  41 + * @param type 字典类型
  42 + * @param value 字典数据值
  43 + * @return 字典标签
  44 + */
  45 + default String getDictDataLabel(String type, Integer value) {
  46 + DictDataRespDTO dictData = getDictData(type, String.valueOf(value));
  47 + if (ObjUtil.isNull(dictData)) {
  48 + return StrUtil.EMPTY;
  49 + }
  50 + return dictData.getLabel();
  51 + }
  52 +
  53 + /**
37 * 解析获得指定的字典数据,从缓存中 54 * 解析获得指定的字典数据,从缓存中
38 * 55 *
39 * @param type 字典类型 56 * @param type 字典类型
yudao-server/pom.xml
@@ -95,11 +95,11 @@ @@ -95,11 +95,11 @@
95 </dependency> 95 </dependency>
96 96
97 <!-- ERP 相关模块。默认注释,保证编译速度 --> 97 <!-- ERP 相关模块。默认注释,保证编译速度 -->
98 - <dependency>  
99 - <groupId>cn.iocoder.boot</groupId>  
100 - <artifactId>yudao-module-erp-biz</artifactId>  
101 - <version>${revision}</version>  
102 - </dependency> 98 +<!-- <dependency>-->
  99 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  100 +<!-- <artifactId>yudao-module-erp-biz</artifactId>-->
  101 +<!-- <version>${revision}</version>-->
  102 +<!-- </dependency>-->
103 103
104 <!-- spring boot 配置所需依赖 --> 104 <!-- spring boot 配置所需依赖 -->
105 <dependency> 105 <dependency>