mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	CRM: 完善销售漏斗
This commit is contained in:
		| @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.CrmBusinessController; | ||||
| 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.CrmStatisticFunnelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelSummaryRespVO; | ||||
| 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.dal.dataobject.business.CrmBusinessDO; | ||||
| @@ -31,37 +31,35 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||
| @Validated | ||||
| public class CrmStatisticsFunnelController { | ||||
|  | ||||
|     // TODO @puhui999:crmStatisticsFunnelService 改成 funnelService 更好点哈 | ||||
|     @Resource | ||||
|     private CrmStatisticsFunnelService crmStatisticsFunnelService; | ||||
|     private CrmStatisticsFunnelService funnelService; | ||||
|  | ||||
|     @GetMapping("/get-funnel-summary") | ||||
|     @Operation(summary = "获取销售漏斗统计数据", description = "用于【销售漏斗】页面的【销售漏斗分析】") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") | ||||
|     public CommonResult<CrmStatisticFunnelRespVO> getFunnelSummary(@Valid CrmStatisticsFunnelReqVO reqVO) { | ||||
|         return success(crmStatisticsFunnelService.getFunnelSummary(reqVO)); | ||||
|     public CommonResult<CrmStatisticFunnelSummaryRespVO> getFunnelSummary(@Valid CrmStatisticsFunnelReqVO reqVO) { | ||||
|         return success(funnelService.getFunnelSummary(reqVO)); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui:这个接口,应该是 getBusinessSummaryByEndStatus?这样更统一哈; | ||||
|     @GetMapping("/get-business-end-status-summary") | ||||
|     @GetMapping("/get-business-summary-by-end-status") | ||||
|     @Operation(summary = "获取商机结束状态统计", description = "用于【销售漏斗】页面的【销售漏斗分析】") | ||||
|     @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") | ||||
|     public CommonResult<List<CrmStatisticBusinessEndStatusRespVO>> getBusinessEndStatusSummary(@Valid CrmStatisticsFunnelReqVO reqVO) { | ||||
|         return success(crmStatisticsFunnelService.getBusinessEndStatusSummary(reqVO)); | ||||
|     public CommonResult<List<CrmStatisticsBusinessSummaryByEndStatusRespVO>> getBusinessSummaryByEndStatus(@Valid CrmStatisticsFunnelReqVO reqVO) { | ||||
|         return success(funnelService.getBusinessSummaryByEndStatus(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)); | ||||
|         return success(funnelService.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); | ||||
|         PageResult<CrmBusinessDO> pageResult = funnelService.getBusinessPageByDate(pageVO); | ||||
|         return success(new PageResult<>(buildBusinessDetailList(pageResult.getList()), pageResult.getTotal())); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -5,12 +5,11 @@ import lombok.AllArgsConstructor; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| 
 | ||||
| // TODO @puhui999:改成 CrmStatisticFunnelSummaryRespVO 更有统计的味道 | ||||
| @Schema(description = "管理后台 - CRM 销售漏斗 Response VO") | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| @Data | ||||
| public class CrmStatisticFunnelRespVO { | ||||
| public class CrmStatisticFunnelSummaryRespVO { | ||||
| 
 | ||||
|     @Schema(description = "客户数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Long customerCount; | ||||
| @@ -18,8 +17,7 @@ public class CrmStatisticFunnelRespVO { | ||||
|     @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Long businessCount; | ||||
| 
 | ||||
|     // TODO @puhui999:这个改成 businessWinCount 可能会更合适点哈; | ||||
|     @Schema(description = "赢单数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Long winCount; | ||||
|     private Long businessWinCount; | ||||
| 
 | ||||
| } | ||||
| @@ -1,107 +0,0 @@ | ||||
| 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.Data; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.time.LocalDateTime; | ||||
|  | ||||
| // TODO @puhui999:是不是可以删除哈? | ||||
| @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; | ||||
|  | ||||
| } | ||||
| @@ -15,8 +15,7 @@ public class CrmStatisticsBusinessSummaryByDateRespVO { | ||||
|     @Schema(description = "新增商机数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer businessCreateCount; | ||||
|  | ||||
|     // TODO @puhui999:是不是金额哈,不是数量 | ||||
|     @Schema(description = "新增商机金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private BigDecimal businessDealCount; | ||||
|     private BigDecimal totalPrice; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -7,12 +7,11 @@ import lombok.NoArgsConstructor; | ||||
| 
 | ||||
| import java.math.BigDecimal; | ||||
| 
 | ||||
| // TODO @puhui999:改成 CrmStatisticsBusinessSummaryByEndStatusRespVO,按照结束状态 | ||||
| @Schema(description = "管理后台 - CRM 商机结束状态统计 Response VO") | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| @Data | ||||
| public class CrmStatisticBusinessEndStatusRespVO { | ||||
| public class CrmStatisticsBusinessSummaryByEndStatusRespVO { | ||||
| 
 | ||||
|     @Schema(description = "结束状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
|     private Integer endStatus; | ||||
| @@ -5,9 +5,8 @@ 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 jakarta.validation.constraints.NotNull; | ||||
| import jakarta.validation.constraints.Size; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
| import org.springframework.format.annotation.DateTimeFormat; | ||||
|  | ||||
| import java.time.LocalDateTime; | ||||
| @@ -17,9 +16,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ | ||||
|  | ||||
| @Schema(description = "管理后台 - CRM 销售漏斗 Request VO") | ||||
| @Data | ||||
| // TODO @puhui999:不用写 EqualsAndHashCode、ToString,已经全局 lombok 啦 | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class CrmStatisticsFunnelReqVO extends PageParam { | ||||
|  | ||||
|     @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||
| @@ -43,13 +39,9 @@ public class CrmStatisticsFunnelReqVO extends PageParam { | ||||
|     @InEnum(value = DateIntervalEnum.class, message = "时间间隔类型,必须是 {value}") | ||||
|     private Integer interval; | ||||
|  | ||||
|     // TODO @puhui999:这个全部前端传递哈;参考 CrmStatisticsCustomerReqVO | ||||
|     /** | ||||
|      * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间 | ||||
|      * 并作为参数传递给Mapper | ||||
|      */ | ||||
|     @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|     @Size(min = 2, max = 2, message = "请选择时间范围") | ||||
|     private LocalDateTime[] times; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.portrait; | ||||
|  | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import jakarta.validation.constraints.Size; | ||||
| import lombok.Data; | ||||
| import org.springframework.format.annotation.DateTimeFormat; | ||||
|  | ||||
| @@ -31,12 +32,9 @@ public class CrmStatisticsPortraitReqVO { | ||||
|     @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") | ||||
|     private List<Long> userIds; | ||||
|  | ||||
|     /** | ||||
|      * 前端如果选择自定义时间, 那么前端传递起始-终止时间, 如果选择其他时间间隔类型, 则由后台计算起始-终止时间 | ||||
|      * 并作为参数传递给Mapper | ||||
|      */ | ||||
|     @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED) | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|     @Size(min = 2, max = 2, message = "请选择时间范围") | ||||
|     private LocalDateTime[] times; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,17 @@ | ||||
| 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.mybatis.core.mapper.BaseMapperX; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; | ||||
| 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.enums.common.CrmBizTypeEnum; | ||||
| import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils; | ||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
|  | ||||
| import java.time.LocalDateTime; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
|  | ||||
| @@ -66,32 +65,10 @@ public interface CrmBusinessMapper extends BaseMapperX<CrmBusinessDO> { | ||||
|                 .eq(CrmBusinessDO::getOwnerUserId, ownerUserId)); | ||||
|     } | ||||
|  | ||||
|     default Long selectCountByOwnerUserIdsAndEndStatus(Collection<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus) { | ||||
|         return selectCount(new LambdaQueryWrapperX<CrmBusinessDO>() | ||||
|                 .in(CrmBusinessDO::getOwnerUserId, ownerUserIds) | ||||
|                 .eqIfPresent(CrmBusinessDO::getEndStatus, endStatus) | ||||
|                 .betweenIfPresent(CrmBusinessDO::getCreateTime, times)); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     default List<CrmBusinessDO> selectListByOwnerUserIdsAndEndStatusNotNull(Collection<Long> ownerUserIds, LocalDateTime[] times) { | ||||
|         return selectList(new LambdaQueryWrapperX<CrmBusinessDO>() | ||||
|                 .in(CrmBusinessDO::getOwnerUserId, ownerUserIds) | ||||
|                 .betweenIfPresent(CrmBusinessDO::getCreateTime, times) | ||||
|                 .isNotNull(CrmBusinessDO::getEndStatus)); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     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)); | ||||
|     default PageResult<CrmBusinessDO> selectPage(CrmStatisticsFunnelReqVO pageVO) { | ||||
|         return selectPage(pageVO, new LambdaQueryWrapperX<CrmBusinessDO>() | ||||
|                 .in(CrmBusinessDO::getOwnerUserId, pageVO.getUserIds()) | ||||
|                 .betweenIfPresent(CrmBusinessDO::getCreateTime, pageVO.getTimes())); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -186,11 +186,4 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> { | ||||
|         return selectCount(query); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     default Long selectCountByOwnerUserIds(Collection<Long> ownerUserIds, LocalDateTime[] times){ | ||||
|         return selectCount(new LambdaQueryWrapperX<CrmCustomerDO>() | ||||
|                 .in(CrmCustomerDO::getOwnerUserId, ownerUserIds) | ||||
|                 .betweenIfPresent(CrmCustomerDO::getCreateTime, times)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| 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.CrmStatisticsBusinessSummaryByEndStatusRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
| import org.apache.ibatis.annotations.Param; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @@ -15,6 +16,12 @@ import java.util.List; | ||||
| @Mapper | ||||
| public interface CrmStatisticsFunnelMapper { | ||||
|  | ||||
|     List<CrmStatisticsBusinessSummaryByDateRespVO> selectBusinessCreateCountGroupByDate(CrmStatisticsFunnelReqVO reqVO); | ||||
|     Long selectCustomerCountByDate(CrmStatisticsFunnelReqVO reqVO); | ||||
|  | ||||
|     Long selectBusinessCountByDateAndEndStatus(@Param("reqVO") CrmStatisticsFunnelReqVO reqVO, @Param("status") Integer status); | ||||
|  | ||||
|     List<CrmStatisticsBusinessSummaryByEndStatusRespVO> selectBusinessSummaryListGroupByEndStatus(CrmStatisticsFunnelReqVO reqVO); | ||||
|  | ||||
|     List<CrmStatisticsBusinessSummaryByDateRespVO> selectBusinessSummaryGroupByDate(CrmStatisticsFunnelReqVO reqVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO; | ||||
| 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.CrmBusinessProductDO; | ||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; | ||||
| @@ -194,45 +195,12 @@ public interface CrmBusinessService { | ||||
|      */ | ||||
|     List<CrmBusinessDO> getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId); | ||||
|  | ||||
|     /** | ||||
|      * 获得商机数 | ||||
|      * | ||||
|      * @param ownerUserIds 负责人编号 | ||||
|      * @param times        时间范围 | ||||
|      * @param endStatus    商机结束状态,允许为空 | ||||
|      * @return 商机数 | ||||
|      */ | ||||
|     Long getBusinessCountByOwnerUserIdsAndEndStatus(List<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus); | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     /** | ||||
|      * 获得商机列表【数据统计】 | ||||
|      * | ||||
|      * @param ownerUserIds 负责人编号 | ||||
|      * @param times        时间范围 | ||||
|      * @return 商机列表 | ||||
|      */ | ||||
|     List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times); | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     /** | ||||
|      * 获得商机列表【数据统计】 | ||||
|      * | ||||
|      * @param ownerUserIds 负责人编号 | ||||
|      * @param times        时间范围 | ||||
|      * @return 商机列表 | ||||
|      */ | ||||
|     List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndDate(List<Long> ownerUserIds, LocalDateTime[] times); | ||||
|  | ||||
|     /** | ||||
|      * 获得商机分页,目前用于【数据统计】 | ||||
|      * | ||||
|      * @param ownerUserIds 负责人编号 | ||||
|      * @param times        时间范围 | ||||
|      * @param pageNo       页码 TODO @puhui999:直接传递 CrmStatisticsFunnelReqVO 吧,虽然有点耦合,但是更清晰一点; | ||||
|      * @param pageSize     数量 | ||||
|      * @param pageVO 请求 | ||||
|      * @return 商机分页 | ||||
|      */ | ||||
|     PageResult<CrmBusinessDO> getBusinessPageByDate(List<Long> ownerUserIds, LocalDateTime[] times, Integer pageNo, Integer pageSize); | ||||
|     PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateStatusReqVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO; | ||||
| 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.CrmBusinessProductDO; | ||||
| import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; | ||||
| @@ -376,35 +377,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Long getBusinessCountByOwnerUserIdsAndEndStatus(List<Long> ownerUserIds, LocalDateTime[] times, Integer endStatus) { | ||||
|         if (CollUtil.isEmpty(ownerUserIds)) { | ||||
|             return 0L; | ||||
|         } | ||||
|         return businessMapper.selectCountByOwnerUserIdsAndEndStatus(convertSet(ownerUserIds), times, endStatus); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     @Override | ||||
|     public List<CrmBusinessDO> getBusinessListByOwnerUserIdsAndEndStatusNotNull(List<Long> ownerUserIds, LocalDateTime[] times) { | ||||
|         if (CollUtil.isEmpty(ownerUserIds)) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|         return businessMapper.selectListByOwnerUserIdsAndEndStatusNotNull(convertSet(ownerUserIds), times); | ||||
|     } | ||||
|  | ||||
|     // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|     @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); | ||||
|     public PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) { | ||||
|         return businessMapper.selectPage(pageVO); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -195,13 +195,4 @@ public interface CrmCustomerService { | ||||
|      */ | ||||
|     int autoPutCustomerPool(); | ||||
|  | ||||
|     /** | ||||
|      * 获得客户数 | ||||
|      * | ||||
|      * @param ownerUserIds 负责人编号 | ||||
|      * @param times        时间范围 | ||||
|      * @return 客户数 | ||||
|      */ | ||||
|     Long getCustomerCountByOwnerUserIds(List<Long> ownerUserIds, LocalDateTime[] times); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -651,14 +651,6 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Long getCustomerCountByOwnerUserIds(List<Long> ownerUserIds, LocalDateTime[] times) { | ||||
|         if (CollUtil.isEmpty(ownerUserIds)) { | ||||
|             return 0L; | ||||
|         } | ||||
|         return customerMapper.selectCountByOwnerUserIds(convertSet(ownerUserIds), times); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获得自身的代理对象,解决 AOP 生效问题 | ||||
|      * | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| 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.CrmStatisticFunnelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelSummaryRespVO; | ||||
| 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.dal.dataobject.business.CrmBusinessDO; | ||||
| @@ -22,7 +22,7 @@ public interface CrmStatisticsFunnelService { | ||||
|      * @param reqVO 请求 | ||||
|      * @return 销售漏斗数据 | ||||
|      */ | ||||
|     CrmStatisticFunnelRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO); | ||||
|     CrmStatisticFunnelSummaryRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获得商机结束状态统计 | ||||
| @@ -30,7 +30,7 @@ public interface CrmStatisticsFunnelService { | ||||
|      * @param reqVO 请求 | ||||
|      * @return 商机结束状态统计 | ||||
|      */ | ||||
|     List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO); | ||||
|     List<CrmStatisticsBusinessSummaryByEndStatusRespVO> getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获取新增商机分析(按日期) | ||||
|   | ||||
| @@ -4,15 +4,14 @@ import cn.hutool.core.collection.CollUtil; | ||||
| 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.CrmStatisticFunnelRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticFunnelSummaryRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO; | ||||
| import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO; | ||||
| 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.mysql.statistics.CrmStatisticsFunnelMapper; | ||||
| import cn.iocoder.yudao.module.crm.enums.business.CrmBusinessEndStatusEnum; | ||||
| import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; | ||||
| import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; | ||||
| 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; | ||||
| @@ -22,14 +21,10 @@ import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.time.LocalDateTime; | ||||
| import java.time.format.DateTimeFormatter; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| 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.date.DateUtils.FORMAT_YEAR_MONTH_DAY; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||||
|  | ||||
| /** | ||||
|  * CRM 销售漏斗分析 Service 实现类 | ||||
| @@ -45,15 +40,12 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic | ||||
|     @Resource | ||||
|     private AdminUserApi adminUserApi; | ||||
|     @Resource | ||||
|     private CrmCustomerService customerService; | ||||
|     @Resource | ||||
|     private CrmBusinessService businessService; | ||||
|     @Resource | ||||
|     private DeptApi deptApi; | ||||
|  | ||||
|     // TODO @puhui999:貌似想了下,可能还是得按照;;; | ||||
|     @Override | ||||
|     public CrmStatisticFunnelRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO) { | ||||
|     public CrmStatisticFunnelSummaryRespVO getFunnelSummary(CrmStatisticsFunnelReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         List<Long> userIds = getUserIds(reqVO); | ||||
|         if (CollUtil.isEmpty(userIds)) { | ||||
| @@ -62,34 +54,22 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic | ||||
|         reqVO.setUserIds(userIds); | ||||
|  | ||||
|         // 2. 获得漏斗数据 | ||||
|         return new CrmStatisticFunnelRespVO( | ||||
|                 customerService.getCustomerCountByOwnerUserIds(userIds, reqVO.getTimes()), | ||||
|                 businessService.getBusinessCountByOwnerUserIdsAndEndStatus(userIds, reqVO.getTimes(), null), | ||||
|                 businessService.getBusinessCountByOwnerUserIdsAndEndStatus(userIds, reqVO.getTimes(), CrmBusinessEndStatusEnum.WIN.getStatus()) | ||||
|         ); | ||||
|         Long customerCount = funnelMapper.selectCustomerCountByDate(reqVO); | ||||
|         Long businessCount = funnelMapper.selectBusinessCountByDateAndEndStatus(reqVO, null); | ||||
|         Long businessWinCount = funnelMapper.selectBusinessCountByDateAndEndStatus(reqVO, CrmBusinessEndStatusEnum.WIN.getStatus()); | ||||
|         return new CrmStatisticFunnelSummaryRespVO(customerCount, businessCount, businessWinCount); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<CrmStatisticBusinessEndStatusRespVO> getBusinessEndStatusSummary(CrmStatisticsFunnelReqVO reqVO) { | ||||
|     public List<CrmStatisticsBusinessSummaryByEndStatusRespVO> getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO) { | ||||
|         // 1. 获得用户编号数组 | ||||
|         reqVO.setUserIds(getUserIds(reqVO)); | ||||
|         if (CollUtil.isEmpty(reqVO.getUserIds())) { | ||||
|             return Collections.emptyList(); | ||||
|         } | ||||
|  | ||||
|         // TODO @puhui999:这个可以优化下,通过统计 sql,不通过内存计算; | ||||
|         // 2.1 获得用户负责的商机 | ||||
|         List<CrmBusinessDO> businessList = businessService.getBusinessListByOwnerUserIdsAndEndStatusNotNull(reqVO.getUserIds(), reqVO.getTimes()); | ||||
|         // 2.2 统计各阶段数据 | ||||
|         Map<Integer, List<CrmBusinessDO>> businessMap = convertMultiMap(businessList, CrmBusinessDO::getEndStatus); | ||||
|         return convertList(CrmBusinessEndStatusEnum.values(), endStatusEnum -> { | ||||
|             List<CrmBusinessDO> list = businessMap.get(endStatusEnum.getStatus()); | ||||
|             if (CollUtil.isEmpty(list)) { | ||||
|                 return new CrmStatisticBusinessEndStatusRespVO(endStatusEnum.getStatus(), 0L, BigDecimal.ZERO); | ||||
|             } | ||||
|             return new CrmStatisticBusinessEndStatusRespVO(endStatusEnum.getStatus(), (long) list.size(), | ||||
|                     getSumValue(list, CrmBusinessDO::getTotalPrice, BigDecimal::add)); | ||||
|         }); | ||||
|         // 2. 获得统计数据 | ||||
|         return funnelMapper.selectBusinessSummaryListGroupByEndStatus(reqVO); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -101,26 +81,20 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic | ||||
|         } | ||||
|  | ||||
|         // 2. 按天统计,获取分项统计数据 | ||||
|         // TODO @puhui999:可以这个统计,返回的时候,就把数量、金额一起统计好; | ||||
|         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))); | ||||
|  | ||||
|         List<CrmStatisticsBusinessSummaryByDateRespVO> businessSummaryList = funnelMapper.selectBusinessSummaryGroupByDate(reqVO); | ||||
|         // 3. 按照日期间隔,合并数据 | ||||
|         List<LocalDateTime[]> timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); | ||||
|         return convertList(timeRanges, times -> { | ||||
|             Integer businessCreateCount = businessCreateCountList.stream() | ||||
|             Integer businessCreateCount = businessSummaryList.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) | ||||
|             BigDecimal businessDealCount = businessSummaryList.stream() | ||||
|                     .filter(vo -> LocalDateTimeUtils.isBetween(times[0], times[1], vo.getTime())) | ||||
|                     .map(CrmStatisticsBusinessSummaryByDateRespVO::getTotalPrice) | ||||
|                     .reduce(BigDecimal.ZERO, BigDecimal::add); | ||||
|             return new CrmStatisticsBusinessSummaryByDateRespVO() | ||||
|                     .setTime(LocalDateTimeUtils.formatDateRange(times[0], times[1], reqVO.getInterval())) | ||||
|                     .setBusinessCreateCount(businessCreateCount).setBusinessDealCount(businessDealCount); | ||||
|                     .setBusinessCreateCount(businessCreateCount).setTotalPrice(businessDealCount); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -132,7 +106,7 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic | ||||
|             return PageResult.empty(); | ||||
|         } | ||||
|         // 2. 执行查询 | ||||
|         return businessService.getBusinessPageByDate(pageVO.getUserIds(), pageVO.getTimes(), pageVO.getPageNo(), pageVO.getPageSize()); | ||||
|         return businessService.getBusinessPageByDate(pageVO); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -2,18 +2,61 @@ | ||||
| <!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"> | ||||
|  | ||||
|     <select id="selectBusinessCreateCountGroupByDate" | ||||
|     <select id="selectCustomerCountByDate" resultType="java.lang.Long"> | ||||
|         SELECT COUNT(*) | ||||
|         FROM crm_customer | ||||
|         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} | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectBusinessCountByDateAndEndStatus" resultType="java.lang.Long"> | ||||
|         SELECT COUNT(*) | ||||
|         FROM crm_business | ||||
|         WHERE deleted = 0 | ||||
|         <if test="status != null"> | ||||
|             AND end_status = #{status} | ||||
|         </if> | ||||
|         AND owner_user_id IN | ||||
|         <foreach collection="reqVO.userIds" item="userId" open="(" close=")" separator=","> | ||||
|             #{userId} | ||||
|         </foreach> | ||||
|         AND create_time BETWEEN #{reqVO.times[0],javaType=java.time.LocalDateTime} AND | ||||
|         #{reqVO.times[1],javaType=java.time.LocalDateTime} | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectBusinessSummaryListGroupByEndStatus" | ||||
|             resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO"> | ||||
|         SELECT end_status AS endStatus,COUNT(*) AS businessCount, SUM(total_price) AS totalPrice | ||||
|         FROM crm_business | ||||
|         WHERE deleted = 0 AND end_status IS NOT NULL | ||||
|         AND owner_user_id IN | ||||
|         <foreach collection="userIds" item="userId" open="(" close=")" separator=","> | ||||
|             #{userId} | ||||
|         </foreach> | ||||
|         AND create_time BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND | ||||
|         #{times[1],javaType=java.time.LocalDateTime} | ||||
|         GROUP BY end_status | ||||
|     </select> | ||||
|  | ||||
|     <select id="selectBusinessSummaryGroupByDate" | ||||
|             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 | ||||
|         DATE_FORMAT(create_time, '%Y-%m-%d') AS time, | ||||
|         COUNT(*) AS businessCreateCount, | ||||
|         SUM(total_price) AS totalPrice | ||||
|         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} | ||||
|         <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> | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 puhui999
					puhui999