2026-09-04 3495965b99dfcbf191eefb8294a8de05bedc160a
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/MesQcIqcController.java
@@ -1,22 +1,34 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.vo.MesQcQualityExportVO;
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
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.iqc.MesQcIqcDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcLineMapper;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
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.iqc.MesQcIqcService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
@@ -31,9 +43,14 @@
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -52,9 +69,15 @@
    @Resource
    private SrmSupplierApi srmSupplierApi;
    @Resource
    private MesQcIndicatorResultService indicatorResultService;
    @Resource
    private MesQcIndicatorService indicatorService;
    @Resource
    private MesMdItemService itemService;
    @Resource
    private MesMdUnitMeasureService unitMeasureService;
    @Resource
    private MesQcIqcLineMapper iqcLineMapper;
    @Resource
    private AdminUserApi adminUserApi;
@@ -117,8 +140,8 @@
                               HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<MesQcIqcDO> list = iqcService.getIqcPage(pageReqVO).getList();
        List<MesQcIqcRespVO> voList = buildIqcRespVOList(list);
        ExcelUtils.write(response, "来料检验单.xls", "数据", MesQcIqcRespVO.class, voList);
        List<MesQcQualityExportVO> exportList = buildIqcQualityExportList(list);
        ExcelUtils.write(response, "来料检验单.xls", "数据", MesQcQualityExportVO.class, exportList);
    }
    // ==================== 拼接 VO ====================
@@ -140,6 +163,63 @@
        // 批量查询检测人员
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(list, MesQcIqcDO::getInspectorUserId));
        // 批量查询检验项指标
        Set<Long> qcIds = convertSet(list, MesQcIqcDO::getId);
        Map<Long, List<MesQcIndicatorResultDO>> indicatorResultMap = new HashMap<>();
        if (CollUtil.isNotEmpty(qcIds)) {
            // 按QC ID批量查询检验结果(IQC类型)
            List<MesQcIndicatorResultDO> indicatorResults = indicatorResultService.getIndicatorResultListByQcIdsAndType(
                    new ArrayList<>(qcIds), MesBizTypeConstants.QC_IQC);
            indicatorResults.forEach(result -> {
                indicatorResultMap.computeIfAbsent(result.getQcId(), k -> new ArrayList<>()).add(result);
            });
        }
        // 批量查询检验结果明细并构建指标映射
        Map<Long, String> indicatorSummaryMap = new HashMap<>();
        if (CollUtil.isNotEmpty(indicatorResultMap)) {
            Set<Long> resultIds = new HashSet<>();
            indicatorResultMap.values().forEach(results -> {
                results.forEach(result -> resultIds.add(result.getId()));
            });
            if (CollUtil.isNotEmpty(resultIds)) {
                // 批量查询检验结果明细
                List<MesQcIndicatorResultDetailDO> indicatorDetails = indicatorResultService.getIndicatorResultDetailListByResultIds(
                        new ArrayList<>(resultIds));
                // 按结果ID分组明细
                Map<Long, List<MesQcIndicatorResultDetailDO>> detailMapByResultId = indicatorDetails.stream()
                        .collect(Collectors.groupingBy(MesQcIndicatorResultDetailDO::getResultId));
                // 批量查询检测指标(indicatorId -> indicator)
                Set<Long> indicatorIds = convertSet(indicatorDetails, MesQcIndicatorResultDetailDO::getIndicatorId);
                Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(indicatorIds);
                // 构建每个QC的指标汇总字符串
                indicatorResultMap.forEach((qcId, results) -> {
                    List<String> indicatorSummaries = new ArrayList<>();
                    for (MesQcIndicatorResultDO result : results) {
                        List<MesQcIndicatorResultDetailDO> details = detailMapByResultId.getOrDefault(result.getId(), Collections.emptyList());
                        for (MesQcIndicatorResultDetailDO detail : details) {
                            // 通过 indicatorId 关联指标名称,查不到则回退为 "指标"
                            String indicatorName = "指标";
                            MesQcIndicatorDO indicator = indicatorMap.get(detail.getIndicatorId());
                            if (indicator != null && StrUtil.isNotBlank(indicator.getName())) {
                                indicatorName = indicator.getName();
                            }
                            String value = detail.getValue();
                            String remark = detail.getRemark();
                            // 格式化为 "指标名称:值" 或 "指标名称:值(备注)"
                            String indicatorStr = indicatorName + ":" + value;
                            if (StrUtil.isNotBlank(remark)) {
                                indicatorStr += "(" + remark + ")";
                            }
                            indicatorSummaries.add(indicatorStr);
                        }
                    }
                    // 用逗号连接多个指标
                    indicatorSummaryMap.put(qcId, String.join(", ", indicatorSummaries));
                });
            }
        }
        // 拼装 VO
        return BeanUtils.toBean(list, MesQcIqcRespVO.class, vo -> {
            findAndThen(vendorMap, vo.getVendorId(),
@@ -153,7 +233,111 @@
            });
            findAndThen(userMap, vo.getInspectorUserId(),
                    user -> vo.setInspectorNickname(user.getNickname()));
            // 设置检验项指标汇总
            vo.setIndicatorResultSummary(indicatorSummaryMap.getOrDefault(vo.getId(), ""));
        });
    }
    /**
     * 构建导出行:一单一行,检验指标 / 判定依据取自行明细并拼接
     */
    private List<MesQcQualityExportVO> buildIqcQualityExportList(List<MesQcIqcDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        // 批量查询检测人员
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(list, MesQcIqcDO::getInspectorUserId));
        // 批量查询物料
        Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(
                convertSet(list, MesQcIqcDO::getItemId));
        // 批量查询行明细
        List<MesQcIqcLineDO> lines = iqcLineMapper.selectListByIqcIds(convertSet(list, MesQcIqcDO::getId));
        Map<Long, List<MesQcIqcLineDO>> lineMap = lines.stream()
                .collect(Collectors.groupingBy(MesQcIqcLineDO::getIqcId));
        // 批量查询检测指标
        Map<Long, MesQcIndicatorDO> indicatorMap = CollUtil.isEmpty(lines) ? Collections.emptyMap()
                : indicatorService.getIndicatorMap(convertSet(lines, MesQcIqcLineDO::getIndicatorId));
        // 批量查询实测值:检验单 ID -> {指标 ID -> 实测值}
        Map<Long, Map<Long, String>> measureMap = buildMeasureValueMap(
                convertSet(list, MesQcIqcDO::getId), MesBizTypeConstants.QC_IQC);
        // 组装导出行
        List<MesQcQualityExportVO> exportList = new ArrayList<>(list.size());
        for (MesQcIqcDO iqc : list) {
            MesQcQualityExportVO vo = new MesQcQualityExportVO();
            vo.setDocName(iqc.getName());
            MesMdItemDO item = itemMap.get(iqc.getItemId());
            vo.setItemName(item != null ? item.getName() : "");
            vo.setBatchNo(iqc.getVendorBatch());
            vo.setInspectDate(MesQcQualityExportVO.formatDateTime(iqc.getInspectDate()));
            List<String> indicatorNames = new ArrayList<>();
            List<String> judgementSegments = new ArrayList<>();
            for (MesQcIqcLineDO line : lineMap.getOrDefault(iqc.getId(), Collections.emptyList())) {
                MesQcIndicatorDO indicator = indicatorMap.get(line.getIndicatorId());
                String name = indicator != null && StrUtil.isNotBlank(indicator.getName())
                        ? indicator.getName() : "";
                String range = MesQcQualityExportVO.buildRangeText(
                        line.getStandardValue(), line.getMinThreshold(), line.getMaxThreshold());
                if (StrUtil.isNotBlank(name)) {
                    String measuredValue = measureMap
                            .getOrDefault(iqc.getId(), Collections.emptyMap())
                            .get(line.getIndicatorId());
                    indicatorNames.add(StrUtil.isNotBlank(measuredValue) ? name + ":" + measuredValue : name);
                    if (StrUtil.isNotBlank(range)) {
                        judgementSegments.add(name + range);
                    }
                }
            }
            vo.setIndicatorNames(String.join("、", indicatorNames));
            vo.setJudgementBasis(String.join(";", judgementSegments));
            vo.setCheckResultText(getCheckResultLabel(iqc.getCheckResult()));
            findAndThen(userMap, iqc.getInspectorUserId(),
                    user -> vo.setInspectorName(user.getNickname()));
            // 暂无审核人数据来源,导出空列
            vo.setAuditorName("");
            vo.setRemark(iqc.getRemark());
            exportList.add(vo);
        }
        return exportList;
    }
    /**
     * 构建 检验单 ID -> {指标 ID -> 实测值} 映射,实测值取自检验结果明细表
     */
    private Map<Long, Map<Long, String>> buildMeasureValueMap(Set<Long> qcIds, int qcType) {
        Map<Long, Map<Long, String>> measureMap = new HashMap<>();
        if (CollUtil.isEmpty(qcIds)) {
            return measureMap;
        }
        List<MesQcIndicatorResultDO> results = indicatorResultService.getIndicatorResultListByQcIdsAndType(
                new ArrayList<>(qcIds), qcType);
        if (CollUtil.isEmpty(results)) {
            return measureMap;
        }
        Map<Long, Long> resultQcMap = results.stream()
                .collect(Collectors.toMap(MesQcIndicatorResultDO::getId, MesQcIndicatorResultDO::getQcId));
        List<MesQcIndicatorResultDetailDO> details = indicatorResultService.getIndicatorResultDetailListByResultIds(
                new ArrayList<>(resultQcMap.keySet()));
        if (CollUtil.isEmpty(details)) {
            return measureMap;
        }
        for (MesQcIndicatorResultDetailDO detail : details) {
            Long qcId = resultQcMap.get(detail.getResultId());
            if (qcId == null) {
                continue;
            }
            measureMap.computeIfAbsent(qcId, k -> new HashMap<>())
                    .put(detail.getIndicatorId(), detail.getValue());
        }
        return measureMap;
    }
    private String getCheckResultLabel(Integer checkResult) {
        if (checkResult == null) {
            return "";
        }
        return DictFrameworkUtils.parseDictDataLabel(
                DictTypeConstants.MES_QC_CHECK_RESULT, String.valueOf(checkResult));
    }
}