Commit 22191e81e3a74f90dd20efe5d4db2d7938aa91de

Authored by puhui999
1 parent ce013a25

CRM: 新增客户区域数据统计

yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; @@ -2,6 +2,7 @@ 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.CrmStatisticCustomerAreaRespVO;
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.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.CrmStatisticCustomerLevelRespVO;
7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; 8 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
@@ -106,4 +107,11 @@ public class CrmStatisticsCustomerController { @@ -106,4 +107,11 @@ public class CrmStatisticsCustomerController {
106 return success(customerService.getCustomerLevel(reqVO)); 107 return success(customerService.getCustomerLevel(reqVO));
107 } 108 }
108 109
  110 + @GetMapping("/get-customer-area-summary")
  111 + @Operation(summary = "获取客户地区统计数据")
  112 + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
  113 + public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerArea(@Valid CrmStatisticsCustomerReqVO reqVO) {
  114 + return success(customerService.getCustomerArea(reqVO));
  115 + }
  116 +
109 } 117 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.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 CrmStatisticCustomerAreaRespVO {
  9 +
  10 + @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  11 + private Integer areaId;
  12 + @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省")
  13 + private String areaName;
  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 areaPortion;
  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.CrmStatisticCustomerAreaRespVO;
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.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.CrmStatisticCustomerLevelRespVO;
6 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
@@ -51,4 +52,6 @@ public interface CrmStatisticsCustomerMapper { @@ -51,4 +52,6 @@ public interface CrmStatisticsCustomerMapper {
51 52
52 List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); 53 List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);
53 54
  55 + List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO);
  56 +
54 } 57 }
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.CrmStatisticCustomerAreaRespVO;
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.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.CrmStatisticCustomerLevelRespVO;
6 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
@@ -104,4 +105,12 @@ public interface CrmStatisticsCustomerService { @@ -104,4 +105,12 @@ public interface CrmStatisticsCustomerService {
104 */ 105 */
105 List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); 106 List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO);
106 107
  108 + /**
  109 + * 获取客户地区统计数据
  110 + *
  111 + * @param reqVO 请求参数
  112 + * @return 统计数据
  113 + */
  114 + List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO);
  115 +
107 } 116 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
@@ -5,7 +5,11 @@ import cn.hutool.core.date.LocalDateTimeUtil; @@ -5,7 +5,11 @@ import cn.hutool.core.date.LocalDateTimeUtil;
5 import cn.hutool.core.util.ObjUtil; 5 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.framework.ip.core.Area;
  9 +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
  10 +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
8 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; 11 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
  12 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO;
9 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; 13 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; 14 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; 15 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO;
@@ -30,6 +34,7 @@ import java.util.Map; @@ -30,6 +34,7 @@ import java.util.Map;
30 import java.util.stream.Stream; 34 import java.util.stream.Stream;
31 35
32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; 36 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  37 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
33 import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; 38 import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
34 39
35 /** 40 /**
@@ -256,11 +261,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -256,11 +261,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
256 vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId()))); 261 vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
257 262
258 respVoList.forEach(vo -> { 263 respVoList.forEach(vo -> {
259 - MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);  
260 - MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName);  
261 - MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()), 264 + findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
  265 + findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
  266 + findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()),
262 user -> vo.setCreatorUserName(user.getNickname())); 267 user -> vo.setCreatorUserName(user.getNickname()));
263 - MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())); 268 + findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
264 }); 269 });
265 270
266 return respVoList; 271 return respVoList;
@@ -400,6 +405,35 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -400,6 +405,35 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
400 }); 405 });
401 } 406 }
402 407
  408 + @Override
  409 + public List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO) {
  410 + // 1. 获得用户编号数组
  411 + List<Long> userIds = getUserIds(reqVO);
  412 + if (CollUtil.isEmpty(userIds)) {
  413 + return Collections.emptyList();
  414 + }
  415 + reqVO.setUserIds(userIds);
  416 + // 2. 获取客户地区统计数据
  417 + List<CrmStatisticCustomerAreaRespVO> list = customerMapper.selectSummaryListByAreaId(reqVO);
  418 + if (CollUtil.isEmpty(list)) {
  419 + return Collections.emptyList();
  420 + }
  421 +
  422 + // 拼接数据
  423 + List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area);
  424 + areaList.add(new Area().setId(null).setName("未知"));
  425 + Map<Integer, Area> areaMap = convertMap(areaList, Area::getId);
  426 + List<CrmStatisticCustomerAreaRespVO> customerAreaRespVOList = convertList(list, item -> {
  427 + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE);
  428 + if (parentId == null) {
  429 + return item;
  430 + }
  431 + findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName()));
  432 + return item;
  433 + });
  434 + return customerAreaRespVOList;
  435 + }
  436 +
403 /** 437 /**
404 * 拼接用户信息(昵称) 438 * 拼接用户信息(昵称)
405 * 439 *
@@ -408,7 +442,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe @@ -408,7 +442,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
408 private <T extends CrmStatisticsCustomerByUserBaseRespVO> void appendUserInfo(List<T> respVoList) { 442 private <T extends CrmStatisticsCustomerByUserBaseRespVO> void appendUserInfo(List<T> respVoList) {
409 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(respVoList, 443 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(respVoList,
410 CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId)); 444 CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
411 - respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()))); 445 + respVoList.forEach(vo -> findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
412 } 446 }
413 447
414 /** 448 /**
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
@@ -312,5 +312,26 @@ @@ -312,5 +312,26 @@
312 GROUP BY 312 GROUP BY
313 level; 313 level;
314 </select> 314 </select>
  315 + <select id="selectSummaryListByAreaId"
  316 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO">
  317 + SELECT
  318 + area_id,
  319 + COUNT(*) AS customerCount,
  320 + SUM(deal_status) AS dealCount,
  321 + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS areaPortion,
  322 + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion
  323 + FROM
  324 + crm_customer
  325 + WHERE
  326 + deleted = 0 AND area_id IS NOT NULL
  327 + AND owner_user_id IN
  328 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  329 + #{userId}
  330 + </foreach>
  331 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  332 + #{times[1],javaType=java.time.LocalDateTime}
  333 + GROUP BY
  334 + area_id;
  335 + </select>
315 336
316 </mapper> 337 </mapper>