mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 23:31:52 +08:00
CRM: 完善新增商机分析
This commit is contained in:
parent
fc3cdc4499
commit
20b4bfd1b0
@ -1,10 +1,28 @@
|
|||||||
package cn.iocoder.yudao.module.crm.controller.admin.statistics;
|
package cn.iocoder.yudao.module.crm.controller.admin.statistics;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessStatusService;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
||||||
import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService;
|
import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsFunnelService;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@ -15,9 +33,14 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - CRM 销售漏斗")
|
@Tag(name = "管理后台 - CRM 销售漏斗")
|
||||||
@RestController
|
@RestController
|
||||||
@ -27,6 +50,19 @@ public class CrmStatisticsFunnelController {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmStatisticsFunnelService crmStatisticsFunnelService;
|
private CrmStatisticsFunnelService crmStatisticsFunnelService;
|
||||||
|
@Resource
|
||||||
|
private CrmBusinessService businessService;
|
||||||
|
@Resource
|
||||||
|
private CrmCustomerService customerService;
|
||||||
|
@Resource
|
||||||
|
private CrmBusinessStatusService businessStatusTypeService;
|
||||||
|
@Resource
|
||||||
|
private CrmBusinessStatusService businessStatusService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
@Resource
|
||||||
|
private DeptApi deptApi;
|
||||||
|
|
||||||
@GetMapping("/get-funnel-summary")
|
@GetMapping("/get-funnel-summary")
|
||||||
@Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面")
|
@Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面")
|
||||||
@ -35,7 +71,6 @@ public class CrmStatisticsFunnelController {
|
|||||||
return success(crmStatisticsFunnelService.getFunnelSummary(reqVO));
|
return success(crmStatisticsFunnelService.getFunnelSummary(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/get-business-end-status-summary")
|
@GetMapping("/get-business-end-status-summary")
|
||||||
@Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面")
|
@Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面")
|
||||||
@PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
|
@PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
|
||||||
@ -43,4 +78,53 @@ public class CrmStatisticsFunnelController {
|
|||||||
return success(crmStatisticsFunnelService.getBusinessEndStatusSummary(reqVO));
|
return success(crmStatisticsFunnelService.getBusinessEndStatusSummary(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-business-summary-by-date")
|
||||||
|
@Operation(summary = "获取新增商机分析(按日期)", description = "用于【销售漏斗】页面")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')")
|
||||||
|
public CommonResult<List<CrmStatisticsBusinessSummaryByDateRespVO>> getBusinessSummaryByDate(@Valid CrmStatisticsFunnelReqVO reqVO) {
|
||||||
|
return success(crmStatisticsFunnelService.getBusinessSummaryByDate(reqVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-business-page-by-date")
|
||||||
|
@Operation(summary = "获得商机分页(按日期)", description = "用于【销售漏斗】页面")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:business:query')")
|
||||||
|
public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByDate(@Valid CrmStatisticsFunnelReqVO pageVO) {
|
||||||
|
PageResult<CrmBusinessDO> pageResult = crmStatisticsFunnelService.getBusinessPageByDate(pageVO);
|
||||||
|
return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CrmBusinessRespVO> buildBusinessDetailList(List<CrmBusinessDO> list) {
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
// 1.1 获取客户列表
|
||||||
|
Map<Long, CrmCustomerDO> customerMap = customerService.getCustomerMap(
|
||||||
|
convertSet(list, CrmBusinessDO::getCustomerId));
|
||||||
|
// 1.2 获取创建人、负责人列表
|
||||||
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(list,
|
||||||
|
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
|
||||||
|
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
|
||||||
|
// 1.3 获得商机状态组
|
||||||
|
Map<Long, CrmBusinessStatusTypeDO> statusTypeMap = businessStatusTypeService.getBusinessStatusTypeMap(
|
||||||
|
convertSet(list, CrmBusinessDO::getStatusTypeId));
|
||||||
|
Map<Long, CrmBusinessStatusDO> statusMap = businessStatusService.getBusinessStatusMap(
|
||||||
|
convertSet(list, CrmBusinessDO::getStatusId));
|
||||||
|
// 2. 拼接数据
|
||||||
|
return BeanUtils.toBean(list, CrmBusinessRespVO.class, businessVO -> {
|
||||||
|
// 2.1 设置客户名称
|
||||||
|
MapUtils.findAndThen(customerMap, businessVO.getCustomerId(), customer -> businessVO.setCustomerName(customer.getName()));
|
||||||
|
// 2.2 设置创建人、负责人名称
|
||||||
|
MapUtils.findAndThen(userMap, NumberUtils.parseLong(businessVO.getCreator()),
|
||||||
|
user -> businessVO.setCreatorName(user.getNickname()));
|
||||||
|
MapUtils.findAndThen(userMap, businessVO.getOwnerUserId(), user -> {
|
||||||
|
businessVO.setOwnerUserName(user.getNickname());
|
||||||
|
MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> businessVO.setOwnerUserDeptName(dept.getName()));
|
||||||
|
});
|
||||||
|
// 2.3 设置商机状态
|
||||||
|
MapUtils.findAndThen(statusTypeMap, businessVO.getStatusTypeId(), statusType -> businessVO.setStatusTypeName(statusType.getName()));
|
||||||
|
MapUtils.findAndThen(statusMap, businessVO.getStatusId(), status -> businessVO.setStatusName(
|
||||||
|
businessService.getBusinessStatusName(businessVO.getEndStatus(), status)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - CRM 商机 Response VO")
|
||||||
|
@Data
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class CrmStatisticsBusinessRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129")
|
||||||
|
@ExcelProperty("编号")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||||
|
@ExcelProperty("商机名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299")
|
||||||
|
private Long customerId;
|
||||||
|
@Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||||
|
@ExcelProperty("客户名称")
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
@Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example ="true")
|
||||||
|
@ExcelProperty("跟进状态")
|
||||||
|
private Boolean followUpStatus;
|
||||||
|
|
||||||
|
@Schema(description = "最后跟进时间")
|
||||||
|
@ExcelProperty("最后跟进时间")
|
||||||
|
private LocalDateTime contactLastTime;
|
||||||
|
|
||||||
|
@Schema(description = "下次联系时间")
|
||||||
|
@ExcelProperty("下次联系时间")
|
||||||
|
private LocalDateTime contactNextTime;
|
||||||
|
|
||||||
|
@Schema(description = "负责人的用户编号", example = "25682")
|
||||||
|
@ExcelProperty("负责人的用户编号")
|
||||||
|
private Long ownerUserId;
|
||||||
|
@Schema(description = "负责人名字", example = "25682")
|
||||||
|
@ExcelProperty("负责人名字")
|
||||||
|
private String ownerUserName;
|
||||||
|
@Schema(description = "负责人部门")
|
||||||
|
@ExcelProperty("负责人部门")
|
||||||
|
private String ownerUserDeptName;
|
||||||
|
|
||||||
|
@Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714")
|
||||||
|
private Long statusTypeId;
|
||||||
|
@Schema(description = "商机状组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中")
|
||||||
|
@ExcelProperty("商机状态组")
|
||||||
|
private String statusTypeName;
|
||||||
|
|
||||||
|
@Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320")
|
||||||
|
private Long statusId;
|
||||||
|
@Schema(description = "状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "跟进中")
|
||||||
|
@ExcelProperty("商机状态")
|
||||||
|
private String statusName;
|
||||||
|
|
||||||
|
@Schema
|
||||||
|
@ExcelProperty("结束状态")
|
||||||
|
private Integer endStatus;
|
||||||
|
|
||||||
|
@ExcelProperty("结束时的备注")
|
||||||
|
private String endRemark;
|
||||||
|
|
||||||
|
@Schema(description = "预计成交日期")
|
||||||
|
@ExcelProperty("预计成交日期")
|
||||||
|
private LocalDateTime dealTime;
|
||||||
|
|
||||||
|
@Schema(description = "产品总金额", example = "12025")
|
||||||
|
@ExcelProperty("产品总金额")
|
||||||
|
private BigDecimal totalProductPrice;
|
||||||
|
|
||||||
|
@Schema(description = "整单折扣")
|
||||||
|
@ExcelProperty("整单折扣")
|
||||||
|
private BigDecimal discountPercent;
|
||||||
|
|
||||||
|
@Schema(description = "商机总金额", example = "12371")
|
||||||
|
@ExcelProperty("商机总金额")
|
||||||
|
private BigDecimal totalPrice;
|
||||||
|
|
||||||
|
@Schema(description = "备注", example = "随便")
|
||||||
|
@ExcelProperty("备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "创建人", example = "1024")
|
||||||
|
@ExcelProperty("创建人")
|
||||||
|
private String creator;
|
||||||
|
@Schema(description = "创建人名字", example = "芋道源码")
|
||||||
|
@ExcelProperty("创建人名字")
|
||||||
|
private String creatorName;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@ExcelProperty("更新时间")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - CRM 新增商机分析(按日期) VO")
|
||||||
|
@Data
|
||||||
|
public class CrmStatisticsBusinessSummaryByDateRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401")
|
||||||
|
private String time;
|
||||||
|
|
||||||
|
@Schema(description = "新增商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer businessCreateCount;
|
||||||
|
|
||||||
|
@Schema(description = "新增商机金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private BigDecimal businessDealCount;
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,13 @@
|
|||||||
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
|
package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -12,7 +17,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
|||||||
|
|
||||||
@Schema(description = "管理后台 - CRM 销售漏斗 Request VO")
|
@Schema(description = "管理后台 - CRM 销售漏斗 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class CrmStatisticsFunnelReqVO {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class CrmStatisticsFunnelReqVO extends PageParam {
|
||||||
|
|
||||||
@Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
@Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@NotNull(message = "部门 id 不能为空")
|
@NotNull(message = "部门 id 不能为空")
|
||||||
@ -31,6 +38,10 @@ public class CrmStatisticsFunnelReqVO {
|
|||||||
@Schema(description = "负责人用户 id 集合", hidden = true, example = "2")
|
@Schema(description = "负责人用户 id 集合", hidden = true, example = "2")
|
||||||
private List<Long> userIds;
|
private List<Long> userIds;
|
||||||
|
|
||||||
|
@Schema(description = "时间间隔类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}")
|
||||||
|
private Integer interval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间
|
* 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间
|
||||||
* 并作为参数传递给Mapper
|
* 并作为参数传递给Mapper
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.crm.dal.mysql.business;
|
package cn.iocoder.yudao.module.crm.dal.mysql.business;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
@ -14,7 +15,6 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商机 Mapper
|
* 商机 Mapper
|
||||||
@ -73,11 +73,23 @@ public interface CrmBusinessMapper extends BaseMapperX<CrmBusinessDO> {
|
|||||||
.betweenIfPresent(CrmBusinessDO::getCreateTime, times));
|
.betweenIfPresent(CrmBusinessDO::getCreateTime, times));
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times){
|
default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times) {
|
||||||
return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
|
return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
|
||||||
.in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
|
.in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
|
||||||
.betweenIfPresent(CrmBusinessDO::getCreateTime, times)
|
.betweenIfPresent(CrmBusinessDO::getCreateTime, times)
|
||||||
.isNotNull(CrmBusinessDO::getEndStatus));
|
.isNotNull(CrmBusinessDO::getEndStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<CrmBusinessDO> selectListByOwnerUserIdsAndDate(Collection<Long> ownerUserIds, LocalDateTime[] times) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<CrmBusinessDO>()
|
||||||
|
.in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
|
||||||
|
.betweenIfPresent(CrmBusinessDO::getCreateTime, times));
|
||||||
|
}
|
||||||
|
|
||||||
|
default PageResult<CrmBusinessDO> selectPage(Collection<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize) {
|
||||||
|
return selectPage(new PageParam().setPageNo(pageNo).setPageSize(pageSize), new LambdaQueryWrapperX<CrmBusinessDO>()
|
||||||
|
.in(CrmBusinessDO::getOwnerUserId, ownerUserIds)
|
||||||
|
.betweenIfPresent(CrmBusinessDO::getCreateTime, times));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
|
package cn.iocoder.yudao.module.crm.dal.mysql.statistics;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerSummaryByDateRespVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRM 销售漏斗 Mapper
|
* CRM 销售漏斗 Mapper
|
||||||
*
|
*
|
||||||
@ -10,5 +15,6 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface CrmStatisticsFunnelMapper {
|
public interface CrmStatisticsFunnelMapper {
|
||||||
|
|
||||||
|
List<CrmStatisticsBusinessSummaryByDateRespVO> selectBusinessCreateCountGroupByDate(CrmStatisticsFunnelReqVO reqVO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -213,4 +213,23 @@ public interface CrmBusinessService {
|
|||||||
*/
|
*/
|
||||||
List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times);
|
List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得商机列表【数据统计】
|
||||||
|
*
|
||||||
|
* @param ownerUserIds 负责人编号
|
||||||
|
* @param times 时间范围
|
||||||
|
* @return 商机列表
|
||||||
|
*/
|
||||||
|
List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商机分页【数据统计】
|
||||||
|
* @param ownerUserIds 负责人编号
|
||||||
|
* @param times 时间范围
|
||||||
|
* @param pageNo 页码
|
||||||
|
* @param pageSize 数量
|
||||||
|
* @return 商机分页
|
||||||
|
*/
|
||||||
|
PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -391,4 +391,18 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
|||||||
return businessMapper.selectListByOwnerUserIdsAndEndStatusNotNull(convertSet(ownerUserIds), times);
|
return businessMapper.selectListByOwnerUserIdsAndEndStatusNotNull(convertSet(ownerUserIds), times);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times) {
|
||||||
|
if (CollUtil.isEmpty(ownerUserIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return businessMapper.selectListByOwnerUserIdsAndDate(convertSet(ownerUserIds), times);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize) {
|
||||||
|
return businessMapper.selectPage(ownerUserIds, times, pageNo, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package cn.iocoder.yudao.module.crm.service.statistics;
|
package cn.iocoder.yudao.module.crm.service.statistics;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -29,4 +32,20 @@ public interface CrmStatisticsFunnelService {
|
|||||||
*/
|
*/
|
||||||
List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO);
|
List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取新增商机分析(按日期)
|
||||||
|
*
|
||||||
|
* @param reqVO 请求
|
||||||
|
* @return 新增商机分析
|
||||||
|
*/
|
||||||
|
List<CrmStatisticsBusinessSummaryByDateRespVO> getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得商机分页(按日期)
|
||||||
|
*
|
||||||
|
* @param pageVO 请求
|
||||||
|
* @return 商机分页
|
||||||
|
*/
|
||||||
|
PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,11 @@ package cn.iocoder.yudao.module.crm.service.statistics;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticBusinessEndStatusRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelRespVO;
|
||||||
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper;
|
import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper;
|
||||||
@ -18,10 +21,15 @@ import jakarta.annotation.Resource;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRM 销售漏斗分析 Service 实现类
|
* CRM 销售漏斗分析 Service 实现类
|
||||||
@ -63,14 +71,13 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
|
|||||||
@Override
|
@Override
|
||||||
public List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO) {
|
public List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO) {
|
||||||
// 1. 获得用户编号数组
|
// 1. 获得用户编号数组
|
||||||
List<Long> userIds = getUserIds(reqVO);
|
reqVO.setUserIds(getUserIds(reqVO));
|
||||||
if (CollUtil.isEmpty(userIds)) {
|
if (CollUtil.isEmpty(reqVO.getUserIds())) {
|
||||||
return null;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
reqVO.setUserIds(userIds);
|
|
||||||
|
|
||||||
// 2.1 获得用户负责的商机
|
// 2.1 获得用户负责的商机
|
||||||
List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(userIds, reqVO.getTimes());
|
List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(reqVO.getUserIds(), reqVO.getTimes());
|
||||||
// 2.2 统计各阶段数据
|
// 2.2 统计各阶段数据
|
||||||
Map<Integer, List<CrmBusinessDO>> businessMap = convertMultiMap(businessList, CrmBusinessDO::getEndStatus);
|
Map<Integer, List<CrmBusinessDO>> businessMap = convertMultiMap(businessList, CrmBusinessDO::getEndStatus);
|
||||||
return convertList(CrmBusinessEndStatusEnum.values(), endStatusEnum -> {
|
return convertList(CrmBusinessEndStatusEnum.values(), endStatusEnum -> {
|
||||||
@ -83,6 +90,48 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CrmStatisticsBusinessSummaryByDateRespVO> getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO) {
|
||||||
|
// 1. 获得用户编号数组
|
||||||
|
reqVO.setUserIds(getUserIds(reqVO));
|
||||||
|
if (CollUtil.isEmpty(reqVO.getUserIds())) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 按天统计,获取分项统计数据
|
||||||
|
List<CrmStatisticsBusinessSummaryByDateRespVO> businessCreateCountList = funnelMapper.selectBusinessCreateCountGroupByDate(reqVO);
|
||||||
|
List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndDate(reqVO.getUserIds(), reqVO.getTimes());
|
||||||
|
Map<String, BigDecimal> businessDealCountMap = businessList.stream().collect(Collectors.groupingBy(business ->
|
||||||
|
business.getCreateTime().format(DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY)),
|
||||||
|
Collectors.reducing(BigDecimal.ZERO, CrmBusinessDO::getTotalPrice, BigDecimal::add)));
|
||||||
|
|
||||||
|
// 3. 按照日期间隔,合并数据
|
||||||
|
List<LocalDateTime[]> timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval());
|
||||||
|
return convertList(timeRanges, times -> {
|
||||||
|
Integer businessCreateCount = businessCreateCountList.stream()
|
||||||
|
.filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime()))
|
||||||
|
.mapToInt(CrmStatisticsBusinessSummaryByDateRespVO::getBusinessCreateCount).sum();
|
||||||
|
BigDecimal businessDealCount = businessDealCountMap.entrySet().stream()
|
||||||
|
.filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getKey()))
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
return new CrmStatisticsBusinessSummaryByDateRespVO()
|
||||||
|
.setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval()))
|
||||||
|
.setBusinessCreateCount(businessCreateCount).setBusinessDealCount(businessDealCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) {
|
||||||
|
// 1. 获得用户编号数组
|
||||||
|
pageVO.setUserIds(getUserIds(pageVO));
|
||||||
|
if (CollUtil.isEmpty(pageVO.getUserIds())) {
|
||||||
|
return PageResult.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return businessService.getBusinessPageByDate(pageVO.getUserIds(), pageVO.getTimes(), pageVO.getPageNo(), pageVO.getPageSize());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号
|
* 获取用户编号数组。如果用户编号为空, 则获得部门下的用户编号数组,包括子部门的所有用户编号
|
||||||
*
|
*
|
||||||
|
@ -2,4 +2,18 @@
|
|||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!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.CrmStatisticsFunnelMapper">
|
<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsFunnelMapper">
|
||||||
|
|
||||||
|
<select id="selectBusinessCreateCountGroupByDate"
|
||||||
|
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO">
|
||||||
|
SELECT DATE_FORMAT(create_time, '%Y-%m-%d') AS time, COUNT(*) AS businessCreateCount
|
||||||
|
FROM crm_business
|
||||||
|
WHERE deleted = 0
|
||||||
|
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 time
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
Loading…
Reference in New Issue
Block a user