package cn.iocoder.yudao.module.crm.api.report; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.crm.api.report.dto.CrmBusinessAnalyzeRespDTO; import cn.iocoder.yudao.module.crm.api.report.dto.CrmContractAnalyzeRespDTO; import cn.iocoder.yudao.module.crm.api.report.dto.CrmCustomerAnalyzeRespDTO; import cn.iocoder.yudao.module.crm.api.report.dto.CrmSalesFunnelRespDTO; import cn.iocoder.yudao.module.crm.api.report.dto.CrmSalesPerformanceRespDTO; import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper; import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper; import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService; 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 jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; /** * CRM 营销报表 API 实现类 * * @author 芋道源码 */ @RestController @RequestMapping(CrmReportApi.PREFIX) @Validated public class CrmReportApiImpl implements CrmReportApi { @Resource private CrmCustomerMapper customerMapper; @Resource private CrmBusinessMapper businessMapper; @Resource private CrmContractMapper contractMapper; @Resource private CrmReceivableService receivableService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override public CommonResult getCustomerAnalyze(LocalDateTime startTime, LocalDateTime endTime) { CrmCustomerAnalyzeRespDTO result = new CrmCustomerAnalyzeRespDTO(); // 客户总数 result.setTotalCount(customerMapper.selectCount()); // 今日新增 result.setTodayCount(customerMapper.selectTodayCount()); // 成交客户数 result.setDealCount(customerMapper.selectDealCount()); // 成交率 if (result.getTotalCount() > 0) { result.setDealRate(BigDecimal.valueOf(result.getDealCount()) .divide(BigDecimal.valueOf(result.getTotalCount()), 4, RoundingMode.HALF_UP) .multiply(BigDecimal.valueOf(100))); } else { result.setDealRate(BigDecimal.ZERO); } // 锁定客户数 result.setLockCount(customerMapper.selectLockCount()); // 公海客户数 result.setPoolCount(customerMapper.selectPoolCount()); return success(result); } @Override public CommonResult getBusinessAnalyze(LocalDateTime startTime, LocalDateTime endTime) { CrmBusinessAnalyzeRespDTO result = new CrmBusinessAnalyzeRespDTO(); // 商机总数 result.setTotalCount(businessMapper.selectCount()); // 今日新增 result.setTodayCount(businessMapper.selectTodayCount()); // 商机总金额 result.setTotalPrice(businessMapper.selectTotalPriceSum()); // 成交商机数 result.setSuccessCount(businessMapper.selectSuccessCount()); // 成交商机金额 result.setSuccessPrice(businessMapper.selectSuccessPriceSum()); // 商机转化率 if (result.getTotalCount() > 0) { result.setSuccessRate(BigDecimal.valueOf(result.getSuccessCount()) .divide(BigDecimal.valueOf(result.getTotalCount()), 4, RoundingMode.HALF_UP) .multiply(BigDecimal.valueOf(100))); } else { result.setSuccessRate(BigDecimal.ZERO); } // 进行中商机数 result.setProcessingCount(businessMapper.selectProcessingCount()); // 失败商机数 result.setFailCount(businessMapper.selectFailCount()); return success(result); } @Override public CommonResult getContractAnalyze(LocalDateTime startTime, LocalDateTime endTime) { CrmContractAnalyzeRespDTO result = new CrmContractAnalyzeRespDTO(); // 合同总数 result.setTotalCount(contractMapper.selectCount()); // 今日新增 result.setTodayCount(contractMapper.selectTodayCount()); // 合同总金额 result.setTotalPrice(contractMapper.selectTotalPriceSum()); // 审批通过合同数 result.setApproveCount(contractMapper.selectApproveCount()); // 审批通过合同金额 result.setApprovePrice(contractMapper.selectApprovePriceSum()); // 审批中合同数 result.setProcessCount(contractMapper.selectProcessCount()); // 已回款金额 BigDecimal receivablePrice = receivableService.getReceivablePriceSum(); result.setReceivablePrice(receivablePrice != null ? receivablePrice : BigDecimal.ZERO); // 回款率 if (result.getApprovePrice() != null && result.getApprovePrice().compareTo(BigDecimal.ZERO) > 0) { result.setReceivableRate(result.getReceivablePrice() .divide(result.getApprovePrice(), 4, RoundingMode.HALF_UP) .multiply(BigDecimal.valueOf(100))); } else { result.setReceivableRate(BigDecimal.ZERO); } return success(result); } @Override public CommonResult getSalesFunnel() { CrmSalesFunnelRespDTO result = new CrmSalesFunnelRespDTO(); List stages = new ArrayList<>(); // 阶段1:线索/客户 Long customerCount = customerMapper.selectCount(); stages.add(createStage("客户", customerCount, BigDecimal.ZERO)); // 阶段2:商机 Long businessCount = businessMapper.selectCount(); BigDecimal businessPrice = businessMapper.selectTotalPriceSum(); stages.add(createStage("商机", businessCount, businessPrice)); // 阶段3:合同 Long contractCount = contractMapper.selectApproveCount(); BigDecimal contractPrice = contractMapper.selectApprovePriceSum(); stages.add(createStage("合同", contractCount, contractPrice)); // 阶段4:回款 BigDecimal receivablePrice = receivableService.getReceivablePriceSum(); stages.add(createStage("回款", null, receivablePrice)); // 计算转化率 for (int i = 0; i < stages.size(); i++) { if (i == 0) { stages.get(i).setConversionRate(BigDecimal.valueOf(100)); } else if (customerCount > 0 && stages.get(i).getCount() != null) { stages.get(i).setConversionRate(BigDecimal.valueOf(stages.get(i).getCount()) .divide(BigDecimal.valueOf(customerCount), 4, RoundingMode.HALF_UP) .multiply(BigDecimal.valueOf(100))); } else { stages.get(i).setConversionRate(BigDecimal.ZERO); } } result.setStages(stages); return success(result); } @Override public CommonResult getSalesPerformance(LocalDateTime startTime, LocalDateTime endTime) { CrmSalesPerformanceRespDTO result = new CrmSalesPerformanceRespDTO(); List items = new ArrayList<>(); // 获取所有销售人员(有合同或商机的负责人) List userIds = contractMapper.selectOwnerUserIds(); userIds.addAll(businessMapper.selectOwnerUserIds()); userIds = userIds.stream().distinct().collect(Collectors.toList()); if (CollUtil.isEmpty(userIds)) { result.setItems(items); return success(result); } // 获取用户信息 Map userMap = adminUserApi.getUserMap(userIds); // 获取部门信息 List deptIds = userMap.values().stream() .map(AdminUserRespDTO::getDeptId) .filter(id -> id != null) .distinct() .collect(Collectors.toList()); Map deptMap = deptApi.getDeptMap(deptIds); for (Long userId : userIds) { AdminUserRespDTO user = userMap.get(userId); if (user == null) { continue; } CrmSalesPerformanceRespDTO.SalesItem item = new CrmSalesPerformanceRespDTO.SalesItem(); item.setUserId(userId); item.setUserName(user.getNickname()); // 获取部门名称 if (user.getDeptId() != null) { DeptRespDTO dept = deptMap.get(user.getDeptId()); item.setDeptName(dept != null ? dept.getName() : ""); } // 合同数量和金额 item.setContractCount(contractMapper.selectCountByOwnerUserId(userId)); item.setContractPrice(contractMapper.selectPriceSumByOwnerUserId(userId)); // 回款金额 item.setReceivablePrice(receivableService.getReceivablePriceByOwnerUserId(userId)); // 商机数量和金额 item.setBusinessCount(businessMapper.selectCountByOwnerUserId(userId)); item.setBusinessPrice(businessMapper.selectPriceSumByOwnerUserId(userId)); items.add(item); } result.setItems(items); return success(result); } private CrmSalesFunnelRespDTO.FunnelStage createStage(String name, Long count, BigDecimal price) { CrmSalesFunnelRespDTO.FunnelStage stage = new CrmSalesFunnelRespDTO.FunnelStage(); stage.setName(name); stage.setCount(count); stage.setPrice(price != null ? price : BigDecimal.ZERO); return stage; } }