mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-29 18:51:53 +08:00
feat: 客户成交周期分析(按区域、按产品)
This commit is contained in:
parent
2038e5204a
commit
67b02c7e5b
@ -53,3 +53,13 @@ tenant-id: {{adminTenentId}}
|
|||||||
GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
|
GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-user?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
|
||||||
Authorization: Bearer {{token}}
|
Authorization: Bearer {{token}}
|
||||||
tenant-id: {{adminTenentId}}
|
tenant-id: {{adminTenentId}}
|
||||||
|
|
||||||
|
### 6.3 获取客户成交周期(按区域)
|
||||||
|
GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-area?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
tenant-id: {{adminTenentId}}
|
||||||
|
|
||||||
|
### 6.4 获取客户成交周期(按产品)
|
||||||
|
GET {{baseUrl}}/crm/statistics-customer/get-customer-deal-cycle-by-product?deptId=100×[0]=2023-01-01 00:00:00×[1]=2024-12-12 23:59:59
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
tenant-id: {{adminTenentId}}
|
||||||
|
@ -96,6 +96,18 @@ public class CrmStatisticsCustomerController {
|
|||||||
return success(customerService.getCustomerDealCycleByUser(reqVO));
|
return success(customerService.getCustomerDealCycleByUser(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO dhb52:【成交周期分析】里,有按照员工(已实现)、地区(未实现)、产品(未实现),需要在看看哈;可以把 CustomerDealCycle 拆成 3 个 tab,员工客户成交周期分析、地区客户成交周期分析、产品客户成交周期分析;
|
@GetMapping("/get-customer-deal-cycle-by-area")
|
||||||
|
@Operation(summary = "获取客户成交周期(按用户)")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
|
||||||
|
public CommonResult<List<CrmStatisticsCustomerDealCycleByAreaRespVO>> getCustomerDealCycleByArea(@Valid CrmStatisticsCustomerReqVO reqVO) {
|
||||||
|
return success(customerService.getCustomerDealCycleByArea(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-customer-deal-cycle-by-product")
|
||||||
|
@Operation(summary = "获取客户成交周期(按用户)")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:statistics-customer:query')")
|
||||||
|
public CommonResult<List<CrmStatisticsCustomerDealCycleByProductRespVO>> getCustomerDealCycleByProduct(@Valid CrmStatisticsCustomerReqVO reqVO) {
|
||||||
|
return success(customerService.getCustomerDealCycleByProduct(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - CRM 客户成交周期分析(按区域) VO")
|
||||||
|
@Data
|
||||||
|
public class CrmStatisticsCustomerDealCycleByAreaRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "省份编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@JsonIgnore
|
||||||
|
private Integer areaId;
|
||||||
|
|
||||||
|
@Schema(description = "省份名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "浙江省")
|
||||||
|
private String areaName;
|
||||||
|
|
||||||
|
@Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0")
|
||||||
|
private Double customerDealCycle;
|
||||||
|
|
||||||
|
@Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer customerDealCount;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - CRM 客户成交周期分析(按产品) VO")
|
||||||
|
@Data
|
||||||
|
public class CrmStatisticsCustomerDealCycleByProductRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "演示产品")
|
||||||
|
private String productName;
|
||||||
|
|
||||||
|
@Schema(description = "成交周期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0")
|
||||||
|
private Double customerDealCycle;
|
||||||
|
|
||||||
|
@Schema(description = "成交客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer customerDealCount;
|
||||||
|
|
||||||
|
}
|
@ -53,6 +53,7 @@ public interface CrmStatisticsCustomerMapper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 合同总金额(按用户)
|
* 合同总金额(按用户)
|
||||||
|
*
|
||||||
* @return 统计数据@return 统计数据@param reqVO 请求参数
|
* @return 统计数据@return 统计数据@param reqVO 请求参数
|
||||||
* @return 统计数据
|
* @return 统计数据
|
||||||
*/
|
*/
|
||||||
@ -191,4 +192,20 @@ public interface CrmStatisticsCustomerMapper {
|
|||||||
*/
|
*/
|
||||||
List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO);
|
List<CrmStatisticsCustomerDealCycleByUserRespVO> selectCustomerDealCycleGroupByUser(CrmStatisticsCustomerReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户成交周期(按区域)
|
||||||
|
*
|
||||||
|
* @param reqVO 请求参数
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<CrmStatisticsCustomerDealCycleByAreaRespVO> selectCustomerDealCycleGroupByAreaId(CrmStatisticsCustomerReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户成交周期(按产品)
|
||||||
|
*
|
||||||
|
* @param reqVO 请求参数
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<CrmStatisticsCustomerDealCycleByProductRespVO> selectCustomerDealCycleGroupByProductId(CrmStatisticsCustomerReqVO reqVO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public interface CrmStatisticsCustomerService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户成交周期(按日期)
|
* 客户成交周期(按日期)
|
||||||
*
|
* <p>
|
||||||
* 成交周期的定义:客户 customer 在创建出来,到合同 contract 第一次成交的时间差
|
* 成交周期的定义:客户 customer 在创建出来,到合同 contract 第一次成交的时间差
|
||||||
*
|
*
|
||||||
* @param reqVO 请求参数
|
* @param reqVO 请求参数
|
||||||
@ -93,4 +93,20 @@ public interface CrmStatisticsCustomerService {
|
|||||||
*/
|
*/
|
||||||
List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO);
|
List<CrmStatisticsCustomerDealCycleByUserRespVO> getCustomerDealCycleByUser(CrmStatisticsCustomerReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户成交周期(按区域)
|
||||||
|
*
|
||||||
|
* @param reqVO 请求参数
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<CrmStatisticsCustomerDealCycleByAreaRespVO> getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户成交周期(按产品)
|
||||||
|
*
|
||||||
|
* @param reqVO 请求参数
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
List<CrmStatisticsCustomerDealCycleByProductRespVO> getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
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.*;
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper;
|
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.DeptApi;
|
||||||
@ -19,6 +22,7 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||||
@ -290,6 +294,51 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||||||
return summaryList;
|
return summaryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmStatisticsCustomerDealCycleByAreaRespVO> getCustomerDealCycleByArea(CrmStatisticsCustomerReqVO reqVO) {
|
||||||
|
// 1. 获得用户编号数组
|
||||||
|
List<Long> userIds = getUserIds(reqVO);
|
||||||
|
if (CollUtil.isEmpty(userIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
reqVO.setUserIds(userIds);
|
||||||
|
|
||||||
|
// 2. 获取客户地区统计数据
|
||||||
|
List<CrmStatisticsCustomerDealCycleByAreaRespVO> dealCycleByAreaList = customerMapper.selectCustomerDealCycleGroupByAreaId(reqVO);
|
||||||
|
if (CollUtil.isEmpty(dealCycleByAreaList)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 拼接数据
|
||||||
|
Map<Integer, Area> areaMap = convertMap(AreaUtils.getByType(AreaTypeEnum.PROVINCE, Function.identity()),
|
||||||
|
Area::getId);
|
||||||
|
return convertList(dealCycleByAreaList, vo -> {
|
||||||
|
if (vo.getAreaId() != null) {
|
||||||
|
Integer parentId = AreaUtils.getParentIdByType(vo.getAreaId(), AreaTypeEnum.PROVINCE);
|
||||||
|
findAndThen(areaMap, parentId, area -> vo.setAreaId(parentId).setAreaName(area.getName()));
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmStatisticsCustomerDealCycleByProductRespVO> getCustomerDealCycleByProduct(CrmStatisticsCustomerReqVO reqVO) {
|
||||||
|
// 1. 获得用户编号数组
|
||||||
|
List<Long> userIds = getUserIds(reqVO);
|
||||||
|
if (CollUtil.isEmpty(userIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
reqVO.setUserIds(userIds);
|
||||||
|
|
||||||
|
// 2. 获取客户产品统计数据
|
||||||
|
List<CrmStatisticsCustomerDealCycleByProductRespVO> dealCycleByProductList = customerMapper.selectCustomerDealCycleGroupByProductId(reqVO);
|
||||||
|
if (CollUtil.isEmpty(dealCycleByProductList)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dealCycleByProductList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拼接用户信息(昵称)
|
* 拼接用户信息(昵称)
|
||||||
*
|
*
|
||||||
|
@ -19,17 +19,18 @@
|
|||||||
<!-- TODO 芋艿:应该不用过滤时间 -->
|
<!-- TODO 芋艿:应该不用过滤时间 -->
|
||||||
<select id="selectCustomerDealCountGroupByDate"
|
<select id="selectCustomerDealCountGroupByDate"
|
||||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
|
||||||
SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d') AS time,
|
SELECT DATE_FORMAT(customer.create_time, '%Y-%m-%d') AS time,
|
||||||
COUNT(DISTINCT customer.id) AS customer_deal_count
|
COUNT(DISTINCT customer.id) AS customer_deal_count
|
||||||
FROM crm_customer AS customer
|
FROM crm_customer AS customer
|
||||||
LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
|
LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
|
||||||
WHERE customer.deleted = 0 AND contract.deleted = 0
|
WHERE customer.deleted = 0
|
||||||
|
AND contract.deleted = 0
|
||||||
AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
|
AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
|
||||||
AND customer.owner_user_id IN
|
AND customer.owner_user_id IN
|
||||||
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
#{userId}
|
#{userId}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
|
AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
|
||||||
GROUP BY time
|
GROUP BY time
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@ -53,13 +54,14 @@
|
|||||||
COUNT(DISTINCT customer.id) AS customer_deal_count
|
COUNT(DISTINCT customer.id) AS customer_deal_count
|
||||||
FROM crm_customer AS customer
|
FROM crm_customer AS customer
|
||||||
LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
|
LEFT JOIN crm_contract AS contract ON contract.customer_id = customer.id
|
||||||
WHERE customer.deleted = 0 AND contract.deleted = 0
|
WHERE customer.deleted = 0
|
||||||
|
AND contract.deleted = 0
|
||||||
AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
|
AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
|
||||||
AND customer.owner_user_id IN
|
AND customer.owner_user_id IN
|
||||||
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
#{userId}
|
#{userId}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND contract.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
|
AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
|
||||||
GROUP BY customer.owner_user_id
|
GROUP BY customer.owner_user_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@ -221,4 +223,42 @@
|
|||||||
GROUP BY customer.owner_user_id
|
GROUP BY customer.owner_user_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCustomerDealCycleGroupByAreaId"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByAreaRespVO">
|
||||||
|
SELECT customer.area_id AS area_id,
|
||||||
|
IFNULL(TRUNCATE(AVG(TIMESTAMPDIFF(DAY, customer.create_time, contract.order_date)), 1), 0) AS customer_deal_cycle,
|
||||||
|
COUNT(DISTINCT customer.id) AS customer_deal_count
|
||||||
|
FROM crm_customer AS customer
|
||||||
|
LEFT JOIN crm_contract AS contract ON customer.id = contract.customer_id
|
||||||
|
WHERE customer.deleted = 0
|
||||||
|
AND contract.deleted = 0
|
||||||
|
AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
|
||||||
|
AND customer.owner_user_id IN
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY
|
||||||
|
customer.area_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCustomerDealCycleGroupByProductId"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerDealCycleByProductRespVO">
|
||||||
|
SELECT (SELECT name FROM crm_product WHERE id = product.id) AS product_name,
|
||||||
|
IFNULL(TRUNCATE(AVG(TIMESTAMPDIFF(DAY, customer.create_time, contract.order_date)), 1), 0) AS customer_deal_cycle,
|
||||||
|
COUNT(DISTINCT customer.id) AS customer_deal_count
|
||||||
|
FROM crm_customer AS customer
|
||||||
|
LEFT JOIN crm_contract AS contract ON customer.id = contract.customer_id
|
||||||
|
LEFT JOIN crm_contract_product AS product ON product.contract_id = contract.id
|
||||||
|
WHERE customer.deleted = 0
|
||||||
|
AND contract.deleted = 0
|
||||||
|
AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
|
||||||
|
AND customer.owner_user_id IN
|
||||||
|
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||||
|
#{userId}
|
||||||
|
</foreach>
|
||||||
|
AND customer.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime}
|
||||||
|
GROUP BY product.id
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
Loading…
Reference in New Issue
Block a user