Commit 3b379d8cc0097e34c10a2dda6afb66adf8830b85
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
Showing
13 changed files
with
412 additions
and
10 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java
| @@ -2,6 +2,10 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; | @@ -2,6 +2,10 @@ 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; | ||
| 6 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO; | ||
| 8 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||
| 5 | import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; | 9 | import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsCustomerService; |
| 6 | import io.swagger.v3.oas.annotations.Operation; | 10 | import io.swagger.v3.oas.annotations.Operation; |
| 7 | import io.swagger.v3.oas.annotations.tags.Tag; | 11 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -86,4 +90,32 @@ public class CrmStatisticsCustomerController { | @@ -86,4 +90,32 @@ public class CrmStatisticsCustomerController { | ||
| 86 | 90 | ||
| 87 | // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; | 91 | // TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析; |
| 88 | 92 | ||
| 93 | + @GetMapping("/get-customer-industry-summary") | ||
| 94 | + @Operation(summary = "获取客户行业统计数据") | ||
| 95 | + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||
| 96 | + public CommonResult<List<CrmStatisticCustomerIndustryRespVO>> getCustomerIndustry(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||
| 97 | + return success(customerService.getCustomerIndustry(reqVO)); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @GetMapping("/get-customer-source-summary") | ||
| 101 | + @Operation(summary = "获取客户来源统计数据") | ||
| 102 | + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||
| 103 | + public CommonResult<List<CrmStatisticCustomerSourceRespVO>> getCustomerSource(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||
| 104 | + return success(customerService.getCustomerSource(reqVO)); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @GetMapping("/get-customer-level-summary") | ||
| 108 | + @Operation(summary = "获取客户级别统计数据") | ||
| 109 | + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||
| 110 | + public CommonResult<List<CrmStatisticCustomerLevelRespVO>> getCustomerLevel(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||
| 111 | + return success(customerService.getCustomerLevel(reqVO)); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + @GetMapping("/get-customer-area-summary") | ||
| 115 | + @Operation(summary = "获取客户地区统计数据") | ||
| 116 | + @PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')") | ||
| 117 | + public CommonResult<List<CrmStatisticCustomerAreaRespVO>> getCustomerArea(@Valid CrmStatisticsCustomerReqVO reqVO) { | ||
| 118 | + return success(customerService.getCustomerArea(reqVO)); | ||
| 119 | + } | ||
| 120 | + | ||
| 89 | } | 121 | } |
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/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.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.CrmStatisticCustomerLevelRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||
| 4 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 5 | 9 | ||
| 6 | import java.util.List; | 10 | import java.util.List; |
| @@ -41,4 +45,12 @@ public interface CrmStatisticsCustomerMapper { | @@ -41,4 +45,12 @@ public interface CrmStatisticsCustomerMapper { | ||
| 41 | 45 | ||
| 42 | List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); | 46 | List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO); |
| 43 | 47 | ||
| 48 | + List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO); | ||
| 49 | + | ||
| 50 | + List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO); | ||
| 51 | + | ||
| 52 | + List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO); | ||
| 53 | + | ||
| 54 | + List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO); | ||
| 55 | + | ||
| 44 | } | 56 | } |
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; | ||
| 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; | ||
| 4 | 8 | ||
| 5 | import java.util.List; | 9 | import java.util.List; |
| 6 | 10 | ||
| @@ -77,4 +81,36 @@ public interface CrmStatisticsCustomerService { | @@ -77,4 +81,36 @@ public interface CrmStatisticsCustomerService { | ||
| 77 | */ | 81 | */ |
| 78 | List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); | 82 | List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO); |
| 79 | 83 | ||
| 84 | + /** | ||
| 85 | + * 获取客户行业统计数据 | ||
| 86 | + * | ||
| 87 | + * @param reqVO 请求参数 | ||
| 88 | + * @return 统计数据 | ||
| 89 | + */ | ||
| 90 | + List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO); | ||
| 91 | + | ||
| 92 | + /** | ||
| 93 | + * 获取客户来源统计数据 | ||
| 94 | + * | ||
| 95 | + * @param reqVO 请求参数 | ||
| 96 | + * @return 统计数据 | ||
| 97 | + */ | ||
| 98 | + List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO); | ||
| 99 | + | ||
| 100 | + /** | ||
| 101 | + * 获取客户级别统计数据 | ||
| 102 | + * | ||
| 103 | + * @param reqVO 请求参数 | ||
| 104 | + * @return 统计数据 | ||
| 105 | + */ | ||
| 106 | + List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO); | ||
| 107 | + | ||
| 108 | + /** | ||
| 109 | + * 获取客户地区统计数据 | ||
| 110 | + * | ||
| 111 | + * @param reqVO 请求参数 | ||
| 112 | + * @return 统计数据 | ||
| 113 | + */ | ||
| 114 | + List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO); | ||
| 115 | + | ||
| 80 | } | 116 | } |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
| @@ -4,7 +4,14 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,7 +4,14 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.util.ObjUtil; | 4 | import cn.hutool.core.util.ObjUtil; |
| 5 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | 5 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 6 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 6 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 7 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 8 | +import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; | ||
| 9 | +import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | ||
| 7 | import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; | 10 | import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; |
| 11 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO; | ||
| 12 | +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.CrmStatisticCustomerLevelRespVO; | ||
| 14 | +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO; | ||
| 8 | import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; | 15 | import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; |
| 9 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; | 16 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| 10 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | 17 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| @@ -23,6 +30,8 @@ import java.util.stream.Stream; | @@ -23,6 +30,8 @@ import java.util.stream.Stream; | ||
| 23 | 30 | ||
| 24 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 31 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 25 | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | 32 | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; |
| 33 | +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||
| 34 | +import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*; | ||
| 26 | 35 | ||
| 27 | /** | 36 | /** |
| 28 | * CRM 客户分析 Service 实现类 | 37 | * CRM 客户分析 Service 实现类 |
| @@ -236,6 +245,104 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | @@ -236,6 +245,104 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe | ||
| 236 | return summaryList; | 245 | return summaryList; |
| 237 | } | 246 | } |
| 238 | 247 | ||
| 248 | + @Override | ||
| 249 | + public List<CrmStatisticCustomerIndustryRespVO> getCustomerIndustry(CrmStatisticsCustomerReqVO reqVO) { | ||
| 250 | + // 1. 获得用户编号数组 | ||
| 251 | + List<Long> userIds = getUserIds(reqVO); | ||
| 252 | + if (CollUtil.isEmpty(userIds)) { | ||
| 253 | + return Collections.emptyList(); | ||
| 254 | + } | ||
| 255 | + reqVO.setUserIds(userIds); | ||
| 256 | + // 2. 获取客户行业统计数据 | ||
| 257 | + List<CrmStatisticCustomerIndustryRespVO> industryRespVOList = customerMapper.selectCustomerIndustryListGroupbyIndustryId(reqVO); | ||
| 258 | + if (CollUtil.isEmpty(industryRespVOList)) { | ||
| 259 | + return Collections.emptyList(); | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + return convertList(industryRespVOList, item -> { | ||
| 263 | + if (ObjUtil.isNull(item.getIndustryId())) { | ||
| 264 | + return item; | ||
| 265 | + } | ||
| 266 | + item.setIndustryName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, item.getIndustryId())); | ||
| 267 | + return item; | ||
| 268 | + }); | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + @Override | ||
| 272 | + public List<CrmStatisticCustomerSourceRespVO> getCustomerSource(CrmStatisticsCustomerReqVO reqVO) { | ||
| 273 | + // 1. 获得用户编号数组 | ||
| 274 | + List<Long> userIds = getUserIds(reqVO); | ||
| 275 | + if (CollUtil.isEmpty(userIds)) { | ||
| 276 | + return Collections.emptyList(); | ||
| 277 | + } | ||
| 278 | + reqVO.setUserIds(userIds); | ||
| 279 | + // 2. 获取客户行业统计数据 | ||
| 280 | + List<CrmStatisticCustomerSourceRespVO> sourceRespVOList = customerMapper.selectCustomerSourceListGroupbySource(reqVO); | ||
| 281 | + if (CollUtil.isEmpty(sourceRespVOList)) { | ||
| 282 | + return Collections.emptyList(); | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + return convertList(sourceRespVOList, item -> { | ||
| 286 | + if (ObjUtil.isNull(item.getSource())) { | ||
| 287 | + return item; | ||
| 288 | + } | ||
| 289 | + item.setSourceName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_SOURCE, item.getSource())); | ||
| 290 | + return item; | ||
| 291 | + }); | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + @Override | ||
| 295 | + public List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO) { | ||
| 296 | + // 1. 获得用户编号数组 | ||
| 297 | + List<Long> userIds = getUserIds(reqVO); | ||
| 298 | + if (CollUtil.isEmpty(userIds)) { | ||
| 299 | + return Collections.emptyList(); | ||
| 300 | + } | ||
| 301 | + reqVO.setUserIds(userIds); | ||
| 302 | + // 2. 获取客户行业统计数据 | ||
| 303 | + List<CrmStatisticCustomerLevelRespVO> levelRespVOList = customerMapper.selectCustomerLevelListGroupbyLevel(reqVO); | ||
| 304 | + if (CollUtil.isEmpty(levelRespVOList)) { | ||
| 305 | + return Collections.emptyList(); | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + return convertList(levelRespVOList, item -> { | ||
| 309 | + if (ObjUtil.isNull(item.getLevel())) { | ||
| 310 | + return item; | ||
| 311 | + } | ||
| 312 | + item.setLevelName(dictDataApi.getDictDataLabel(CRM_CUSTOMER_LEVEL, item.getLevel())); | ||
| 313 | + return item; | ||
| 314 | + }); | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + @Override | ||
| 318 | + public List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO) { | ||
| 319 | + // 1. 获得用户编号数组 | ||
| 320 | + List<Long> userIds = getUserIds(reqVO); | ||
| 321 | + if (CollUtil.isEmpty(userIds)) { | ||
| 322 | + return Collections.emptyList(); | ||
| 323 | + } | ||
| 324 | + reqVO.setUserIds(userIds); | ||
| 325 | + // 2. 获取客户地区统计数据 | ||
| 326 | + List<CrmStatisticCustomerAreaRespVO> list = customerMapper.selectSummaryListByAreaId(reqVO); | ||
| 327 | + if (CollUtil.isEmpty(list)) { | ||
| 328 | + return Collections.emptyList(); | ||
| 329 | + } | ||
| 330 | + | ||
| 331 | + // 拼接数据 | ||
| 332 | + List<Area> areaList = AreaUtils.getByType(AreaTypeEnum.PROVINCE, area -> area); | ||
| 333 | + areaList.add(new Area().setId(null).setName("未知")); | ||
| 334 | + Map<Integer, Area> areaMap = convertMap(areaList, Area::getId); | ||
| 335 | + List<CrmStatisticCustomerAreaRespVO> customerAreaRespVOList = convertList(list, item -> { | ||
| 336 | + Integer parentId = AreaUtils.getParentIdByType(item.getAreaId(), AreaTypeEnum.PROVINCE); | ||
| 337 | + if (parentId == null) { | ||
| 338 | + return item; | ||
| 339 | + } | ||
| 340 | + findAndThen(areaMap, parentId, area -> item.setAreaId(parentId).setAreaName(area.getName())); | ||
| 341 | + return item; | ||
| 342 | + }); | ||
| 343 | + return customerAreaRespVOList; | ||
| 344 | + } | ||
| 345 | + | ||
| 239 | /** | 346 | /** |
| 240 | * 拼接用户信息(昵称) | 347 | * 拼接用户信息(昵称) |
| 241 | * | 348 | * |
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
| @@ -229,4 +229,89 @@ | @@ -229,4 +229,89 @@ | ||
| 229 | GROUP BY customer.owner_user_id | 229 | GROUP BY customer.owner_user_id |
| 230 | </select> | 230 | </select> |
| 231 | 231 | ||
| 232 | + <select id="selectCustomerIndustryListGroupbyIndustryId" | ||
| 233 | + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerIndustryRespVO"> | ||
| 234 | + SELECT | ||
| 235 | + industry_id, | ||
| 236 | + COUNT(*) AS customerCount, | ||
| 237 | + SUM(deal_status) AS dealCount, | ||
| 238 | + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS industryPortion, | ||
| 239 | + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||
| 240 | + FROM | ||
| 241 | + crm_customer | ||
| 242 | + WHERE | ||
| 243 | + deleted = 0 AND industry_id IS NOT NULL | ||
| 244 | + AND owner_user_id IN | ||
| 245 | + <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||
| 246 | + #{userId} | ||
| 247 | + </foreach> | ||
| 248 | + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||
| 249 | + #{times[1],javaType=java.time.LocalDateTime} | ||
| 250 | + GROUP BY | ||
| 251 | + industry_id; | ||
| 252 | + </select> | ||
| 253 | + <select id="selectCustomerSourceListGroupbySource" | ||
| 254 | + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerSourceRespVO"> | ||
| 255 | + SELECT | ||
| 256 | + source, | ||
| 257 | + COUNT(*) AS customerCount, | ||
| 258 | + SUM(deal_status) AS dealCount, | ||
| 259 | + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS sourcePortion, | ||
| 260 | + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||
| 261 | + FROM | ||
| 262 | + crm_customer | ||
| 263 | + WHERE | ||
| 264 | + deleted = 0 AND source IS NOT NULL | ||
| 265 | + AND owner_user_id IN | ||
| 266 | + <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||
| 267 | + #{userId} | ||
| 268 | + </foreach> | ||
| 269 | + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||
| 270 | + #{times[1],javaType=java.time.LocalDateTime} | ||
| 271 | + GROUP BY | ||
| 272 | + source; | ||
| 273 | + </select> | ||
| 274 | + <select id="selectCustomerLevelListGroupbyLevel" | ||
| 275 | + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerLevelRespVO"> | ||
| 276 | + SELECT | ||
| 277 | + level, | ||
| 278 | + COUNT(*) AS customerCount, | ||
| 279 | + SUM(deal_status) AS dealCount, | ||
| 280 | + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS levelPortion, | ||
| 281 | + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||
| 282 | + FROM | ||
| 283 | + crm_customer | ||
| 284 | + WHERE | ||
| 285 | + deleted = 0 AND level IS NOT NULL | ||
| 286 | + AND owner_user_id IN | ||
| 287 | + <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||
| 288 | + #{userId} | ||
| 289 | + </foreach> | ||
| 290 | + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||
| 291 | + #{times[1],javaType=java.time.LocalDateTime} | ||
| 292 | + GROUP BY | ||
| 293 | + level; | ||
| 294 | + </select> | ||
| 295 | + <select id="selectSummaryListByAreaId" | ||
| 296 | + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.analyze.CrmStatisticCustomerAreaRespVO"> | ||
| 297 | + SELECT | ||
| 298 | + area_id, | ||
| 299 | + COUNT(*) AS customerCount, | ||
| 300 | + SUM(deal_status) AS dealCount, | ||
| 301 | + ROUND(COUNT(*) / (SELECT COUNT(*) FROM crm_customer WHERE deleted = 0) * 100, 2) AS areaPortion, | ||
| 302 | + ROUND(SUM(deal_status) / NULLIF(COUNT(*), 0) * 100, 2) AS dealPortion | ||
| 303 | + FROM | ||
| 304 | + crm_customer | ||
| 305 | + WHERE | ||
| 306 | + deleted = 0 AND area_id IS NOT NULL | ||
| 307 | + AND owner_user_id IN | ||
| 308 | + <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||
| 309 | + #{userId} | ||
| 310 | + </foreach> | ||
| 311 | + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||
| 312 | + #{times[1],javaType=java.time.LocalDateTime} | ||
| 313 | + GROUP BY | ||
| 314 | + area_id; | ||
| 315 | + </select> | ||
| 316 | + | ||
| 232 | </mapper> | 317 | </mapper> |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
| @@ -624,7 +624,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -624,7 +624,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 624 | throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY); | 624 | throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY); |
| 625 | } | 625 | } |
| 626 | // 1.3 支付价格不能为 0 | 626 | // 1.3 支付价格不能为 0 |
| 627 | - int newPayPrice = order.getPayPrice() + order.getAdjustPrice(); | 627 | + int newPayPrice = order.getPayPrice() + reqVO.getAdjustPrice(); |
| 628 | if (newPayPrice <= 0) { | 628 | if (newPayPrice <= 0) { |
| 629 | throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR); | 629 | throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR); |
| 630 | } | 630 | } |
| @@ -635,12 +635,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | @@ -635,12 +635,14 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { | ||
| 635 | 635 | ||
| 636 | // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊 | 636 | // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊 |
| 637 | List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); | 637 | List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); |
| 638 | - List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, newPayPrice); | 638 | + List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, reqVO.getAdjustPrice()); |
| 639 | List<TradeOrderItemDO> updateItems = new ArrayList<>(); | 639 | List<TradeOrderItemDO> updateItems = new ArrayList<>(); |
| 640 | for (int i = 0; i < orderOrderItems.size(); i++) { | 640 | for (int i = 0; i < orderOrderItems.size(); i++) { |
| 641 | TradeOrderItemDO item = orderOrderItems.get(i); | 641 | TradeOrderItemDO item = orderOrderItems.get(i); |
| 642 | + // TODO puhui999: 已有分摊记录的情况下价格是否会不对,也就是说之前订单项 1 分摊了 10 块这次是 -100 | ||
| 643 | + // 那么 setPayPrice 是否改为 (item.getPayPrice()-item.getAdjustPrice()) + dividePrices.get(i) 先减掉原来的价格再加上调价。经过验证可行,修改后订单价格增减都能正确分摊 | ||
| 642 | updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(dividePrices.get(i)) | 644 | updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(dividePrices.get(i)) |
| 643 | - .setPayPrice(item.getPayPrice() + dividePrices.get(i))); | 645 | + .setPayPrice((item.getPayPrice() - item.getAdjustPrice()) + dividePrices.get(i))); |
| 644 | } | 646 | } |
| 645 | tradeOrderItemMapper.updateBatch(updateItems); | 647 | tradeOrderItemMapper.updateBatch(updateItems); |
| 646 | 648 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
| @@ -254,12 +254,15 @@ public class TradePriceCalculatorHelper { | @@ -254,12 +254,15 @@ public class TradePriceCalculatorHelper { | ||
| 254 | TradeOrderItemDO orderItem = items.get(i); | 254 | TradeOrderItemDO orderItem = items.get(i); |
| 255 | int partPrice; | 255 | int partPrice; |
| 256 | if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 | 256 | if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减 |
| 257 | - partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); | 257 | + // partPrice = (int) (price * (1.0D * orderItem.getPayPrice() / total)); |
| 258 | + // pr fix: 改为了使用订单原价来计算比例 | ||
| 259 | + partPrice = (int) (price * (1.0D * orderItem.getPrice() / total)); | ||
| 258 | remainPrice -= partPrice; | 260 | remainPrice -= partPrice; |
| 259 | } else { | 261 | } else { |
| 260 | partPrice = remainPrice; | 262 | partPrice = remainPrice; |
| 261 | } | 263 | } |
| 262 | - Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); | 264 | + // TODO puhui999: 如果是减价的情况这里过不了 |
| 265 | + // Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0"); | ||
| 263 | prices.add(partPrice); | 266 | prices.add(partPrice); |
| 264 | } | 267 | } |
| 265 | return prices; | 268 | return prices; |
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> |