package cn.iocoder.yudao.module.mes.service.qc.indicatorresult;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.iocoder.yudao.module.mes.controller.admin.qc.indicatorresult.vo.MesQcQcReportRespVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDetailDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcIndicatorItemTypeEnum;
|
import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
|
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
|
import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
|
import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
|
import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService;
|
import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService;
|
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.context.annotation.Lazy;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Comparator;
|
import java.util.HashSet;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
|
/**
|
* MES 检验报告单 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesQcReportServiceImpl implements MesQcReportService {
|
|
@Resource
|
private MesQcIndicatorResultService resultService;
|
@Resource
|
private MesQcIndicatorService indicatorService;
|
|
@Resource
|
private MesQcIqcService iqcService;
|
@Resource
|
private MesQcIqcLineService iqcLineService;
|
@Resource
|
@Lazy
|
private MesQcIpqcService ipqcService;
|
@Resource
|
@Lazy
|
private MesQcIpqcLineService ipqcLineService;
|
@Resource
|
@Lazy
|
private MesQcOqcService oqcService;
|
@Resource
|
@Lazy
|
private MesQcOqcLineService oqcLineService;
|
@Resource
|
@Lazy
|
private MesQcRqcService rqcService;
|
@Resource
|
@Lazy
|
private MesQcRqcLineService rqcLineService;
|
|
@Resource
|
private MesMdItemService itemService;
|
@Resource
|
private AdminUserApi adminUserApi;
|
|
@Override
|
public MesQcQcReportRespVO getQcReportData(Long qcId, Integer qcType, Long resultId) {
|
MesQcQcReportRespVO report = new MesQcQcReportRespVO();
|
report.setQcType(qcType);
|
|
// 1. 主表信息(按类型取公共字段)
|
Long itemId = null;
|
List<Long> lineIndicatorIds = new ArrayList<>();
|
Map<Long, LineInfo> lineInfoMap = new LinkedHashMap<>();
|
if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
|
MesQcIqcDO doc = iqcService.validateIqcExists(qcId);
|
itemId = doc.getItemId();
|
report.setDocCode(doc.getCode()).setDocName(doc.getName())
|
.setBatchNo(doc.getVendorBatch()).setBatchQuantity(doc.getReceivedQuantity())
|
.setSamplingTime(doc.getInspectDate() != null ? doc.getInspectDate() : doc.getReceiveDate())
|
.setSamplingLocation(doc.getSamplingLocation()).setCertificateNo(doc.getCertificateNo())
|
.setExecuteStandard(doc.getExecuteStandard())
|
.setInspectorUserId(doc.getInspectorUserId()).setAuditUserId(doc.getAuditUserId())
|
.setApproveUserId(doc.getApproveUserId()).setCheckResult(doc.getCheckResult())
|
.setInspectDate(doc.getInspectDate()).setDocCreateTime(doc.getCreateTime())
|
.setRemark(doc.getRemark());
|
List<MesQcIqcLineDO> lines = iqcLineService.getIqcLineListByIqcId(qcId);
|
for (MesQcIqcLineDO line : lines) {
|
lineIndicatorIds.add(line.getIndicatorId());
|
lineInfoMap.putIfAbsent(line.getIndicatorId(), new LineInfo(line.getCheckMethod(),
|
line.getStandardValue(), line.getMinThreshold(), line.getMaxThreshold()));
|
}
|
} else if (Objects.equals(qcType, MesQcTypeEnum.IPQC.getType())) {
|
MesQcIpqcDO doc = ipqcService.validateIpqcExists(qcId);
|
itemId = doc.getItemId();
|
report.setDocCode(doc.getCode()).setDocName(doc.getName())
|
.setBatchNo(doc.getSourceDocCode()).setBatchQuantity(doc.getCheckQuantity())
|
.setSamplingTime(doc.getInspectDate())
|
.setSamplingLocation(doc.getSamplingLocation()).setCertificateNo(doc.getCertificateNo())
|
.setExecuteStandard(doc.getExecuteStandard())
|
.setInspectorUserId(doc.getInspectorUserId()).setAuditUserId(doc.getAuditUserId())
|
.setApproveUserId(doc.getApproveUserId()).setCheckResult(doc.getCheckResult())
|
.setInspectDate(doc.getInspectDate()).setDocCreateTime(doc.getCreateTime())
|
.setRemark(doc.getRemark());
|
List<MesQcIpqcLineDO> lines = ipqcLineService.getIpqcLineListByIpqcId(qcId);
|
for (MesQcIpqcLineDO line : lines) {
|
lineIndicatorIds.add(line.getIndicatorId());
|
lineInfoMap.putIfAbsent(line.getIndicatorId(), new LineInfo(line.getCheckMethod(),
|
line.getStandardValue(), line.getMinThreshold(), line.getMaxThreshold()));
|
}
|
} else if (Objects.equals(qcType, MesQcTypeEnum.OQC.getType())) {
|
MesQcOqcDO doc = oqcService.validateOqcExists(qcId);
|
itemId = doc.getItemId();
|
report.setDocCode(doc.getCode()).setDocName(doc.getName())
|
.setBatchNo(doc.getBatchCode()).setBatchQuantity(doc.getOutQuantity())
|
.setSamplingTime(doc.getInspectDate() != null ? doc.getInspectDate() : doc.getOutDate())
|
.setSamplingLocation(doc.getSamplingLocation()).setCertificateNo(doc.getCertificateNo())
|
.setExecuteStandard(doc.getExecuteStandard())
|
.setInspectorUserId(doc.getInspectorUserId()).setAuditUserId(doc.getAuditUserId())
|
.setApproveUserId(doc.getApproveUserId()).setCheckResult(doc.getCheckResult())
|
.setInspectDate(doc.getInspectDate()).setDocCreateTime(doc.getCreateTime())
|
.setRemark(doc.getRemark());
|
List<MesQcOqcLineDO> lines = oqcLineService.getOqcLineListByOqcId(qcId);
|
for (MesQcOqcLineDO line : lines) {
|
lineIndicatorIds.add(line.getIndicatorId());
|
lineInfoMap.putIfAbsent(line.getIndicatorId(), new LineInfo(line.getCheckMethod(),
|
line.getStandardValue(), line.getMinThreshold(), line.getMaxThreshold()));
|
}
|
} else if (Objects.equals(qcType, MesQcTypeEnum.RQC.getType())) {
|
MesQcRqcDO doc = rqcService.validateRqcExists(qcId);
|
itemId = doc.getItemId();
|
report.setDocCode(doc.getCode()).setDocName(doc.getName())
|
.setBatchNo(doc.getBatchCode()).setBatchQuantity(doc.getCheckQuantity())
|
.setSamplingTime(doc.getInspectDate())
|
.setSamplingLocation(doc.getSamplingLocation()).setCertificateNo(doc.getCertificateNo())
|
.setExecuteStandard(doc.getExecuteStandard())
|
.setInspectorUserId(doc.getInspectorUserId()).setAuditUserId(doc.getAuditUserId())
|
.setApproveUserId(doc.getApproveUserId()).setCheckResult(doc.getCheckResult())
|
.setInspectDate(doc.getInspectDate()).setDocCreateTime(doc.getCreateTime())
|
.setRemark(doc.getRemark());
|
List<MesQcRqcLineDO> lines = rqcLineService.getRqcLineListByRqcId(qcId);
|
for (MesQcRqcLineDO line : lines) {
|
lineIndicatorIds.add(line.getIndicatorId());
|
lineInfoMap.putIfAbsent(line.getIndicatorId(), new LineInfo(line.getCheckMethod(),
|
line.getStandardValue(), line.getMinThreshold(), line.getMaxThreshold()));
|
}
|
} else {
|
throw new IllegalArgumentException("暂不支持 qcType=" + qcType);
|
}
|
|
// 2. 样品列表与选中的检验结果
|
List<MesQcIndicatorResultDO> results = resultService.getIndicatorResultListByQcIdAndType(qcId, qcType);
|
Long effectiveResultId = resultId;
|
if (effectiveResultId == null && CollUtil.isNotEmpty(results)) {
|
effectiveResultId = results.stream()
|
.min(Comparator.comparing(MesQcIndicatorResultDO::getId))
|
.map(MesQcIndicatorResultDO::getId).orElse(null);
|
}
|
|
// 3. 指标(含父分组自动补全)
|
Set<Long> indicatorIds = new HashSet<>(lineIndicatorIds);
|
Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(indicatorIds);
|
Set<Long> missingParentIds = indicatorMap.values().stream()
|
.filter(ind -> ind.getParentId() != null && ind.getParentId() > 0 && !indicatorMap.containsKey(ind.getParentId()))
|
.map(MesQcIndicatorDO::getParentId).collect(Collectors.toSet());
|
if (CollUtil.isNotEmpty(missingParentIds)) {
|
indicatorMap.putAll(indicatorService.getIndicatorMap(missingParentIds));
|
}
|
|
// 4. 检验结果明细(按 indicatorId 分组、measureNo 升序)
|
Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap = Collections.emptyMap();
|
if (effectiveResultId != null) {
|
List<MesQcIndicatorResultDetailDO> details =
|
resultService.getIndicatorResultDetailListByResultId(effectiveResultId);
|
detailMap = details.stream().collect(Collectors.groupingBy(MesQcIndicatorResultDetailDO::getIndicatorId));
|
}
|
|
// 5. 组装检验项树
|
List<MesQcQcReportRespVO.ReportItem> roots = buildReportItems(indicatorMap, lineInfoMap, detailMap, report);
|
report.setItems(roots);
|
|
// 6. 表头关联数据:物料、人员
|
if (itemId != null) {
|
MesMdItemDO item = itemService.getItemMap(Collections.singleton(itemId)).get(itemId);
|
if (item != null) {
|
report.setItemCode(item.getCode()).setItemName(item.getName())
|
.setItemSpecification(item.getSpecification());
|
}
|
}
|
Set<Long> userIds = new HashSet<>();
|
userIds.add(report.getInspectorUserId());
|
userIds.add(report.getAuditUserId());
|
userIds.add(report.getApproveUserId());
|
userIds.removeIf(Objects::isNull);
|
if (CollUtil.isNotEmpty(userIds)) {
|
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
|
if (report.getInspectorUserId() != null && userMap.get(report.getInspectorUserId()) != null) {
|
report.setInspectorName(userMap.get(report.getInspectorUserId()).getNickname());
|
}
|
if (report.getAuditUserId() != null && userMap.get(report.getAuditUserId()) != null) {
|
report.setAuditName(userMap.get(report.getAuditUserId()).getNickname());
|
}
|
if (report.getApproveUserId() != null && userMap.get(report.getApproveUserId()) != null) {
|
report.setApproveName(userMap.get(report.getApproveUserId()).getNickname());
|
}
|
}
|
return report;
|
}
|
|
/**
|
* 组装报告检验项树;顺带收集全局 measureNos 列头
|
*/
|
private List<MesQcQcReportRespVO.ReportItem> buildReportItems(
|
Map<Long, MesQcIndicatorDO> indicatorMap,
|
Map<Long, LineInfo> lineInfoMap,
|
Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap,
|
MesQcQcReportRespVO report) {
|
Map<Long, MesQcQcReportRespVO.ReportItem> nodeMap = new LinkedHashMap<>();
|
Set<Integer> measureNoSet = new HashSet<>();
|
for (Long indicatorId : indicatorMap.keySet()) {
|
MesQcIndicatorDO indicator = indicatorMap.get(indicatorId);
|
MesQcQcReportRespVO.ReportItem node = new MesQcQcReportRespVO.ReportItem();
|
node.setIndicatorId(indicator.getId());
|
node.setIndicatorCode(indicator.getCode());
|
node.setIndicatorName(indicator.getName());
|
node.setParentId(Objects.requireNonNullElse(indicator.getParentId(), 0L));
|
node.setItemType(Objects.requireNonNullElse(indicator.getItemType(),
|
MesQcIndicatorItemTypeEnum.RECORD.getType()));
|
node.setFormulaText(indicator.getFormulaText());
|
node.setUnitText(indicator.getUnitText());
|
node.setSortOrder(Objects.requireNonNullElse(indicator.getSortOrder(), 0));
|
LineInfo lineInfo = lineInfoMap.get(indicator.getId());
|
if (lineInfo != null) {
|
node.setCheckMethod(lineInfo.checkMethod);
|
node.setStandardValue(lineInfo.standardValue);
|
node.setThresholdMin(lineInfo.thresholdMin);
|
node.setThresholdMax(lineInfo.thresholdMax);
|
}
|
List<MesQcIndicatorResultDetailDO> details = detailMap.getOrDefault(indicator.getId(), Collections.emptyList());
|
List<MesQcQcReportRespVO.ReportMeasure> measures = new ArrayList<>(details.size());
|
details.stream()
|
.sorted(Comparator.comparing(d -> Objects.requireNonNullElse(d.getMeasureNo(), 1)))
|
.forEach(d -> {
|
MesQcQcReportRespVO.ReportMeasure measure = new MesQcQcReportRespVO.ReportMeasure();
|
measure.setMeasureNo(Objects.requireNonNullElse(d.getMeasureNo(), 1));
|
measure.setValue(d.getValue());
|
measure.setRemark(d.getRemark());
|
measures.add(measure);
|
measureNoSet.add(measure.getMeasureNo());
|
});
|
node.setMeasures(measures);
|
nodeMap.put(indicatorId, node);
|
}
|
// 挂树:父不在集合内的子项提升为顶级
|
List<MesQcQcReportRespVO.ReportItem> roots = new ArrayList<>();
|
Comparator<MesQcQcReportRespVO.ReportItem> byOrder =
|
Comparator.comparing(MesQcQcReportRespVO.ReportItem::getSortOrder)
|
.thenComparing(MesQcQcReportRespVO.ReportItem::getIndicatorId);
|
for (MesQcQcReportRespVO.ReportItem node : nodeMap.values()) {
|
MesQcQcReportRespVO.ReportItem parent = node.getParentId() > 0 ? nodeMap.get(node.getParentId()) : null;
|
if (parent == null) {
|
roots.add(node);
|
} else {
|
if (parent.getChildren() == null) {
|
parent.setChildren(new ArrayList<>());
|
}
|
parent.getChildren().add(node);
|
}
|
}
|
roots.sort(byOrder);
|
roots.forEach(root -> {
|
if (root.getChildren() != null) {
|
root.getChildren().sort(byOrder);
|
}
|
});
|
// 列头:至少一列
|
if (measureNoSet.isEmpty()) {
|
report.setMeasureNos(Collections.singletonList(1));
|
} else {
|
report.setMeasureNos(new ArrayList<>(measureNoSet).stream().sorted().collect(Collectors.toList()));
|
}
|
return roots;
|
}
|
|
/**
|
* 检验单行的判定信息(四类 line 的公共字段快照)
|
*/
|
private record LineInfo(String checkMethod, BigDecimal standardValue, BigDecimal thresholdMin, BigDecimal thresholdMax) {
|
}
|
|
}
|