18 小时以前 7a681887e5a8e1aab49acc886974d354c69a280e
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicatorresult/MesQcIndicatorResultController.java
@@ -13,8 +13,10 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcLineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcIndicatorItemTypeEnum;
import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService;
import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcReportService;
import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcLineService;
import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcLineService;
import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcLineService;
@@ -30,6 +32,7 @@
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
@@ -44,6 +47,8 @@
    @Resource
    private MesQcIndicatorResultService resultService;
    @Resource
    private MesQcReportService reportService;
    @Resource
    private MesQcIqcLineService iqcLineService;
    @Resource
@@ -117,12 +122,29 @@
        return success(voPageResult);
    }
    @GetMapping("/report")
    @Operation(summary = "获得检验报告单数据(打印用:表头 + 检验项树 + 平行测量 + 签字区)")
    @Parameters({
            @Parameter(name = "qcId", description = "质检单ID", required = true, example = "1"),
            @Parameter(name = "qcType", description = "质检类型", required = true, example = "1"),
            @Parameter(name = "resultId", description = "检验结果(样品)编号,可不传;多样品时用于选择", example = "1")
    })
    @PreAuthorize("@ss.hasPermission('mes:qc-iqc:query')")
    public CommonResult<MesQcQcReportRespVO> getQcReportData(
            @RequestParam("qcId") Long qcId,
            @RequestParam("qcType") Integer qcType,
            @RequestParam(value = "resultId", required = false) Long resultId) {
        return success(reportService.getQcReportData(qcId, qcType, resultId));
    }
    // ==================== 拼接 VO ====================
    /**
     * 构建明细 Item 列表
     * 构建明细 Item 树(支持分组层级 + 平行测量多批次)
     *
     * <p>前端表单仅需:indicatorId、indicatorName、valueType、valueSpecification + 已有结果(id、value、remark)</p>
     * <p>返回树形列表:顶级为分组项或独立录入项,分组项 children 挂子项;
     * 每个录入项的平行测量值放在 measures(按 measureNo 升序);
     * 兼容字段 id/value/remark 取第一批值,供旧数据直接展示</p>
     *
     * @param details 已有结果明细(空列表表示获取空值模板)
     * @param qcId    质检单 ID
@@ -155,30 +177,78 @@
            return Collections.emptyList();
        }
        // 1.2 批量查询检测指标
        // 1.2 批量查询检测指标;子项的父分组未挂在行上时自动补全,保证树完整
        Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(new HashSet<>(indicatorIds));
        // 1.3 构建已有明细 Map(按 indicatorId 索引)
        Map<Long, MesQcIndicatorResultDetailDO> detailMap = CollUtil.isEmpty(details)
                ? Collections.emptyMap()
                : convertMap(details, MesQcIndicatorResultDetailDO::getIndicatorId);
        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));
        }
        // 2. 遍历指标 ID,组装 VO
        List<MesQcIndicatorResultRespVO.Item> voList = new ArrayList<>(indicatorIds.size());
        for (Long indicatorId : indicatorIds) {
        // 1.3 已有明细分组(indicatorId -> 多批次列表)
        Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap = CollUtil.isEmpty(details)
                ? Collections.emptyMap()
                : details.stream().collect(Collectors.groupingBy(MesQcIndicatorResultDetailDO::getIndicatorId));
        // 2. 构建节点
        Map<Long, MesQcIndicatorResultRespVO.Item> nodeMap = new LinkedHashMap<>();
        for (Map.Entry<Long, MesQcIndicatorDO> entry : indicatorMap.entrySet()) {
            Long indicatorId = entry.getKey();
            MesQcIndicatorDO indicator = entry.getValue();
            MesQcIndicatorResultRespVO.Item vo = new MesQcIndicatorResultRespVO.Item()
                    .setIndicatorId(indicatorId);
            // 来自 indicator
            findAndThen(indicatorMap, indicatorId, indicator -> vo
                    .setIndicatorId(indicatorId)
                    .setIndicatorName(indicator.getName())
                    .setValueType(indicator.getResultType())
                    .setValueSpecification(indicator.getResultSpecification()));
            // 来自已有结果明细(如有)
            findAndThen(detailMap, indicatorId, detail -> vo
                    .setId(detail.getId()).setResultId(detail.getResultId())
                    .setValue(detail.getValue()).setRemark(detail.getRemark()));
            voList.add(vo);
                    .setValueSpecification(indicator.getResultSpecification())
                    .setParentId(Objects.requireNonNullElse(indicator.getParentId(), 0L))
                    .setItemType(Objects.requireNonNullElse(indicator.getItemType(),
                            MesQcIndicatorItemTypeEnum.RECORD.getType()))
                    .setFormulaText(indicator.getFormulaText())
                    .setUnitText(indicator.getUnitText())
                    .setSortOrder(Objects.requireNonNullElse(indicator.getSortOrder(), 0));
            List<MesQcIndicatorResultDetailDO> itemDetails = detailMap.getOrDefault(indicatorId, Collections.emptyList());
            List<MesQcIndicatorResultRespVO.Measure> measures = new ArrayList<>(itemDetails.size());
            itemDetails.stream()
                    .sorted(Comparator.comparing(d -> Objects.requireNonNullElse(d.getMeasureNo(), 1)))
                    .forEach(detail -> measures.add(new MesQcIndicatorResultRespVO.Measure()
                            .setDetailId(detail.getId()).setResultId(detail.getResultId())
                            .setMeasureNo(Objects.requireNonNullElse(detail.getMeasureNo(), 1))
                            .setValue(detail.getValue()).setRemark(detail.getRemark())));
            vo.setMeasures(measures);
            // 兼容旧字段:取第一批测量值
            if (CollUtil.isNotEmpty(measures)) {
                MesQcIndicatorResultRespVO.Measure first = measures.get(0);
                vo.setId(first.getDetailId()).setResultId(first.getResultId())
                        .setValue(first.getValue()).setRemark(first.getRemark());
            }
            nodeMap.put(indicatorId, vo);
        }
        return voList;
        // 3. 挂树:父不在集合内的子项提升为顶级;同级按排序号
        Comparator<MesQcIndicatorResultRespVO.Item> byOrder =
                Comparator.comparing(MesQcIndicatorResultRespVO.Item::getSortOrder)
                        .thenComparing(MesQcIndicatorResultRespVO.Item::getIndicatorId);
        List<MesQcIndicatorResultRespVO.Item> roots = new ArrayList<>();
        for (MesQcIndicatorResultRespVO.Item node : nodeMap.values()) {
            MesQcIndicatorResultRespVO.Item 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);
            }
        });
        return roots;
    }
}