CRM:code review 客户总量统计
This commit is contained in:
parent
85817a2426
commit
8dcc12f215
4
pom.xml
4
pom.xml
|
@ -16,12 +16,12 @@
|
|||
<module>yudao-module-system</module>
|
||||
<module>yudao-module-infra</module>
|
||||
<!-- <module>yudao-module-member</module>-->
|
||||
<!-- <module>yudao-module-bpm</module>-->
|
||||
<module>yudao-module-bpm</module>
|
||||
<!-- <module>yudao-module-report</module>-->
|
||||
<!-- <module>yudao-module-mp</module>-->
|
||||
<!-- <module>yudao-module-pay</module>-->
|
||||
<!-- <module>yudao-module-mall</module>-->
|
||||
<!-- <module>yudao-module-crm</module>-->
|
||||
<module>yudao-module-crm</module>
|
||||
<!-- <module>yudao-module-erp</module>-->
|
||||
<!-- 示例项目 -->
|
||||
<!-- <module>yudao-example</module>-->
|
||||
|
|
|
@ -5,12 +5,14 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户客户统计响应 Base VO
|
||||
* 用户客户统计响应 Base Response VO
|
||||
*
|
||||
* 目的:可以统一拼接子 VO 的 ownerUserId、ownerUserName 属性
|
||||
*/
|
||||
@Data
|
||||
public class CrmStatisticsCustomerByUserBaseRespVO {
|
||||
|
||||
@Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@JsonIgnore
|
||||
private Long ownerUserId;
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
||||
|
||||
@Schema(description = "管理后台 - CRM 客户转化率分析 VO")
|
||||
@Data
|
||||
|
@ -43,14 +43,14 @@ public class CrmStatisticsCustomerContractSummaryRespVO {
|
|||
@Schema(description = "客户来源", requiredMode = Schema.RequiredMode.REQUIRED, example = "外呼")
|
||||
private String sourceName;
|
||||
|
||||
@Schema(description = "负责人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@JsonIgnore
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "负责人", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
|
||||
private String ownerUserName;
|
||||
|
||||
@Schema(description = "创建人ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@Schema(description = "创建人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@JsonIgnore
|
||||
private String creatorUserId;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.List;
|
|||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - CRM 数据统计 员工客户分析 Request VO")
|
||||
@Schema(description = "管理后台 - CRM 数据统计的员工客户分析 Request VO")
|
||||
@Data
|
||||
public class CrmStatisticsCustomerReqVO {
|
||||
|
||||
|
@ -39,12 +39,16 @@ public class CrmStatisticsCustomerReqVO {
|
|||
@NotEmpty(message = "时间范围不能为空")
|
||||
private LocalDateTime[] times;
|
||||
|
||||
// TODO @dhb52:这个时间间隔,建议前端传递;例如说:字段叫 interval,枚举有天、周、月、季度、年。因为一般分析类的系统,都是交给用户选择筛选时间间隔,而我们这里是默认根据日期选项,默认对应的 interval 而已
|
||||
// 然后实现上,可以在 common 包的 enums 加个 DateIntervalEnum,里面一个是 interval 字段,枚举过去,然后有个 pattern 字段,用于格式化时间格式;
|
||||
// 这样的话,可以通过 interval 获取到 pattern,然后前端就可以根据 pattern 格式化时间,计算还是交给数据库
|
||||
/**
|
||||
* group by DATE_FORMAT(field, #{dateFormat})
|
||||
*/
|
||||
@Schema(description = "Group By 日期格式", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "%Y%m")
|
||||
private String sqlDateFormat;
|
||||
|
||||
// TODO @dhb52:这个字段,目前是不是没啥用呀?
|
||||
/**
|
||||
* 数据类型 {@link CrmBizTypeEnum}
|
||||
*/
|
||||
|
|
|
@ -13,17 +13,18 @@ import java.util.List;
|
|||
@Mapper
|
||||
public interface CrmStatisticsCustomerMapper {
|
||||
|
||||
List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
|
||||
// TODO @dhb52:拼写,GroupBy。一般 idea 如果出现绿色的警告,可能是单词拼写错误,建议是要修改的哈;
|
||||
List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerCreateCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
|
||||
|
||||
List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
|
||||
List<CrmStatisticsCustomerSummaryByDateRespVO> selectCustomerDealCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO); // 已经 review
|
||||
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO);
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerCreateCountGroupbyUser(CrmStatisticsCustomerReqVO reqVO); // 已经 review
|
||||
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO);
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectCustomerDealCountGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
|
||||
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO);
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectContractPriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
|
||||
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO);
|
||||
List<CrmStatisticsCustomerSummaryByUserRespVO> selectReceivablePriceGroupbyUser(CrmStatisticsCustomerReqVO crmStatisticsCustomerReqVO); // 已经 review
|
||||
|
||||
List<CrmStatisticsFollowupSummaryByDateRespVO> selectFollowupRecordCountGroupbyDate(CrmStatisticsCustomerReqVO reqVO);
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
@Resource
|
||||
private DictDataApi dictDataApi;
|
||||
|
||||
|
||||
@Override
|
||||
public List<CrmStatisticsCustomerSummaryByDateRespVO> getCustomerSummaryByDate(CrmStatisticsCustomerReqVO reqVO) {
|
||||
// 1. 获得用户编号数组
|
||||
|
@ -66,14 +65,17 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
reqVO.setUserIds(userIds);
|
||||
|
||||
// 2. 获取分项统计数据
|
||||
// TODO @dhb52:如果是 list 变量,要么 List 要么 s 后缀
|
||||
reqVO.setSqlDateFormat(getSqlDateFormat(reqVO.getTimes()[0], reqVO.getTimes()[1]));
|
||||
final List<CrmStatisticsCustomerSummaryByDateRespVO> customerCreateCount = customerMapper.selectCustomerCreateCountGroupbyDate(reqVO);
|
||||
final List<CrmStatisticsCustomerSummaryByDateRespVO> customerDealCount = customerMapper.selectCustomerDealCountGroupbyDate(reqVO);
|
||||
|
||||
// 3. 获取时间序列
|
||||
// TODO @dhb52:3 和 4 其实做的是一类事情,所以可以考虑 3.1 获取时间序列、3.2 合并统计数据 这样注释;然后中间就不空行了;就是说,一般空行的目的,是让逻辑分片,看着整体性更好,但是不能让逻辑感觉碎碎的;
|
||||
final List<String> times = generateTimeSeries(reqVO.getTimes()[0], reqVO.getTimes()[1]);
|
||||
|
||||
// 4. 合并统计数据
|
||||
// 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,
|
||||
|
@ -86,7 +88,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
.setCustomerCreateCount(customerCreateCountMap.getOrDefault(time, 0))
|
||||
.setCustomerDealCount(customerDealCountMap.getOrDefault(time, 0))
|
||||
));
|
||||
|
||||
return respVoList;
|
||||
}
|
||||
|
||||
|
@ -131,7 +132,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
|
||||
// 4. 拼接用户信息
|
||||
appendUserInfo(respVoList);
|
||||
|
||||
return respVoList;
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
|
||||
// 4. 拼接用户信息
|
||||
appendUserInfo(respVoList);
|
||||
|
||||
return respVoList;
|
||||
}
|
||||
|
||||
|
@ -290,7 +289,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
new CrmStatisticsCustomerDealCycleByDateRespVO().setTime(time)
|
||||
.setCustomerDealCycle(customerDealCycleMap.getOrDefault(time, 0D))
|
||||
));
|
||||
|
||||
return respVoList;
|
||||
}
|
||||
|
||||
|
@ -337,9 +335,8 @@ 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())));
|
||||
CrmStatisticsCustomerByUserBaseRespVO::getOwnerUserId));
|
||||
respVoList.forEach(vo -> MapUtils.findAndThen(userMap, vo.getOwnerUserId(), user -> vo.setOwnerUserName(user.getNickname())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -349,16 +346,17 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
* @return 用户编号数组
|
||||
*/
|
||||
private List<Long> getUserIds(CrmStatisticsCustomerReqVO reqVO) {
|
||||
// 情况一:选中某个用户
|
||||
if (ObjUtil.isNotNull(reqVO.getUserId())) {
|
||||
return List.of(reqVO.getUserId());
|
||||
} else {
|
||||
// 1. 获得部门列表
|
||||
final Long deptId = reqVO.getDeptId();
|
||||
List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
|
||||
deptIds.add(deptId);
|
||||
// 2. 获得用户编号
|
||||
return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
|
||||
}
|
||||
// 情况二:选中某个部门
|
||||
// 2.1 获得部门列表
|
||||
final Long deptId = reqVO.getDeptId();
|
||||
List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
|
||||
deptIds.add(deptId);
|
||||
// 2.2 获得用户编号
|
||||
return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
|
||||
}
|
||||
|
||||
|
||||
|
@ -380,6 +378,7 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe
|
|||
* @param endTime 结束时间
|
||||
* @return 时间序列
|
||||
*/
|
||||
// TODO @dhb52:可以抽象到 DateUtils 里,开始时间、结束时间,事件间隔,然后返回这个哈;
|
||||
private List<String> generateTimeSeries(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
boolean byMonth = queryByMonth(startTime, endTime);
|
||||
List<String> times = CollUtil.newArrayList();
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper">
|
||||
|
||||
<!-- TODO @dhb52:数据库的关键字,进行大写。例如说,COUNT -->
|
||||
|
||||
<select id="selectCustomerCreateCountGroupbyDate"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
|
||||
SELECT
|
||||
<!-- TODO @dhb52:下面这个,缩进一个 tab;这样可读性更好哈 -->
|
||||
DATE_FORMAT( create_time, #{sqlDateFormat} ) AS time,
|
||||
count(*) AS customerCreateCount
|
||||
COUNT(*) AS customerCreateCount
|
||||
FROM crm_customer
|
||||
WHERE deleted = 0
|
||||
AND owner_user_id IN
|
||||
|
@ -14,6 +17,7 @@
|
|||
#{userId}
|
||||
</foreach>
|
||||
AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
|
||||
<!-- TODO @dhb52:这可以考虑不换行,直接跟在后面的 AND,更连贯哈; -->
|
||||
#{times[1],javaType=java.time.LocalDateTime}
|
||||
GROUP BY time
|
||||
</select>
|
||||
|
@ -21,6 +25,8 @@
|
|||
<select id="selectCustomerDealCountGroupbyDate"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO">
|
||||
SELECT
|
||||
<!-- TODO @dhb52:下面这个,缩进一个 tab;这样可读性更好哈 -->
|
||||
<!-- TODO @dhb52:表变量最好不要用 a、b;可以用 customer 和 constract;虽然长一点,但是一眼看的清楚哈 -->
|
||||
DATE_FORMAT( b.order_date, #{sqlDateFormat} ) AS time,
|
||||
count( DISTINCT a.id ) AS customerDealCount
|
||||
FROM crm_customer AS a
|
||||
|
@ -31,11 +37,13 @@
|
|||
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
|
||||
#{userId}
|
||||
</foreach>
|
||||
<!-- TODO @dhb52:这个应该是 order_date 的范围哈;貌似如果改成这样,不需要查询 customer 表,只要 contract 表就 ok 拉 -->
|
||||
AND b.create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
|
||||
#{times[1],javaType=java.time.LocalDateTime}
|
||||
GROUP BY time
|
||||
</select>
|
||||
|
||||
<!-- TODO @dhb52:根据上面建议,进行优化 -->
|
||||
<select id="selectCustomerCreateCountGroupbyUser"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
|
||||
SELECT owner_user_id, COUNT(1) AS customer_create_count
|
||||
|
@ -50,6 +58,7 @@
|
|||
GROUP BY owner_user_id
|
||||
</select>
|
||||
|
||||
<!-- TODO @dhb52:根据上面建议,进行优化 -->
|
||||
<select id="selectCustomerDealCountGroupbyUser"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
|
||||
SELECT a.owner_user_id, count( DISTINCT a.id ) AS customer_deal_count
|
||||
|
@ -66,6 +75,7 @@
|
|||
GROUP BY a.owner_user_id
|
||||
</select>
|
||||
|
||||
<!-- TODO @dhb52:根据上面建议,进行优化 -->
|
||||
<select id="selectContractPriceGroupbyUser"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
|
||||
SELECT owner_user_id, IFNULL(SUM(total_price), 0) AS contract_price
|
||||
|
@ -82,6 +92,7 @@
|
|||
</select>
|
||||
|
||||
|
||||
<!-- TODO @dhb52:根据上面建议,进行优化 -->
|
||||
<select id="selectReceivablePriceGroupbyUser"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByUserRespVO">
|
||||
SELECT owner_user_id,
|
||||
|
|
|
@ -46,11 +46,11 @@
|
|||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- 工作流。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-bpm-biz</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-bpm-biz</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 支付服务。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
|
@ -88,18 +88,18 @@
|
|||
<!-- </dependency>-->
|
||||
|
||||
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-crm-biz</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-crm-biz</artifactId>
|
||||
<version>${revision}</version>
|
||||
</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>
|
||||
|
|
Loading…
Reference in New Issue