mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	feat: 客户成交周期分析(按区域、按产品)
This commit is contained in:
		| @@ -53,3 +53,13 @@ tenant-id: {{adminTenentId}} | ||||
| 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 | ||||
| Authorization: Bearer {{token}} | ||||
| tenant-id: {{adminTenentId}} | ||||
|  | ||||
| ### 6.3 获取客户成交周期(按区域) | ||||
| GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-area?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 | ||||
| Authorization: Bearer {{token}} | ||||
| tenant-id: {{adminTenentId}} | ||||
|  | ||||
| ### 6.4 获取客户成交周期(按产品) | ||||
| GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-product?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59 | ||||
| Authorization: Bearer {{token}} | ||||
| tenant-id: {{adminTenentId}} | ||||
|   | ||||
| @@ -96,6 +96,18 @@ public class CrmStatisticsCustomerController { | ||||
|         return success(customerService.getCustomerDealCycleByUser(reqVO)); | ||||
|     } | ||||
|  | ||||
|     // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; | ||||
|     @GetMapping("/get-customer-deal-cycle-by-area") | ||||
|     @Operation(summary = "获取客户成交周期(按用户)") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticsCustomerDealCycleByAreaRespVO>> getCustomerDealCycleByArea(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerDealCycleByArea(reqVO)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-customer-deal-cycle-by-product") | ||||
|     @Operation(summary = "获取客户成交周期(按用户)") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticsCustomerDealCycleByProductRespVO>> getCustomerDealCycleByProduct(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerDealCycleByProduct(reqVO)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,24 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; | ||||
|  | ||||
| import com.fasterxml.jackson.annotation.JsonIgnore; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 客户成交周期分析(按区域) VO") | ||||
| @Data | ||||
| public class CrmStatisticsCustomerDealCycleByAreaRespVO { | ||||
|  | ||||
|     @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     @JsonIgnore | ||||
|     private Integer areaId; | ||||
|  | ||||
|     @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") | ||||
|     private String areaName; | ||||
|  | ||||
|     @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") | ||||
|     private Double customerDealCycle; | ||||
|  | ||||
|     @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer customerDealCount; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,19 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 客户成交周期分析(按产品) VO") | ||||
| @Data | ||||
| public class CrmStatisticsCustomerDealCycleByProductRespVO { | ||||
|  | ||||
|     @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示产品") | ||||
|     private String productName; | ||||
|  | ||||
|     @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") | ||||
|     private Double customerDealCycle; | ||||
|  | ||||
|     @Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer customerDealCount; | ||||
|  | ||||
| } | ||||
| @@ -53,6 +53,7 @@ public interface CrmStatisticsCustomerMapper { | ||||
|  | ||||
|     /** | ||||
|      * 合同总金额(按用户) | ||||
|      * | ||||
|      * @return 统计数据@return 统计数据@param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
| @@ -191,4 +192,20 @@ public interface CrmStatisticsCustomerMapper { | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 客户成交周期(按区域) | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByAreaRespVO> selectCustomerDealCycleGroupByAreaId(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 客户成交周期(按产品) | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByProductRespVO> selectCustomerDealCycleGroupByProductId(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -77,7 +77,7 @@ public interface CrmStatisticsCustomerService { | ||||
|  | ||||
|     /** | ||||
|      * 客户成交周期(按日期) | ||||
|      * | ||||
|      * <p> | ||||
|      * 成交周期的定义:客户 customer 在创建出来,到合同 contract 第一次成交的时间差 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
| @@ -93,4 +93,20 @@ public interface CrmStatisticsCustomerService { | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 客户成交周期(按区域) | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByAreaRespVO> getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 客户成交周期(按产品) | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByProductRespVO> getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,9 @@ import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.framework.ip.core.Area; | ||||
| import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; | ||||
| import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | ||||
| 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.system.api.dept.DeptApi; | ||||
| @@ -19,6 +22,7 @@ import java.time.LocalDateTime; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.function.Function; | ||||
| import java.util.stream.Stream; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||
| @@ -290,6 +294,51 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||||
|         return summaryList; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticsCustomerDealCycleByAreaRespVO> getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         reqVO.setUserIds(userIds); | ||||
|  | ||||
|         // 2. 获取客户地区统计数据 | ||||
|         List<CrmStatisticsCustomerDealCycleByAreaRespVO> dealCycleByAreaList = customerMapper.selectCustomerDealCycleGroupByAreaId(reqVO); | ||||
|         if (CollUtil.isEmpty(dealCycleByAreaList)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         // 3. 拼接数据 | ||||
|         Map<Integer, Area> areaMap = convertMap(AreaUtils.getByType(AreaTypeEnum.PROVINCE, Function.identity()), | ||||
|                                                 Area::getId); | ||||
|         return convertList(dealCycleByAreaList, vo -> { | ||||
|             if (vo.getAreaId() != null) { | ||||
|                 Integer parentId = AreaUtils.getParentIdByType(vo.getAreaId(), AreaTypeEnum.PROVINCE); | ||||
|                 findAndThen(areaMap, parentId, area -> vo.setAreaId(parentId).setAreaName(area.getName())); | ||||
|             } | ||||
|             return vo; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticsCustomerDealCycleByProductRespVO> getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         reqVO.setUserIds(userIds); | ||||
|  | ||||
|         // 2. 获取客户产品统计数据 | ||||
|         List<CrmStatisticsCustomerDealCycleByProductRespVO> dealCycleByProductList = customerMapper.selectCustomerDealCycleGroupByProductId(reqVO); | ||||
|         if (CollUtil.isEmpty(dealCycleByProductList)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         return dealCycleByProductList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 拼接用户信息(昵称) | ||||
|      * | ||||
|   | ||||
| @@ -19,17 +19,18 @@ | ||||
|     <!-- TODO 芋艿:应该不用过滤时间 --> | ||||
|     <select id="selectCustomerDealCountGroupByDate" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO"> | ||||
|         SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d') AS time, | ||||
|                COUNT(DISTINCT customer.id) AS customer_deal_count | ||||
|         SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d')    AS time, | ||||
|                COUNT(DISTINCT customer.id)                      AS customer_deal_count | ||||
|           FROM crm_customer AS customer | ||||
|                 LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id | ||||
|          WHERE customer.deleted = 0 AND contract.deleted = 0 | ||||
|          WHERE customer.deleted = 0 | ||||
|            AND contract.deleted = 0 | ||||
|            AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} | ||||
|            AND customer.owner_user_id IN | ||||
|                 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|                     #{userId} | ||||
|                 </foreach> | ||||
|            AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} | ||||
|            AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} | ||||
|          GROUP BY time | ||||
|     </select> | ||||
|  | ||||
| @@ -53,13 +54,14 @@ | ||||
|                COUNT(DISTINCT customer.id) AS customer_deal_count | ||||
|           FROM crm_customer AS customer | ||||
|                 LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id | ||||
|          WHERE customer.deleted = 0 AND contract.deleted = 0 | ||||
|          WHERE customer.deleted = 0 | ||||
|            AND contract.deleted = 0 | ||||
|            AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} | ||||
|            AND customer.owner_user_id IN | ||||
|                 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|                     #{userId} | ||||
|                 </foreach> | ||||
|            AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} | ||||
|            AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} | ||||
|          GROUP BY customer.owner_user_id | ||||
|     </select> | ||||
|  | ||||
| @@ -221,4 +223,42 @@ | ||||
|          GROUP BY customer.owner_user_id | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectCustomerDealCycleGroupByAreaId" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByAreaRespVO"> | ||||
|         SELECT customer.area_id AS area_id, | ||||
|                IFNULL(TRUNCATE(AVG(TIMESTAMPDIFF(DAY, customer.create_time, contract.order_date)), 1), 0) AS customer_deal_cycle, | ||||
|                COUNT(DISTINCT customer.id) AS customer_deal_count | ||||
|         FROM crm_customer AS customer | ||||
|                 LEFT JOIN crm_contract AS contract ON customer.id = contract.customer_id | ||||
|         WHERE customer.deleted = 0 | ||||
|           AND contract.deleted = 0 | ||||
|           AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} | ||||
|           AND customer.owner_user_id IN | ||||
|                 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|                     #{userId} | ||||
|                 </foreach> | ||||
|           AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} | ||||
|         GROUP BY | ||||
|             customer.area_id | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectCustomerDealCycleGroupByProductId" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByProductRespVO"> | ||||
|         SELECT (SELECT name FROM crm_product WHERE id = product.id)                                         AS product_name, | ||||
|                IFNULL(TRUNCATE(AVG(TIMESTAMPDIFF(DAY, customer.create_time, contract.order_date)), 1), 0)   AS customer_deal_cycle, | ||||
|                COUNT(DISTINCT customer.id)                                                                  AS customer_deal_count | ||||
|           FROM crm_customer AS customer | ||||
|                 LEFT JOIN crm_contract AS contract ON customer.id = contract.customer_id | ||||
|                 LEFT JOIN crm_contract_product AS product ON product.contract_id = contract.id | ||||
|          WHERE customer.deleted = 0 | ||||
|            AND contract.deleted = 0 | ||||
|            AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} | ||||
|            AND customer.owner_user_id IN | ||||
|                  <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|                      #{userId} | ||||
|                  </foreach> | ||||
|            AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} | ||||
|         GROUP BY product.id | ||||
|     </select> | ||||
|  | ||||
| </mapper> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 dhb52
					dhb52