Browse Source

CRM: 新增客户行业、来源、级别统计数据统计

puhui999 1 year ago
parent
commit
ce013a2562

+ 24 - 0
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsCustomerController.java

@@ -2,6 +2,9 @@ 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.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;
@@ -82,4 +85,25 @@ public class CrmStatisticsCustomerController {
         return success(customerService.getCustomerDealCycleByUser(reqVO));
     }
 
+    @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));
+    }
+
 }

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

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

@@ -1,6 +1,9 @@
 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.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;
@@ -42,4 +45,10 @@ public interface CrmStatisticsCustomerMapper {
 
     List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
 
+    List<CrmStatisticCustomerIndustryRespVO> selectCustomerIndustryListGroupbyIndustryId(CrmStatisticsCustomerReqVO reqVO);
+
+    List<CrmStatisticCustomerSourceRespVO> selectCustomerSourceListGroupbySource(CrmStatisticsCustomerReqVO reqVO);
+
+    List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);
+
 }

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

@@ -1,6 +1,9 @@
 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.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 +80,28 @@ 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);
+
 }

+ 118 - 46
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java

@@ -6,6 +6,9 @@ import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*;
+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.crm.enums.common.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
@@ -78,15 +81,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         // TODO @dhb52:这个是不是要 add 到 respVoList 里?或者还可以 convertList(times, time -> new CrmStatisticsCustomerDealCycleByDateRespVO()...)
         List<CrmStatisticsCustomerSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());
         final Map<String, Integer> customerCreateCountMap = convertMap(customerCreateCount,
-            CrmStatisticsCustomerSummaryByDateRespVO::getTime,
-            CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount);
+                CrmStatisticsCustomerSummaryByDateRespVO::getTime,
+                CrmStatisticsCustomerSummaryByDateRespVO::getCustomerCreateCount);
         final Map<String, Integer> customerDealCountMap = convertMap(customerDealCount,
-            CrmStatisticsCustomerSummaryByDateRespVO::getTime,
-            CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount);
+                CrmStatisticsCustomerSummaryByDateRespVO::getTime,
+                CrmStatisticsCustomerSummaryByDateRespVO::getCustomerDealCount);
         times.forEach(time -> respVoList.add(
-            new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time)
-                .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
-                .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))
+                new CrmStatisticsCustomerSummaryByDateRespVO().setTime(time)
+                        .setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
+                        .setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))
         ));
         return respVoList;
     }
@@ -108,25 +111,25 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
 
         // 3. 合并统计数据
         final Map<Long, Integer> customerCreateCountMap = convertMap(customerCreateCount,
-            CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount);
+                CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsCustomerSummaryByUserRespVO::getCustomerCreateCount);
         final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
-            CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
+                CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
         final Map<Long, BigDecimal> contractPriceMap = convertMap(contractPrice,
-            CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice);
+                CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsCustomerSummaryByUserRespVO::getContractPrice);
         final Map<Long, BigDecimal> receivablePriceMap = convertMap(receivablePrice,
-            CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice);
+                CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsCustomerSummaryByUserRespVO::getReceivablePrice);
         List<CrmStatisticsCustomerSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());
         userIds.forEach(userId -> {
             final CrmStatisticsCustomerSummaryByUserRespVO vo = new CrmStatisticsCustomerSummaryByUserRespVO();
             vo.setOwnerUserId(userId);
             vo.setCustomerCreateCount(customerCreateCountMap.getOrDefault(userId, 0))
-                .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))
-                .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))
-                .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO));
+                    .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0))
+                    .setContractPrice(contractPriceMap.getOrDefault(userId, BigDecimal.ZERO))
+                    .setReceivablePrice(receivablePriceMap.getOrDefault(userId, BigDecimal.ZERO));
             respVoList.add(vo);
         });
 
@@ -156,15 +159,15 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         // 4. 合并统计数据
         List<CrmStatisticsFollowupSummaryByDateRespVO> respVoList = new ArrayList<>(times.size());
         final Map<String, Integer> followupRecordCountMap = convertMap(followupRecordCount,
-            CrmStatisticsFollowupSummaryByDateRespVO::getTime,
-            CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount);
+                CrmStatisticsFollowupSummaryByDateRespVO::getTime,
+                CrmStatisticsFollowupSummaryByDateRespVO::getFollowupRecordCount);
         final Map<String, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
-            CrmStatisticsFollowupSummaryByDateRespVO::getTime,
-            CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount);
+                CrmStatisticsFollowupSummaryByDateRespVO::getTime,
+                CrmStatisticsFollowupSummaryByDateRespVO::getFollowupCustomerCount);
         times.forEach(time -> respVoList.add(
-            new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)
-                .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))
-                .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0))
+                new CrmStatisticsFollowupSummaryByDateRespVO().setTime(time)
+                        .setFollowupRecordCount(followupRecordCountMap.getOrDefault(time, 0))
+                        .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(time, 0))
         ));
 
         return respVoList;
@@ -186,16 +189,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
 
         // 3. 合并统计数据
         final Map<Long, Integer> followupRecordCountMap = convertMap(followupRecordCount,
-            CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount);
+                CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsFollowupSummaryByUserRespVO::getFollowupRecordCount);
         final Map<Long, Integer> followupCustomerCountMap = convertMap(followupCustomerCount,
-            CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount);
+                CrmStatisticsFollowupSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsFollowupSummaryByUserRespVO::getFollowupCustomerCount);
         List<CrmStatisticsFollowupSummaryByUserRespVO> respVoList = new ArrayList<>(userIds.size());
         userIds.forEach(userId -> {
             final CrmStatisticsFollowupSummaryByUserRespVO vo = new CrmStatisticsFollowupSummaryByUserRespVO()
-                .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))
-                .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0));
+                    .setFollowupRecordCount(followupRecordCountMap.getOrDefault(userId, 0))
+                    .setFollowupCustomerCount(followupCustomerCountMap.getOrDefault(userId, 0));
             vo.setOwnerUserId(userId);
             respVoList.add(vo);
         });
@@ -221,7 +224,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         // 3. 获取字典数据
         List<DictDataRespDTO> followUpTypes = dictDataApi.getDictDataList(CRM_FOLLOW_UP_TYPE);
         final Map<String, String> followUpTypeMap = convertMap(followUpTypes,
-            DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
+                DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
         respVoList.forEach(vo -> {
             vo.setFollowupType(followUpTypeMap.get(vo.getFollowupType()));
         });
@@ -244,19 +247,19 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         // 3. 设置 创建人、负责人、行业、来源
         // 获取客户所属行业
         Map<String, String> industryMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_INDUSTRY),
-            DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
+                DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
         // 获取客户来源
         Map<String, String> sourceMap = convertMap(dictDataApi.getDictDataList(CRM_CUSTOMER_SOURCE),
-            DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
+                DictDataRespDTO::getValue, DictDataRespDTO::getLabel);
         // 获取创建人、负责人列表
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(respVoList,
-            vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
+                vo -> Stream.of(NumberUtils.parseLong(vo.getCreatorUserId()), vo.getOwnerUserId())));
 
         respVoList.forEach(vo -> {
             MapUtils.findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
             MapUtils.findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
             MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()),
-                user -> vo.setCreatorUserName(user.getNickname()));
+                    user -> vo.setCreatorUserName(user.getNickname()));
             MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
         });
 
@@ -283,11 +286,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         // 4. 合并统计数据
         List<CrmStatisticsCustomerDealCycleByDateRespVO> respVoList = new ArrayList<>(times.size());
         final Map<String, Double> customerDealCycleMap = convertMap(customerDealCycle,
-            CrmStatisticsCustomerDealCycleByDateRespVO::getTime,
-            CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle);
+                CrmStatisticsCustomerDealCycleByDateRespVO::getTime,
+                CrmStatisticsCustomerDealCycleByDateRespVO::getCustomerDealCycle);
         times.forEach(time -> respVoList.add(
-            new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
-                .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
+                new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
+                        .setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
         ));
         return respVoList;
     }
@@ -308,16 +311,16 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
 
         // 3. 合并统计数据
         final Map<Long, Double> customerDealCycleMap = convertMap(customerDealCycle,
-            CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,
-            CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle);
+                CrmStatisticsCustomerDealCycleByUserRespVO::getOwnerUserId,
+                CrmStatisticsCustomerDealCycleByUserRespVO::getCustomerDealCycle);
         final Map<Long, Integer> customerDealCountMap = convertMap(customerDealCount,
-            CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
-            CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
+                CrmStatisticsCustomerSummaryByUserRespVO::getOwnerUserId,
+                CrmStatisticsCustomerSummaryByUserRespVO::getCustomerDealCount);
         List<CrmStatisticsCustomerDealCycleByUserRespVO> respVoList = new ArrayList<>(userIds.size());
         userIds.forEach(userId -> {
             final CrmStatisticsCustomerDealCycleByUserRespVO vo = new CrmStatisticsCustomerDealCycleByUserRespVO()
-                .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))
-                .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0));
+                    .setCustomerDealCycle(customerDealCycleMap.getOrDefault(userId, 0.0))
+                    .setCustomerDealCount(customerDealCountMap.getOrDefault(userId, 0));
             vo.setOwnerUserId(userId);
             respVoList.add(vo);
         });
@@ -328,6 +331,75 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         return respVoList;
     }
 
+    @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;
+        });
+    }
+
     /**
      * 拼接用户信息(昵称)
      *

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

@@ -249,4 +249,68 @@
         GROUP BY a.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>
+
 </mapper>

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