2026-09-04 3495965b99dfcbf191eefb8294a8de05bedc160a
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcController.java
@@ -1,20 +1,32 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.rqc;
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.rqc.vo.MesQcRqcPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.MesQcRqcRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.MesQcRqcSaveReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.vo.MesQcQualityExportVO;
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.rqc.MesQcRqcDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.rqc.MesQcRqcLineMapper;
import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
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.service.qc.indicator.MesQcIndicatorService;
import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService;
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;
@@ -29,9 +41,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;
@@ -50,6 +67,12 @@
    private MesMdItemService itemService;
    @Resource
    private MesMdUnitMeasureService unitMeasureService;
    @Resource
    private MesQcIndicatorResultService indicatorResultService;
    @Resource
    private MesQcIndicatorService indicatorService;
    @Resource
    private MesQcRqcLineMapper rqcLineMapper;
    @Resource
    private AdminUserApi adminUserApi;
@@ -112,8 +135,8 @@
                               HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<MesQcRqcDO> list = rqcService.getRqcPage(pageReqVO).getList();
        List<MesQcRqcRespVO> voList = buildRqcRespVOList(list);
        ExcelUtils.write(response, "退货检验单.xls", "数据", MesQcRqcRespVO.class, voList);
        List<MesQcQualityExportVO> exportList = buildRqcQualityExportList(list);
        ExcelUtils.write(response, "退货检验单.xls", "数据", MesQcQualityExportVO.class, exportList);
    }
    // ==================== 拼接 VO ====================
@@ -131,6 +154,8 @@
        // 批量查询检测人员
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(list, MesQcRqcDO::getInspectorUserId));
        // 批量查询检验项指标
        Map<Long, String> indicatorSummaryMap = buildIndicatorSummaryMap(list);
        // 拼装 VO
        return BeanUtils.toBean(list, MesQcRqcRespVO.class, vo -> {
            findAndThen(itemMap, vo.getItemId(), item -> {
@@ -140,7 +165,166 @@
            });
            findAndThen(userMap, vo.getInspectorUserId(),
                    user -> vo.setInspectorNickname(user.getNickname()));
            vo.setIndicatorResultSummary(indicatorSummaryMap.getOrDefault(vo.getId(), ""));
        });
    }
    /**
     * 构建每个检验单的检验项指标汇总字符串(qcType = RQC)
     */
    private Map<Long, String> buildIndicatorSummaryMap(List<MesQcRqcDO> list) {
        Map<Long, String> indicatorSummaryMap = new HashMap<>();
        Set<Long> qcIds = convertSet(list, MesQcRqcDO::getId);
        if (CollUtil.isEmpty(qcIds)) {
            return indicatorSummaryMap;
        }
        // 按 QC ID 批量查询检验结果
        List<MesQcIndicatorResultDO> indicatorResults = indicatorResultService.getIndicatorResultListByQcIdsAndType(
                new ArrayList<>(qcIds), MesBizTypeConstants.QC_RQC);
        if (CollUtil.isEmpty(indicatorResults)) {
            return indicatorSummaryMap;
        }
        // 按 QC ID 分组结果
        Map<Long, List<MesQcIndicatorResultDO>> resultMap = indicatorResults.stream()
                .collect(Collectors.groupingBy(MesQcIndicatorResultDO::getQcId));
        // 批量查询检验结果明细
        Set<Long> resultIds = convertSet(indicatorResults, MesQcIndicatorResultDO::getId);
        List<MesQcIndicatorResultDetailDO> indicatorDetails = indicatorResultService.getIndicatorResultDetailListByResultIds(
                new ArrayList<>(resultIds));
        // 按结果 ID 分组明细
        Map<Long, List<MesQcIndicatorResultDetailDO>> detailMapByResultId = indicatorDetails.stream()
                .collect(Collectors.groupingBy(MesQcIndicatorResultDetailDO::getResultId));
        // 批量查询检测指标
        Set<Long> indicatorIds = convertSet(indicatorDetails, MesQcIndicatorResultDetailDO::getIndicatorId);
        Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(indicatorIds);
        // 构建每个 QC 的指标汇总字符串
        resultMap.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));
        });
        return indicatorSummaryMap;
    }
    /**
     * 构建导出行:一单一行,检验指标 / 判定依据取自行明细并拼接
     */
    private List<MesQcQualityExportVO> buildRqcQualityExportList(List<MesQcRqcDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        // 批量查询检测人员
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(list, MesQcRqcDO::getInspectorUserId));
        // 批量查询物料
        Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(
                convertSet(list, MesQcRqcDO::getItemId));
        // 批量查询行明细
        List<MesQcRqcLineDO> lines = rqcLineMapper.selectListByRqcIds(convertSet(list, MesQcRqcDO::getId));
        Map<Long, List<MesQcRqcLineDO>> lineMap = lines.stream()
                .collect(Collectors.groupingBy(MesQcRqcLineDO::getRqcId));
        // 批量查询检测指标
        Map<Long, MesQcIndicatorDO> indicatorMap = CollUtil.isEmpty(lines) ? Collections.emptyMap()
                : indicatorService.getIndicatorMap(convertSet(lines, MesQcRqcLineDO::getIndicatorId));
        // 批量查询实测值:检验单 ID -> {指标 ID -> 实测值}
        Map<Long, Map<Long, String>> measureMap = buildMeasureValueMap(
                convertSet(list, MesQcRqcDO::getId), MesBizTypeConstants.QC_RQC);
        // 组装导出行
        List<MesQcQualityExportVO> exportList = new ArrayList<>(list.size());
        for (MesQcRqcDO rqc : list) {
            MesQcQualityExportVO vo = new MesQcQualityExportVO();
            vo.setDocName(rqc.getName());
            MesMdItemDO item = itemMap.get(rqc.getItemId());
            vo.setItemName(item != null ? item.getName() : "");
            vo.setBatchNo(rqc.getBatchCode());
            vo.setInspectDate(MesQcQualityExportVO.formatDateTime(rqc.getInspectDate()));
            List<String> indicatorNames = new ArrayList<>();
            List<String> judgementSegments = new ArrayList<>();
            for (MesQcRqcLineDO line : lineMap.getOrDefault(rqc.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(rqc.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(rqc.getCheckResult()));
            findAndThen(userMap, rqc.getInspectorUserId(),
                    user -> vo.setInspectorName(user.getNickname()));
            // 暂无审核人数据来源,导出空列
            vo.setAuditorName("");
            vo.setRemark(rqc.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));
    }
}