Commit 20b4bfd1b03fbcca713aa7d107491f53d592be9f

Authored by puhui999
1 parent fc3cdc44

CRM: 完善新增商机分析

Showing 11 changed files with 367 additions and 9 deletions
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java
1 1 package cn.iocoder.yudao.module.crm.controller.admin.statistics;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  9 +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO;
4 10 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
5 11 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
  12 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
6 13 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
  14 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
  15 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
  16 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO;
  17 +import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
  18 +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
  19 +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService;
  20 +import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
7 21 import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService;
  22 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  23 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  24 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  25 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
8 26 import io.swagger.v3.oas.annotations.Operation;
9 27 import io.swagger.v3.oas.annotations.tags.Tag;
10 28 import jakarta.annotation.Resource;
... ... @@ -15,9 +33,14 @@ import org.springframework.web.bind.annotation.GetMapping;
15 33 import org.springframework.web.bind.annotation.RequestMapping;
16 34 import org.springframework.web.bind.annotation.RestController;
17 35  
  36 +import java.util.Collections;
18 37 import java.util.List;
  38 +import java.util.Map;
  39 +import java.util.stream.Stream;
19 40  
20 41 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  42 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
  43 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
21 44  
22 45 @Tag(name = "管理后台 - CRM 销售漏斗")
23 46 @RestController
... ... @@ -27,6 +50,19 @@ public class CrmStatisticsFunnelController {
27 50  
28 51 @Resource
29 52 private CrmStatisticsFunnelService crmStatisticsFunnelService;
  53 + @Resource
  54 + private CrmBusinessService businessService;
  55 + @Resource
  56 + private CrmCustomerService customerService;
  57 + @Resource
  58 + private CrmBusinessStatusService businessStatusTypeService;
  59 + @Resource
  60 + private CrmBusinessStatusService businessStatusService;
  61 +
  62 + @Resource
  63 + private AdminUserApi adminUserApi;
  64 + @Resource
  65 + private DeptApi deptApi;
30 66  
31 67 @GetMapping("/get-funnel-summary")
32 68 @Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面")
... ... @@ -35,7 +71,6 @@ public class CrmStatisticsFunnelController {
35 71 return success(crmStatisticsFunnelService.getFunnelSummary(reqVO));
36 72 }
37 73  
38   -
39 74 @GetMapping("/get-business-end-status-summary")
40 75 @Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面")
41 76 @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
... ... @@ -43,4 +78,53 @@ public class CrmStatisticsFunnelController {
43 78 return success(crmStatisticsFunnelService.getBusinessEndStatusSummary(reqVO));
44 79 }
45 80  
  81 + @GetMapping("/get-business-summary-by-date")
  82 + @Operation(summary = "获取新增商机分析(按日期)", description = "用于【销售漏斗】页面")
  83 + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
  84 + public CommonResult<List<CrmStatisticsBusinessSummaryByDateRespVO>> getBusinessSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) {
  85 + return success(crmStatisticsFunnelService.getBusinessSummaryByDate(reqVO));
  86 + }
  87 +
  88 + @GetMapping("/get-business-page-by-date")
  89 + @Operation(summary = "获得商机分页(按日期)", description = "用于【销售漏斗】页面")
  90 + @PreAuthorize("@ss.hasPermission('crm:business:query')")
  91 + public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByDate(@Valid CrmStatisticsFunnelReqVO pageVO) {
  92 + PageResult<CrmBusinessDO> pageResult = crmStatisticsFunnelService.getBusinessPageByDate(pageVO);
  93 + return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal()));
  94 + }
  95 +
  96 + private List<CrmBusinessRespVO> buildBusinessDetailList(List<CrmBusinessDO> list) {
  97 + if (CollUtil.isEmpty(list)) {
  98 + return Collections.emptyList();
  99 + }
  100 + // 1.1 获取客户列表
  101 + Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
  102 + convertSet(list, CrmBusinessDO::getCustomerId));
  103 + // 1.2 获取创建人、负责人列表
  104 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list,
  105 + contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
  106 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  107 + // 1.3 获得商机状态组
  108 + Map<Long, CrmBusinessStatusTypeDO> statusTypeMap = businessStatusTypeService.getBusinessStatusTypeMap(
  109 + convertSet(list, CrmBusinessDO::getStatusTypeId));
  110 + Map<Long, CrmBusinessStatusDO> statusMap = businessStatusService.getBusinessStatusMap(
  111 + convertSet(list, CrmBusinessDO::getStatusId));
  112 + // 2. 拼接数据
  113 + return BeanUtils.toBean(list, CrmBusinessRespVO.class, businessVO -> {
  114 + // 2.1 设置客户名称
  115 + MapUtils.findAndThen(customerMap, businessVO.getCustomerId(), customer -> businessVO.setCustomerName(customer.getName()));
  116 + // 2.2 设置创建人、负责人名称
  117 + MapUtils.findAndThen(userMap, NumberUtils.parseLong(businessVO.getCreator()),
  118 + user -> businessVO.setCreatorName(user.getNickname()));
  119 + MapUtils.findAndThen(userMap, businessVO.getOwnerUserId(), user -> {
  120 + businessVO.setOwnerUserName(user.getNickname());
  121 + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> businessVO.setOwnerUserDeptName(dept.getName()));
  122 + });
  123 + // 2.3 设置商机状态
  124 + MapUtils.findAndThen(statusTypeMap, businessVO.getStatusTypeId(), statusType -> businessVO.setStatusTypeName(statusType.getName()));
  125 + MapUtils.findAndThen(statusMap, businessVO.getStatusId(), status -> businessVO.setStatusName(
  126 + businessService.getBusinessStatusName(businessVO.getEndStatus(), status)));
  127 + });
  128 + }
  129 +
46 130 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Data;
  8 +import lombok.NoArgsConstructor;
  9 +
  10 +import java.math.BigDecimal;
  11 +import java.time.LocalDateTime;
  12 +import java.util.List;
  13 +
  14 +@Schema(description = "管理后台 - CRM 商机 Response VO")
  15 +@Data
  16 +@ExcelIgnoreUnannotated
  17 +public class CrmStatisticsBusinessRespVO {
  18 +
  19 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129")
  20 + @ExcelProperty("编号")
  21 + private Long id;
  22 +
  23 + @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  24 + @ExcelProperty("商机名称")
  25 + private String name;
  26 +
  27 + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299")
  28 + private Long customerId;
  29 + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  30 + @ExcelProperty("客户名称")
  31 + private String customerName;
  32 +
  33 + @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true")
  34 + @ExcelProperty("跟进状态")
  35 + private Boolean followUpStatus;
  36 +
  37 + @Schema(description = "最后跟进时间")
  38 + @ExcelProperty("最后跟进时间")
  39 + private LocalDateTime contactLastTime;
  40 +
  41 + @Schema(description = "下次联系时间")
  42 + @ExcelProperty("下次联系时间")
  43 + private LocalDateTime contactNextTime;
  44 +
  45 + @Schema(description = "负责人的用户编号", example = "25682")
  46 + @ExcelProperty("负责人的用户编号")
  47 + private Long ownerUserId;
  48 + @Schema(description = "负责人名字", example = "25682")
  49 + @ExcelProperty("负责人名字")
  50 + private String ownerUserName;
  51 + @Schema(description = "负责人部门")
  52 + @ExcelProperty("负责人部门")
  53 + private String ownerUserDeptName;
  54 +
  55 + @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714")
  56 + private Long statusTypeId;
  57 + @Schema(description = "商机状组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中")
  58 + @ExcelProperty("商机状态组")
  59 + private String statusTypeName;
  60 +
  61 + @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
  62 + private Long statusId;
  63 + @Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中")
  64 + @ExcelProperty("商机状态")
  65 + private String statusName;
  66 +
  67 + @Schema
  68 + @ExcelProperty("结束状态")
  69 + private Integer endStatus;
  70 +
  71 + @ExcelProperty("结束时的备注")
  72 + private String endRemark;
  73 +
  74 + @Schema(description = "预计成交日期")
  75 + @ExcelProperty("预计成交日期")
  76 + private LocalDateTime dealTime;
  77 +
  78 + @Schema(description = "产品总金额", example = "12025")
  79 + @ExcelProperty("产品总金额")
  80 + private BigDecimal totalProductPrice;
  81 +
  82 + @Schema(description = "整单折扣")
  83 + @ExcelProperty("整单折扣")
  84 + private BigDecimal discountPercent;
  85 +
  86 + @Schema(description = "商机总金额", example = "12371")
  87 + @ExcelProperty("商机总金额")
  88 + private BigDecimal totalPrice;
  89 +
  90 + @Schema(description = "备注", example = "随便")
  91 + @ExcelProperty("备注")
  92 + private String remark;
  93 +
  94 + @Schema(description = "创建人", example = "1024")
  95 + @ExcelProperty("创建人")
  96 + private String creator;
  97 + @Schema(description = "创建人名字", example = "芋道源码")
  98 + @ExcelProperty("创建人名字")
  99 + private String creatorName;
  100 +
  101 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  102 + @ExcelProperty("创建时间")
  103 + private LocalDateTime createTime;
  104 +
  105 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  106 + @ExcelProperty("更新时间")
  107 + private LocalDateTime updateTime;
  108 +
  109 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByDateRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +
  8 +@Schema(description = "管理后台 - CRM 新增商机分析(按日期) VO")
  9 +@Data
  10 +public class CrmStatisticsBusinessSummaryByDateRespVO {
  11 +
  12 + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
  13 + private String time;
  14 +
  15 + @Schema(description = "新增商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer businessCreateCount;
  17 +
  18 + @Schema(description = "新增商机金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private BigDecimal businessDealCount;
  20 +
  21 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java
1 1 package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  5 +import cn.iocoder.yudao.framework.common.validation.InEnum;
3 6 import io.swagger.v3.oas.annotations.media.Schema;
4 7 import jakarta.validation.constraints.NotNull;
5 8 import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
6 11 import org.springframework.format.annotation.DateTimeFormat;
7 12  
8 13 import java.time.LocalDateTime;
... ... @@ -12,7 +17,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
12 17  
13 18 @Schema(description = "管理后台 - CRM 销售漏斗 Request VO")
14 19 @Data
15   -public class CrmStatisticsFunnelReqVO {
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +public class CrmStatisticsFunnelReqVO extends PageParam {
16 23  
17 24 @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
18 25 @NotNull(message = "部门 id 不能为空")
... ... @@ -31,6 +38,10 @@ public class CrmStatisticsFunnelReqVO {
31 38 @Schema(description = "负责人用户 id 集合", hidden = true, example = "2")
32 39 private List<Long> userIds;
33 40  
  41 + @Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  42 + @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}")
  43 + private Integer interval;
  44 +
34 45 /**
35 46 * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间
36 47 * 并作为参数传递给Mapper
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
1 1 package cn.iocoder.yudao.module.crm.dal.mysql.business;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
... ... @@ -14,7 +15,6 @@ import org.apache.ibatis.annotations.Mapper;
14 15 import java.time.LocalDateTime;
15 16 import java.util.Collection;
16 17 import java.util.List;
17   -import java.util.Set;
18 18  
19 19 /**
20 20 * 商机 Mapper
... ... @@ -73,11 +73,23 @@ public interface CrmBusinessMapper extends BaseMapperX&lt;CrmBusinessDO&gt; {
73 73 .betweenIfPresent(CrmBusinessDO::getCreateTime, times));
74 74 }
75 75  
76   - default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times){
  76 + default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times) {
77 77 return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
78 78 .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
79 79 .betweenIfPresent(CrmBusinessDO::getCreateTime, times)
80 80 .isNotNull(CrmBusinessDO::getEndStatus));
81 81 }
82 82  
  83 + default List<CrmBusinessDO> selectListByOwnerUserIdsAndDate(Collection<Long> ownerUserIds, LocalDateTime[] times) {
  84 + return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
  85 + .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
  86 + .betweenIfPresent(CrmBusinessDO::getCreateTime, times));
  87 + }
  88 +
  89 + default PageResult<CrmBusinessDO> selectPage(Collection<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize) {
  90 + return selectPage(new PageParam().setPageNo(pageNo).setPageSize(pageSize), new LambdaQueryWrapperX<CrmBusinessDO>()
  91 + .in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
  92 + .betweenIfPresent(CrmBusinessDO::getCreateTime, times));
  93 + }
  94 +
83 95 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java
1 1 package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
2 2  
  3 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
3 6 import org.apache.ibatis.annotations.Mapper;
4 7  
  8 +import java.util.List;
  9 +
5 10 /**
6 11 * CRM 销售漏斗 Mapper
7 12 *
... ... @@ -10,5 +15,6 @@ import org.apache.ibatis.annotations.Mapper;
10 15 @Mapper
11 16 public interface CrmStatisticsFunnelMapper {
12 17  
  18 + List<CrmStatisticsBusinessSummaryByDateRespVO> selectBusinessCreateCountGroupByDate(CrmStatisticsFunnelReqVO reqVO);
13 19  
14 20 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
... ... @@ -213,4 +213,23 @@ public interface CrmBusinessService {
213 213 */
214 214 List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times);
215 215  
  216 + /**
  217 + * 获得商机列表【数据统计】
  218 + *
  219 + * @param ownerUserIds 负责人编号
  220 + * @param times 时间范围
  221 + * @return 商机列表
  222 + */
  223 + List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times);
  224 +
  225 + /**
  226 + * 商机分页【数据统计】
  227 + * @param ownerUserIds 负责人编号
  228 + * @param times 时间范围
  229 + * @param pageNo 页码
  230 + * @param pageSize 数量
  231 + * @return 商机分页
  232 + */
  233 + PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize);
  234 +
216 235 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -391,4 +391,18 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
391 391 return businessMapper.selectListByOwnerUserIdsAndEndStatusNotNull(convertSet(ownerUserIds), times);
392 392 }
393 393  
  394 + @Override
  395 + public List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times) {
  396 + if (CollUtil.isEmpty(ownerUserIds)) {
  397 + return Collections.emptyList();
  398 + }
  399 +
  400 + return businessMapper.selectListByOwnerUserIdsAndDate(convertSet(ownerUserIds), times);
  401 + }
  402 +
  403 + @Override
  404 + public PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize) {
  405 + return businessMapper.selectPage(ownerUserIds, times, pageNo, pageSize);
  406 + }
  407 +
394 408 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java
1 1 package cn.iocoder.yudao.module.crm.service.statistics;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 4 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
4 5 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
5 7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
  8 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
6 9  
7 10 import java.util.List;
8 11  
... ... @@ -29,4 +32,20 @@ public interface CrmStatisticsFunnelService {
29 32 */
30 33 List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO);
31 34  
  35 + /**
  36 + * 获取新增商机分析(按日期)
  37 + *
  38 + * @param reqVO 请求
  39 + * @return 新增商机分析
  40 + */
  41 + List<CrmStatisticsBusinessSummaryByDateRespVO> getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO);
  42 +
  43 + /**
  44 + * 获得商机分页(按日期)
  45 + *
  46 + * @param pageVO 请求
  47 + * @return 商机分页
  48 + */
  49 + PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO);
  50 +
32 51 }
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java
... ... @@ -2,8 +2,11 @@ package cn.iocoder.yudao.module.crm.service.statistics;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
5 7 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
6 8 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
  9 +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
7 10 import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
8 11 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
9 12 import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper;
... ... @@ -18,10 +21,15 @@ import jakarta.annotation.Resource;
18 21 import org.springframework.stereotype.Service;
19 22  
20 23 import java.math.BigDecimal;
  24 +import java.time.LocalDateTime;
  25 +import java.time.format.DateTimeFormatter;
  26 +import java.util.Collections;
21 27 import java.util.List;
22 28 import java.util.Map;
  29 +import java.util.stream.Collectors;
23 30  
24 31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  32 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
25 33  
26 34 /**
27 35 * CRM 销售漏斗分析 Service 实现类
... ... @@ -63,14 +71,13 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
63 71 @Override
64 72 public List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO) {
65 73 // 1. 获得用户编号数组
66   - List<Long> userIds = getUserIds(reqVO);
67   - if (CollUtil.isEmpty(userIds)) {
68   - return null;
  74 + reqVO.setUserIds(getUserIds(reqVO));
  75 + if (CollUtil.isEmpty(reqVO.getUserIds())) {
  76 + return Collections.emptyList();
69 77 }
70   - reqVO.setUserIds(userIds);
71 78  
72 79 // 2.1 获得用户负责的商机
73   - List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(userIds, reqVO.getTimes());
  80 + List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(reqVO.getUserIds(), reqVO.getTimes());
74 81 // 2.2 统计各阶段数据
75 82 Map<Integer, List<CrmBusinessDO>> businessMap = convertMultiMap(businessList, CrmBusinessDO::getEndStatus);
76 83 return convertList(CrmBusinessEndStatusEnum.values(), endStatusEnum -> {
... ... @@ -83,6 +90,48 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
83 90 });
84 91 }
85 92  
  93 + @Override
  94 + public List<CrmStatisticsBusinessSummaryByDateRespVO> getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO) {
  95 + // 1. 获得用户编号数组
  96 + reqVO.setUserIds(getUserIds(reqVO));
  97 + if (CollUtil.isEmpty(reqVO.getUserIds())) {
  98 + return Collections.emptyList();
  99 + }
  100 +
  101 + // 2. 按天统计,获取分项统计数据
  102 + List<CrmStatisticsBusinessSummaryByDateRespVO> businessCreateCountList = funnelMapper.selectBusinessCreateCountGroupByDate(reqVO);
  103 + List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndDate(reqVO.getUserIds(), reqVO.getTimes());
  104 + Map<String, BigDecimal> businessDealCountMap = businessList.stream().collect(Collectors.groupingBy(business ->
  105 + business.getCreateTime().format(DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY)),
  106 + Collectors.reducing(BigDecimal.ZERO, CrmBusinessDO::getTotalPrice, BigDecimal::add)));
  107 +
  108 + // 3. 按照日期间隔,合并数据
  109 + List<LocalDateTime[]> timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval());
  110 + return convertList(timeRanges, times -> {
  111 + Integer businessCreateCount = businessCreateCountList.stream()
  112 + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime()))
  113 + .mapToInt(CrmStatisticsBusinessSummaryByDateRespVO::getBusinessCreateCount).sum();
  114 + BigDecimal businessDealCount = businessDealCountMap.entrySet().stream()
  115 + .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getKey()))
  116 + .map(Map.Entry::getValue)
  117 + .reduce(BigDecimal.ZERO, BigDecimal::add);
  118 + return new CrmStatisticsBusinessSummaryByDateRespVO()
  119 + .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval()))
  120 + .setBusinessCreateCount(businessCreateCount).setBusinessDealCount(businessDealCount);
  121 + });
  122 + }
  123 +
  124 + @Override
  125 + public PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) {
  126 + // 1. 获得用户编号数组
  127 + pageVO.setUserIds(getUserIds(pageVO));
  128 + if (CollUtil.isEmpty(pageVO.getUserIds())) {
  129 + return PageResult.empty();
  130 + }
  131 +
  132 + return businessService.getBusinessPageByDate(pageVO.getUserIds(), pageVO.getTimes(), pageVO.getPageNo(), pageVO.getPageSize());
  133 + }
  134 +
86 135 /**
87 136 * 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号
88 137 *
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml
... ... @@ -2,4 +2,18 @@
2 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 3 <mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper">
4 4  
  5 + <select id="selectBusinessCreateCountGroupByDate"
  6 + resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO">
  7 + SELECT DATE_FORMAT(create_time, '%Y-%m-%d') AS time, COUNT(*) AS businessCreateCount
  8 + FROM crm_business
  9 + WHERE deleted = 0
  10 + AND owner_user_id IN
  11 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  12 + #{userId}
  13 + </foreach>
  14 + AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND
  15 + #{times[1],javaType=java.time.LocalDateTime}
  16 + GROUP BY time
  17 + </select>
  18 +
5 19 </mapper>
... ...