瀏覽代碼

CRM: 新增客户区域数据统计

puhui999 1 年之前
父節點
當前提交
22191e81e3

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

@@ -2,6 +2,7 @@ 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;
@@ -106,4 +107,11 @@ public class CrmStatisticsCustomerController {
         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;
+
+}

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

@@ -1,6 +1,7 @@
 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;
@@ -51,4 +52,6 @@ public interface CrmStatisticsCustomerMapper {
 
     List<CrmStatisticCustomerLevelRespVO> selectCustomerLevelListGroupbyLevel(CrmStatisticsCustomerReqVO reqVO);
 
+    List<CrmStatisticCustomerAreaRespVO> selectSummaryListByAreaId(CrmStatisticsCustomerReqVO reqVO);
+
 }

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

@@ -1,6 +1,7 @@
 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;
@@ -104,4 +105,12 @@ public interface CrmStatisticsCustomerService {
      */
     List<CrmStatisticCustomerLevelRespVO> getCustomerLevel(CrmStatisticsCustomerReqVO reqVO);
 
+    /**
+     * 获取客户地区统计数据
+     *
+     * @param reqVO 请求参数
+     * @return 统计数据
+     */
+    List<CrmStatisticCustomerAreaRespVO> getCustomerArea(CrmStatisticsCustomerReqVO reqVO);
+
 }

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

@@ -5,7 +5,11 @@ import cn.hutool.core.date.LocalDateTimeUtil;
 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.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;
@@ -30,6 +34,7 @@ import java.util.Map;
 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.module.crm.enums.DictTypeConstants.*;
 
 /**
@@ -256,11 +261,11 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
                 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()),
+            findAndThen(industryMap, vo.getIndustryId(), vo::setIndustryName);
+            findAndThen(sourceMap, vo.getSource(), vo::setSourceName);
+            findAndThen(userMap, NumberUtils.parseLong(vo.getCreatorUserId()),
                     user -> vo.setCreatorUserName(user.getNickname()));
-            MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
+            findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname()));
         });
 
         return respVoList;
@@ -400,6 +405,35 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
         });
     }
 
+    @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;
+    }
+
     /**
      * 拼接用户信息(昵称)
      *
@@ -408,7 +442,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
     private <T extends CrmStatisticsCustomerByUserBaseRespVO> void appendUserInfo(List<T> respVoList) {
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(respVoList,
                 CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
-        respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
+        respVoList.forEach(vo -> findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
     }
 
     /**

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

@@ -312,5 +312,26 @@
         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>