package cn.iocoder.yudao.module.srm.service.statistics; import cn.iocoder.yudao.module.srm.controller.admin.statistics.vo.SrmTenderStatisticsRespVO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmBidAwardDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderBidDO; import cn.iocoder.yudao.module.srm.dal.dataobject.SrmTenderProjectDO; import cn.iocoder.yudao.module.srm.dal.mysql.SrmBidAwardMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderBidMapper; import cn.iocoder.yudao.module.srm.dal.mysql.SrmTenderProjectMapper; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; import java.util.stream.Collectors; @Service public class SrmStatisticsServiceImpl implements SrmStatisticsService { @Resource private SrmTenderProjectMapper tenderProjectMapper; @Resource private SrmTenderBidMapper tenderBidMapper; @Resource private SrmBidAwardMapper bidAwardMapper; @Override public SrmTenderStatisticsRespVO getTenderStatistics(String year) { // 查询当年所有招标项目 List projects = tenderProjectMapper.selectList( new LambdaQueryWrapperX() .apply("YEAR(create_time) = {0}", year)); // 查询当年所有定标记录 List awards = bidAwardMapper.selectList( new LambdaQueryWrapperX() .apply("YEAR(create_time) = {0}", year)); // 查询当年所有投标供应商数(去重) List bids = tenderBidMapper.selectList( new LambdaQueryWrapperX() .apply("YEAR(create_time) = {0}", year)); long totalTenderCount = projects.size(); //招标总金额(预算金额) BigDecimal totalTenderAmount = projects.stream() .map(p -> p.getBudgetAmount() != null ? p.getBudgetAmount() : BigDecimal.ZERO) .reduce(BigDecimal.ZERO, BigDecimal::add); //定标总金额(中标金额) BigDecimal totalAwardAmount = awards.stream() .map(a -> a.getAwardAmount() != null ? a.getAwardAmount() : BigDecimal.ZERO) .reduce(BigDecimal.ZERO, BigDecimal::add); // 节约金额(仅计算当年定标的项目的:预算金额 - 中标总金额) BigDecimal savedAmount = BigDecimal.ZERO; if (!awards.isEmpty()) { // 按项目分组汇总中标金额(处理一个项目可能有多个定标记录的情况) java.util.Map projectAwardSumMap = awards.stream() .collect(Collectors.groupingBy( SrmBidAwardDO::getTenderProjectId, Collectors.reducing( BigDecimal.ZERO, a -> a.getAwardAmount() != null ? a.getAwardAmount() : BigDecimal.ZERO, BigDecimal::add ) )); List awardedProjectIds = new java.util.ArrayList<>(projectAwardSumMap.keySet()); if (!awardedProjectIds.isEmpty()) { List awardedProjects = tenderProjectMapper.selectBatchIds(awardedProjectIds); for (SrmTenderProjectDO project : awardedProjects) { BigDecimal budget = project.getBudgetAmount() != null ? project.getBudgetAmount() : BigDecimal.ZERO; // 处理数据异常:如果项目预算为 0 或空,直接跳过该项目的节约金额计算,避免由于缺失预算导致出现不合理的巨大负数节约金额 if (budget.compareTo(BigDecimal.ZERO) > 0) { BigDecimal awardSum = projectAwardSumMap.getOrDefault(project.getId(), BigDecimal.ZERO); savedAmount = savedAmount.add(budget.subtract(awardSum)); } } } } long supplierCount = bids.stream() .map(SrmTenderBidDO::getSupplierId) .distinct() .count(); // 定标率 (当年创建的项目中,目前已经定标的项目数 / 当年创建的项目总数) BigDecimal winRate = BigDecimal.ZERO; if (totalTenderCount > 0) { List projectIds = projects.stream().map(SrmTenderProjectDO::getId).collect(Collectors.toList()); long awardedCount = 0; if (!projectIds.isEmpty()) { List matchedAwards = bidAwardMapper.selectList(new LambdaQueryWrapperX() .in(SrmBidAwardDO::getTenderProjectId, projectIds) .select(SrmBidAwardDO::getTenderProjectId)); awardedCount = matchedAwards.stream() .map(SrmBidAwardDO::getTenderProjectId) .distinct() .count(); } winRate = BigDecimal.valueOf(awardedCount) .multiply(BigDecimal.valueOf(100)) .divide(BigDecimal.valueOf(totalTenderCount), 1, RoundingMode.HALF_UP); } SrmTenderStatisticsRespVO vo = new SrmTenderStatisticsRespVO(); vo.setTotalTenderCount(totalTenderCount); vo.setTotalTenderAmount(totalTenderAmount); vo.setTotalAwardAmount(totalAwardAmount); vo.setSavedAmount(savedAmount); vo.setWinRate(winRate); vo.setSupplierCount(supplierCount); vo.setPeriod(year); return vo; } }