package cn.iocoder.yudao.module.mes.service.qc.statistics; import cn.iocoder.yudao.module.mes.controller.admin.qc.statistics.vo.MesQcStatisticsByProcessVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.statistics.vo.MesQcStatisticsByWorkOrderVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.statistics.vo.MesQcStatisticsOverallVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.statistics.vo.MesQcStatisticsRespVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.statistics.vo.MesQcStatisticsTypeVO; import cn.iocoder.yudao.module.mes.dal.mysql.qc.statistics.MesQcStatisticsMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * MES 质量统计 Service 实现类 * * @author 超级管理员 */ @Service @Validated public class MesQcStatisticsServiceImpl implements MesQcStatisticsService { /** * 固定输出顺序与名称:IQC / IPQC / OQC / RQC,无数据的类型也要返回 0 */ private static final Map QC_TYPE_NAMES = Map.of( "IQC", "来料检验", "IPQC", "过程检验", "OQC", "出货检验", "RQC", "退货检验"); private static final List QC_TYPE_ORDER = List.of("IQC", "IPQC", "OQC", "RQC"); @Resource private MesQcStatisticsMapper statisticsMapper; @Override public MesQcStatisticsRespVO getStatisticsSummary(LocalDateTime beginTime, LocalDateTime endTime) { return new MesQcStatisticsRespVO() .setOverall(buildOverall(beginTime, endTime)) .setByProcess(buildByProcess(beginTime, endTime)) .setByWorkOrder(buildByWorkOrder(beginTime, endTime)); } private MesQcStatisticsOverallVO buildOverall(LocalDateTime beginTime, LocalDateTime endTime) { Map typeMap = new HashMap<>(); for (MesQcStatisticsTypeVO row : statisticsMapper.selectTypeStatistics(beginTime, endTime)) { typeMap.put(row.getQcType(), row); } long totalQcCount = 0L; BigDecimal totalCheckQuantity = BigDecimal.ZERO; BigDecimal totalQualifiedQuantity = BigDecimal.ZERO; BigDecimal totalUnqualifiedQuantity = BigDecimal.ZERO; List types = new ArrayList<>(QC_TYPE_ORDER.size()); for (String qcType : QC_TYPE_ORDER) { MesQcStatisticsTypeVO type = typeMap.get(qcType); if (type == null) { type = new MesQcStatisticsTypeVO().setQcType(qcType); } type.setQcTypeName(QC_TYPE_NAMES.get(qcType)); type.setQcCount(defaultZero(type.getQcCount())); type.setCheckQuantity(defaultZero(type.getCheckQuantity())); type.setQualifiedQuantity(defaultZero(type.getQualifiedQuantity())); type.setUnqualifiedQuantity(defaultZero(type.getUnqualifiedQuantity())); type.setQualifiedRate(calculateRate(type.getQualifiedQuantity(), type.getCheckQuantity())); type.setUnqualifiedRate(calculateRate(type.getUnqualifiedQuantity(), type.getCheckQuantity())); types.add(type); totalQcCount += type.getQcCount(); totalCheckQuantity = totalCheckQuantity.add(type.getCheckQuantity()); totalQualifiedQuantity = totalQualifiedQuantity.add(type.getQualifiedQuantity()); totalUnqualifiedQuantity = totalUnqualifiedQuantity.add(type.getUnqualifiedQuantity()); } return new MesQcStatisticsOverallVO() .setTotalQcCount(totalQcCount) .setCheckQuantity(totalCheckQuantity) .setQualifiedQuantity(totalQualifiedQuantity) .setUnqualifiedQuantity(totalUnqualifiedQuantity) .setQualifiedRate(calculateRate(totalQualifiedQuantity, totalCheckQuantity)) .setUnqualifiedRate(calculateRate(totalUnqualifiedQuantity, totalCheckQuantity)) .setTypes(types); } private List buildByProcess(LocalDateTime beginTime, LocalDateTime endTime) { List list = statisticsMapper.selectStatisticsByProcess(beginTime, endTime); for (MesQcStatisticsByProcessVO row : list) { row.setCheckQuantity(defaultZero(row.getCheckQuantity())); row.setQualifiedQuantity(defaultZero(row.getQualifiedQuantity())); row.setUnqualifiedQuantity(defaultZero(row.getUnqualifiedQuantity())); row.setQualifiedRate(calculateRate(row.getQualifiedQuantity(), row.getCheckQuantity())); } return list; } private List buildByWorkOrder(LocalDateTime beginTime, LocalDateTime endTime) { List list = statisticsMapper.selectStatisticsByWorkOrder(beginTime, endTime); for (MesQcStatisticsByWorkOrderVO row : list) { row.setCheckQuantity(defaultZero(row.getCheckQuantity())); row.setQualifiedQuantity(defaultZero(row.getQualifiedQuantity())); row.setUnqualifiedQuantity(defaultZero(row.getUnqualifiedQuantity())); row.setQualifiedRate(calculateRate(row.getQualifiedQuantity(), row.getCheckQuantity())); } return list; } private static Long defaultZero(Long value) { return value == null ? 0L : value; } private static BigDecimal defaultZero(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; } /** * 计算百分比,保留两位小数;分母为空或 0 时返回 0.00,避免除零 */ private static BigDecimal calculateRate(BigDecimal part, BigDecimal total) { if (part == null || total == null || total.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); } return part.multiply(BigDecimal.valueOf(100)) .divide(total, 2, RoundingMode.HALF_UP); } }