mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-30 09:48:43 +08:00 
			
		
		
		
	Merge branch 'develop' of https://gitee.com/puhui999/ruoyi-vue-pro into develop
# Conflicts: # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
This commit is contained in:
		| @@ -2,6 +2,10 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||||
| import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; | ||||
| import io.swagger.v3.oas.annotations.Operation; | ||||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||||
| @@ -86,4 +90,32 @@ public class CrmStatisticsCustomerController { | ||||
|  | ||||
|     // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; | ||||
|  | ||||
|     @GetMapping("/get-customer-industry-summary") | ||||
|     @Operation(summary = "获取客户行业统计数据") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerIndustry(reqVO)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-customer-source-summary") | ||||
|     @Operation(summary = "获取客户来源统计数据") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerSource(reqVO)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-customer-level-summary") | ||||
|     @Operation(summary = "获取客户级别统计数据") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerLevel(reqVO)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-customer-area-summary") | ||||
|     @Operation(summary = "获取客户地区统计数据") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||||
|     public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerArea(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||||
|         return success(customerService.getCustomerArea(reqVO)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,27 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 客户省份分析 VO") | ||||
| @Data | ||||
| public class CrmStatisticCustomerAreaRespVO { | ||||
|  | ||||
|     @Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer areaId; | ||||
|     @Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省") | ||||
|     private String areaName; | ||||
|  | ||||
|     @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer customerCount; | ||||
|  | ||||
|     @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer dealCount; | ||||
|  | ||||
|     @Schema(description = "省份占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double areaPortion; | ||||
|  | ||||
|     @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double dealPortion; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 客户行业分析 VO") | ||||
| @Data | ||||
| public class CrmStatisticCustomerIndustryRespVO { | ||||
|  | ||||
|     @Schema(description = "客户行业ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private Integer industryId; | ||||
|     @Schema(description = "客户行业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private String industryName; | ||||
|  | ||||
|     @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer customerCount; | ||||
|  | ||||
|     @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer dealCount; | ||||
|  | ||||
|     @Schema(description = "行业占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double industryPortion; | ||||
|  | ||||
|     @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double dealPortion; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 客户级别分析 VO") | ||||
| @Data | ||||
| public class CrmStatisticCustomerLevelRespVO { | ||||
|  | ||||
|     @Schema(description = "客户级别ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private Integer level; | ||||
|     @Schema(description = "客户级别名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private String levelName; | ||||
|  | ||||
|     @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer customerCount; | ||||
|  | ||||
|     @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer dealCount; | ||||
|  | ||||
|     @Schema(description = "级别占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double levelPortion; | ||||
|  | ||||
|     @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double dealPortion; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 客户来源分析 VO") | ||||
| @Data | ||||
| public class CrmStatisticCustomerSourceRespVO { | ||||
|  | ||||
|     @Schema(description = "客户来源ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private Integer source; | ||||
|     @Schema(description = "客户来源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||
|     private String sourceName; | ||||
|  | ||||
|     @Schema(description = "客户个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer customerCount; | ||||
|  | ||||
|     @Schema(description = "成交个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer dealCount; | ||||
|  | ||||
|     @Schema(description = "来源占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double sourcePortion; | ||||
|  | ||||
|     @Schema(description = "成交占比(%)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Double dealPortion; | ||||
|  | ||||
| } | ||||
| @@ -1,6 +1,10 @@ | ||||
| package cn.iocoder.yudao.module.crm.dal.mysql.statistics; | ||||
|  | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -41,4 +45,12 @@ public interface CrmStatisticsCustomerMapper { | ||||
|  | ||||
|     List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,10 @@ | ||||
| package cn.iocoder.yudao.module.crm.service.statistics; | ||||
|  | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @@ -77,4 +81,36 @@ public interface CrmStatisticsCustomerService { | ||||
|      */ | ||||
|     List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取客户行业统计数据 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取客户来源统计数据 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取客户级别统计数据 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取客户地区统计数据 | ||||
|      * | ||||
|      * @param reqVO 请求参数 | ||||
|      * @return 统计数据 | ||||
|      */ | ||||
|     List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,14 @@ 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.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||||
| import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; | ||||
| import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||||
| import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||||
| @@ -23,6 +30,8 @@ import java.util.stream.Stream; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||||
| import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; | ||||
|  | ||||
| /** | ||||
|  * CRM 客户分析 Service 实现类 | ||||
| @@ -236,6 +245,104 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||||
|         return summaryList; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         reqVO.setUserIds(userIds); | ||||
|         // 2. 获取客户行业统计数据 | ||||
|         List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = customerMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); | ||||
|         if (CollUtil.isEmpty(industryRespVOList)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         return convertList(industryRespVOList, item -> { | ||||
|             if (ObjUtil.isNull(item.getIndustryId())) { | ||||
|                 return item; | ||||
|             } | ||||
|             item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId())); | ||||
|             return item; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         reqVO.setUserIds(userIds); | ||||
|         // 2. 获取客户行业统计数据 | ||||
|         List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = customerMapper.selectCustomerSourceListGroupbySource(reqVO); | ||||
|         if (CollUtil.isEmpty(sourceRespVOList)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         return convertList(sourceRespVOList, item -> { | ||||
|             if (ObjUtil.isNull(item.getSource())) { | ||||
|                 return item; | ||||
|             } | ||||
|             item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource())); | ||||
|             return item; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         reqVO.setUserIds(userIds); | ||||
|         // 2. 获取客户行业统计数据 | ||||
|         List<CrmStatisticCustomerLevelRespVO> levelRespVOList = customerMapper.selectCustomerLevelListGroupbyLevel(reqVO); | ||||
|         if (CollUtil.isEmpty(levelRespVOList)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         return convertList(levelRespVOList, item -> { | ||||
|             if (ObjUtil.isNull(item.getLevel())) { | ||||
|                 return item; | ||||
|             } | ||||
|             item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel())); | ||||
|             return item; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         reqVO.setUserIds(userIds); | ||||
|         // 2. 获取客户地区统计数据 | ||||
|         List<CrmStatisticCustomerAreaRespVO> list = customerMapper.selectSummaryListByAreaId(reqVO); | ||||
|         if (CollUtil.isEmpty(list)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         // 拼接数据 | ||||
|         List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); | ||||
|         areaList.add(new Area().setId(null).setName("未知")); | ||||
|         Map<Integer, Area> areaMap = convertMap(areaList, Area::getId); | ||||
|         List<CrmStatisticCustomerAreaRespVO> customerAreaRespVOList = convertList(list, item -> { | ||||
|             Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); | ||||
|             if (parentId == null) { | ||||
|                 return item; | ||||
|             } | ||||
|             findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); | ||||
|             return item; | ||||
|         }); | ||||
|         return customerAreaRespVOList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 拼接用户信息(昵称) | ||||
|      * | ||||
|   | ||||
| @@ -229,4 +229,89 @@ | ||||
|         GROUP BY customer.owner_user_id | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectCustomerIndustryListGroupbyIndustryId" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO"> | ||||
|         SELECT | ||||
|             industry_id, | ||||
|             COUNT(*) AS customerCount, | ||||
|             SUM(deal_status) AS dealCount, | ||||
|             ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS industryPortion, | ||||
|             ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||||
|         FROM | ||||
|             crm_customer | ||||
|         WHERE | ||||
|             deleted = 0 AND industry_id IS NOT NULL | ||||
|         AND owner_user_id 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} | ||||
|         GROUP BY | ||||
|             industry_id; | ||||
|     </select> | ||||
|     <select id="selectCustomerSourceListGroupbySource" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO"> | ||||
|         SELECT | ||||
|             source, | ||||
|             COUNT(*) AS customerCount, | ||||
|             SUM(deal_status) AS dealCount, | ||||
|             ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS sourcePortion, | ||||
|             ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||||
|         FROM | ||||
|             crm_customer | ||||
|         WHERE | ||||
|             deleted = 0 AND source IS NOT NULL | ||||
|         AND owner_user_id 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} | ||||
|         GROUP BY | ||||
|             source; | ||||
|     </select> | ||||
|     <select id="selectCustomerLevelListGroupbyLevel" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO"> | ||||
|         SELECT | ||||
|             level, | ||||
|             COUNT(*) AS customerCount, | ||||
|             SUM(deal_status) AS dealCount, | ||||
|             ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS levelPortion, | ||||
|             ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||||
|         FROM | ||||
|             crm_customer | ||||
|         WHERE | ||||
|             deleted = 0 AND level IS NOT NULL | ||||
|         AND owner_user_id 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} | ||||
|         GROUP BY | ||||
|             level; | ||||
|     </select> | ||||
|     <select id="selectSummaryListByAreaId" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO"> | ||||
|         SELECT | ||||
|             area_id, | ||||
|             COUNT(*) AS customerCount, | ||||
|             SUM(deal_status) AS dealCount, | ||||
|             ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS areaPortion, | ||||
|             ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||||
|         FROM | ||||
|             crm_customer | ||||
|         WHERE | ||||
|             deleted = 0 AND area_id IS NOT NULL | ||||
|         AND owner_user_id 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} | ||||
|         GROUP BY | ||||
|             area_id; | ||||
|     </select> | ||||
|  | ||||
| </mapper> | ||||
|   | ||||
| @@ -624,7 +624,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||||
|             throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY); | ||||
|         } | ||||
|         // 1.3 支付价格不能为 0 | ||||
|         int newPayPrice = order.getPayPrice() + order.getAdjustPrice(); | ||||
|         int newPayPrice = order.getPayPrice() + reqVO.getAdjustPrice(); | ||||
|         if (newPayPrice <= 0) { | ||||
|             throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR); | ||||
|         } | ||||
| @@ -635,12 +635,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||||
|  | ||||
|         // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊 | ||||
|         List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); | ||||
|         List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, newPayPrice); | ||||
|         List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, reqVO.getAdjustPrice()); | ||||
|         List<TradeOrderItemDO> updateItems = new ArrayList<>(); | ||||
|         for (int i = 0; i < orderOrderItems.size(); i++) { | ||||
|             TradeOrderItemDO item = orderOrderItems.get(i); | ||||
|             // TODO puhui999: 已有分摊记录的情况下价格是否会不对,也就是说之前订单项 1 分摊了 10 块这次是 -100 | ||||
|             // 那么 setPayPrice 是否改为 (item.getPayPrice()-item.getAdjustPrice()) + dividePrices.get(i) 先减掉原来的价格再加上调价。经过验证可行,修改后订单价格增减都能正确分摊 | ||||
|             updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(dividePrices.get(i)) | ||||
|                     .setPayPrice(item.getPayPrice() + dividePrices.get(i))); | ||||
|                     .setPayPrice((item.getPayPrice() - item.getAdjustPrice()) + dividePrices.get(i))); | ||||
|         } | ||||
|         tradeOrderItemMapper.updateBatch(updateItems); | ||||
|  | ||||
|   | ||||
| @@ -254,12 +254,15 @@ public class TradePriceCalculatorHelper { | ||||
|             TradeOrderItemDO orderItem = items.get(i); | ||||
|             int partPrice; | ||||
|             if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 | ||||
|                 partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); | ||||
|                 // partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); | ||||
|                 // pr fix:  改为了使用订单原价来计算比例 | ||||
|                 partPrice = (int) (price * (1.0D * orderItem.getPrice() / total)); | ||||
|                 remainPrice -= partPrice; | ||||
|             } else { | ||||
|                 partPrice = remainPrice; | ||||
|             } | ||||
|             Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); | ||||
|             // TODO puhui999: 如果是减价的情况这里过不了 | ||||
|             // Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); | ||||
|             prices.add(partPrice); | ||||
|         } | ||||
|         return prices; | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| package cn.iocoder.yudao.module.system.api.dict; | ||||
|  | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; | ||||
|  | ||||
| import java.util.Collection; | ||||
| @@ -33,6 +35,21 @@ public interface DictDataApi { | ||||
|      */ | ||||
|     DictDataRespDTO getDictData(String type, String value); | ||||
|  | ||||
|     /** | ||||
|      * 获得指定的字典标签,从缓存中 | ||||
|      * | ||||
|      * @param type  字典类型 | ||||
|      * @param value 字典数据值 | ||||
|      * @return 字典标签 | ||||
|      */ | ||||
|     default String getDictDataLabel(String type, Integer value) { | ||||
|         DictDataRespDTO dictData = getDictData(type, String.valueOf(value)); | ||||
|         if (ObjUtil.isNull(dictData)) { | ||||
|             return StrUtil.EMPTY; | ||||
|         } | ||||
|         return dictData.getLabel(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 解析获得指定的字典数据,从缓存中 | ||||
|      * | ||||
|   | ||||
| @@ -95,11 +95,11 @@ | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- ERP 相关模块。默认注释,保证编译速度 --> | ||||
|         <dependency> | ||||
|             <groupId>cn.iocoder.boot</groupId> | ||||
|             <artifactId>yudao-module-erp-biz</artifactId> | ||||
|             <version>${revision}</version> | ||||
|         </dependency> | ||||
| <!--        <dependency>--> | ||||
| <!--            <groupId>cn.iocoder.boot</groupId>--> | ||||
| <!--            <artifactId>yudao-module-erp-biz</artifactId>--> | ||||
| <!--            <version>${revision}</version>--> | ||||
| <!--        </dependency>--> | ||||
|  | ||||
|         <!-- spring boot 配置所需依赖 --> | ||||
|         <dependency> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV