mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	feat: CRM/数据统计/员工客户分析 初稿
This commit is contained in:
		| @@ -55,4 +55,18 @@ public class CrmStatisticsCustomerController { | ||||
|         return success(customerService.getDistinctRecordCount(reqVO)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-record-type-count") | ||||
|     @Operation(summary = "获取客户跟进方式统计数") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticsCustomerCountVO>> getRecordTypeCount(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getRecordTypeCount(reqVO)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-customer-cycle") | ||||
|     @Operation(summary = "获取客户成交周期") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticsCustomerCountVO>> getCustomerCycle(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerCycle(reqVO)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -23,6 +23,12 @@ public class CrmStatisticsCustomerCountVO { | ||||
|      * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行 | ||||
|      */ | ||||
|     @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer count; | ||||
|     private Integer count = 0; | ||||
|  | ||||
|     /** | ||||
|      * 成交周期(天) | ||||
|      */ | ||||
|     @Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0") | ||||
|     private Double cycle = 0.0; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -22,4 +22,8 @@ public interface CrmStatisticsCustomerMapper { | ||||
|  | ||||
|     List<CrmStatisticsCustomerCountVO> selectDistinctRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticsCustomerCountVO> selectRecordCountGroupbyType(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticsCustomerCountVO> selectCustomerCycleGroupbyDate(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -45,4 +45,20 @@ public interface CrmStatisticsCustomerService { | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerCountVO> getDistinctRecordCount(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取客户跟进方式统计数 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 客户跟进方式统计数 | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerCountVO> getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取客户成交周期 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 客户成交周期 | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerCountVO> getCustomerCycle(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -3,12 +3,14 @@ package cn.iocoder.yudao.module.crm.service.statistics; | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.date.LocalDateTimeUtil; | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; | ||||
| 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; | ||||
| import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; | ||||
| import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||||
| import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||||
| import jakarta.annotation.Resource; | ||||
| @@ -21,7 +23,8 @@ import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.function.Function; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||||
|  | ||||
| /** | ||||
|  * CRM 数据统计 员工客户分析 Service 实现类 | ||||
| @@ -39,6 +42,8 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||||
|     private AdminUserApi adminUserApi; | ||||
|     @Resource | ||||
|     private DeptApi deptApi; | ||||
|     @Resource | ||||
|     private DictDataApi dictDataApi; | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticsCustomerCountVO> getTotalCustomerCount(CrmStatisticsCustomerReqVO reqVO) { | ||||
| @@ -62,6 +67,37 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||||
|         return getStat(reqVO, customerMapper::selectDistinctRecordCountGroupbyDate); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticsCustomerCountVO> getRecordTypeCount(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组: 如果用户编号为空, 则获得部门下的用户编号数组 | ||||
|         if (ObjUtil.isNotNull(reqVO.getUserId())) { | ||||
|             reqVO.setUserIds(List.of(reqVO.getUserId())); | ||||
|         } else { | ||||
|             reqVO.setUserIds(getUserIds(reqVO.getDeptId())); | ||||
|         } | ||||
|         if (CollUtil.isEmpty(reqVO.getUserIds())) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         // 2. 获得排行数据 | ||||
|         reqVO.setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()); | ||||
|         List<CrmStatisticsCustomerCountVO> stats = customerMapper.selectRecordCountGroupbyType(reqVO); | ||||
|  | ||||
|         // 3. 获取字典数据 | ||||
|         List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList("crm_follow_up_type"); | ||||
|         final Map<String, String> followUpTypeMap = convertMap(followUpTypes, DictDataRespDTO::getValue, DictDataRespDTO::getLabel); | ||||
|         stats.forEach(stat -> { | ||||
|             stat.setCategory(followUpTypeMap.get(stat.getCategory())); | ||||
|         }); | ||||
|  | ||||
|         return stats; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticsCustomerCountVO> getCustomerCycle(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return getStat(reqVO, customerMapper::selectCustomerCycleGroupbyDate); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获得统计数据 | ||||
|      * | ||||
| @@ -98,9 +134,9 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||||
|  | ||||
|         // 4. 生成时间序列 | ||||
|         List<CrmStatisticsCustomerCountVO> result = CollUtil.newArrayList(); | ||||
|         while (startTime.compareTo(endTime) <= 0) { | ||||
|         while (!startTime.isAfter(endTime)) { | ||||
|             final String category = LocalDateTimeUtil.format(startTime, byMonth ? "yyyyMM" : "yyyyMMdd"); | ||||
|             result.add(new CrmStatisticsCustomerCountVO().setCategory(category).setCount(0)); | ||||
|             result.add(new CrmStatisticsCustomerCountVO().setCategory(category)); | ||||
|             if (byMonth) | ||||
|                 startTime = startTime.plusMonths(1); | ||||
|             else | ||||
| @@ -108,12 +144,13 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||||
|         } | ||||
|  | ||||
|         // 5. 使用时间序列填充结果 | ||||
|         final Map<String, Integer> statMap = convertMap(stats, | ||||
|                 CrmStatisticsCustomerCountVO::getCategory, | ||||
|                 CrmStatisticsCustomerCountVO::getCount); | ||||
|         final Map<String, CrmStatisticsCustomerCountVO> statMap = convertMap(stats, | ||||
|             CrmStatisticsCustomerCountVO::getCategory, | ||||
|             Function.identity()); | ||||
|         result.forEach(r -> { | ||||
|             if (statMap.containsKey(r.getCategory())) { | ||||
|                 r.setCount(statMap.get(r.getCategory())); | ||||
|                 r.setCount(statMap.get(r.getCategory()).getCount()) | ||||
|                     .setCycle(statMap.get(r.getCategory()).getCycle()); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
|     <select id="selectCustomerCountGroupbyDate" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO"> | ||||
|         SELECT | ||||
|             count(*) AS count, | ||||
|             DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category | ||||
|             DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) AS category, | ||||
|             count(*) AS count | ||||
|         FROM | ||||
|             crm_customer | ||||
|         WHERE | ||||
| @@ -18,15 +18,14 @@ | ||||
|                 </foreach> | ||||
|           AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|                 #{times[1],javaType=java.time.LocalDateTime} | ||||
|         GROUP BY | ||||
|             DATE_FORMAT( create_time, #{sqlDateFormat,javaType=java.lang.String} ) | ||||
|         GROUP BY category | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectDealCustomerCountGroupbyDate" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO"> | ||||
|         SELECT | ||||
|             count( DISTINCT a.id ) AS count, | ||||
|             DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) AS category | ||||
|             DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) AS category, | ||||
|             count( DISTINCT a.id ) AS count | ||||
|         FROM | ||||
|             crm_customer AS a | ||||
|                 LEFT JOIN crm_contract AS b ON b.customer_id = a.id | ||||
| @@ -39,8 +38,7 @@ | ||||
|                 </foreach> | ||||
|           AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|                 #{times[1],javaType=java.time.LocalDateTime} | ||||
|         GROUP BY | ||||
|             DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) | ||||
|         GROUP BY category | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectRecordCountGroupbyDate" | ||||
| @@ -58,8 +56,7 @@ | ||||
|           AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|                 #{times[1],javaType=java.time.LocalDateTime} | ||||
|           AND biz_type = #{bizType,javaType=java.lang.Integer} | ||||
|         GROUP BY | ||||
|             DATE_FORMAT (create_time, #{sqlDateFormat,javaType=java.lang.String} ) | ||||
|         GROUP BY category | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectDistinctRecordCountGroupbyDate" | ||||
| @@ -77,7 +74,43 @@ | ||||
|           AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|                 #{times[1],javaType=java.time.LocalDateTime} | ||||
|           AND biz_type = #{bizType,javaType=java.lang.Integer} | ||||
|         GROUP BY DATE_FORMAT (create_time, #{sqlDateFormat,javaType=java.lang.String} ) | ||||
|         GROUP BY category | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectRecordCountGroupbyType" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO"> | ||||
|         SELECT | ||||
|             type AS category, | ||||
|             count(*) AS count | ||||
|           FROM crm_follow_up_record | ||||
|          WHERE | ||||
|             creator IN | ||||
|                 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|                     #{userId} | ||||
|                 </foreach> | ||||
|           AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|                 #{times[1],javaType=java.time.LocalDateTime} | ||||
|           AND biz_type = #{bizType,javaType=java.lang.Integer} | ||||
|         GROUP BY category | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectCustomerCycleGroupbyDate" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerCountVO"> | ||||
|         SELECT | ||||
|             DATE_FORMAT( b.order_date, #{sqlDateFormat,javaType=java.lang.String} ) AS category, | ||||
|             IFNULL( TRUNCATE ( AVG( TIMESTAMPDIFF( DAY, a.create_time, b.order_date )), 1 ), 0 ) AS cycle | ||||
|           FROM crm_customer AS a | ||||
|             LEFT JOIN crm_contract AS b ON b.customer_id = a.id | ||||
|          WHERE | ||||
|             a.deleted = 0 AND b.deleted = 0 | ||||
|            AND b.audit_status = 20 | ||||
|            AND a.owner_user_id IN | ||||
|                 <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|                     #{userId} | ||||
|                 </foreach> | ||||
|            AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|                 #{times[1],javaType=java.time.LocalDateTime} | ||||
|          GROUP BY category | ||||
|     </select> | ||||
|  | ||||
| </mapper> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 dhb52
					dhb52