浏览代码

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
YunaiV 1 年之前
父节点
当前提交
3b379d8cc0
共有 13 个文件被更改,包括 412 次插入10 次删除
  1. 32 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java
  2. 27 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java
  3. 27 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java
  4. 27 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java
  5. 27 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java
  6. 12 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java
  7. 36 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java
  8. 107 0
      yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java
  9. 85 0
      yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml
  10. 5 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  11. 5 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
  12. 17 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java
  13. 5 5
      yudao-server/pom.xml

+ 32 - 0
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;
 
 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));
+    }
+
 }

+ 27 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerAreaRespVO.java

@@ -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;
+
+}

+ 27 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerIndustryRespVO.java

@@ -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;
+
+}

+ 27 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerLevelRespVO.java

@@ -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;
+
+}

+ 27 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/customer/analyze/CrmStatisticCustomerSourceRespVO.java

@@ -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;
+
+}

+ 12 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java

@@ -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);
+
 }

+ 36 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerService.java

@@ -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);
+
 }

+ 107 - 0
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;
 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;
+    }
+
     /**
      * 拼接用户信息(昵称)
      *

+ 85 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsCustomerMapper.xml

@@ -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>

+ 5 - 3
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 {
             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);
 

+ 5 - 2
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 {
             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;

+ 17 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dict/DictDataApi.java

@@ -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();
+    }
+
     /**
      * 解析获得指定的字典数据,从缓存中
      *

+ 5 - 5
yudao-server/pom.xml

@@ -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>