吴羡
16 小时以前 330f90fe25f054ddcdec4c3ce037ea1ea851be72
cnas-process/src/main/java/com/ruoyi/process/service/impl/ProcessMethodVerifyServiceImpl.java
@@ -2,6 +2,9 @@
import  cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
@@ -29,6 +32,11 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@@ -41,6 +49,9 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
/**
 * 标准方法验证
@@ -103,6 +114,7 @@
        if (methodVerifyDto.getOperationType() == null) {
            throw new ErrorException("请选择是变更还是验证");
        }
        validateWordVerification(methodVerifyDto);
        // 新增
        baseMapper.insert(methodVerifyDto);
@@ -148,6 +160,37 @@
        return processMethodVerifyDto;
    }
    @Override
    public List<ProcessMethodVerifyWorkFile> getCurrentWorkFiles(String userIds) {
        List<ProcessMethodVerifyWorkFile> files = new ArrayList<>();
        if (StringUtils.isBlank(userIds)) return files;
        Set<Integer> ids = new LinkedHashSet<>();
        for (String value : StrUtil.split(userIds, ",")) {
            try {
                ids.add(Integer.valueOf(value.trim()));
            } catch (NumberFormatException e) {
                throw new ErrorException("检测人员ID无效");
            }
        }
        if (ids.size() > 5) throw new ErrorException("最多选择5名检测人员");
        for (Integer userId : ids) {
            ProcessMethodVerifyWorkFile file = processMethodVerifyWorkFileMapper.selectLatestAuthorization(userId);
            if (file == null) continue;
            file.setUserId(userId);
            if (StringUtils.isBlank(file.getFileUrl())) {
                file.setFileName("未上传上岗证书");
                file.setType(0);
            } else {
                file.setFileName(file.getFileUrl());
                file.setType(file.getFileUrl().matches("(?i).*\\.(png|jpe?g|gif|bmp|webp)$") ? 1 : 2);
            }
            files.add(file);
        }
        return files;
    }
    /**
     * 修改标准方法验证
     *
@@ -156,6 +199,7 @@
     */
    @Override
    public boolean updateMethodVerify(ProcessMethodVerifyDto methodVerifyDto) {
        validateWordVerification(methodVerifyDto);
        baseMapper.updateById(methodVerifyDto);
        // 删除上岗证
@@ -288,6 +332,14 @@
    public void exportMethodVerify(Integer methodVerifyId, HttpServletResponse response) {
        // 获取标准方法更新验证数据
        ProcessMethodVerify processMethodVerify = baseMapper.selectById(methodVerifyId);
        if (processMethodVerify == null) {
            throw new ErrorException("方法验证记录不存在");
        }
        if (Objects.equals(processMethodVerify.getOperationType(), 1)
                && StringUtils.isNotBlank(processMethodVerify.getVerificationContent())) {
            exportWordVerification(processMethodVerify, response);
            return;
        }
        // 将内部字段转换成展示到word中的对象
        ProcessMethodVerifyExportWordDto exportWordTemplate = getExportWordTemplate(processMethodVerify);
@@ -350,6 +402,91 @@
            e.printStackTrace();
            throw new RuntimeException("导出失败");
        }
    }
    /** 新版方法验证主表导出;原始记录和验证结果仍作为附件保存。 */
    private void exportWordVerification(ProcessMethodVerify verify, HttpServletResponse response) {
        JSONObject content = JSONUtil.parseObj(verify.getVerificationContent());
        String[][] checks = {
                {"personnel", "1. 人员能力"}, {"equipment", "2. 检测设备"},
                {"reagents", "3. 试剂要求"}, {"conditions", "4. 试验条件"},
                {"sample", "5. 样品处置"}, {"steps", "6. 试验步骤"},
                {"processing", "7. 数据处理"}, {"qualityControl", "质量控制方法"},
                {"result", "方法验证结果"}
        };
        try (XWPFDocument document = new XWPFDocument()) {
            XWPFParagraph title = document.createParagraph();
            title.setAlignment(ParagraphAlignment.CENTER);
            title.createRun().setText("方法验证记录");
            XWPFTable basic = document.createTable(2, 4);
            setCells(basic, 0, "标准名称", verify.getStandardName(), "标准编号", verify.getStandardCode());
            setCells(basic, 1, "验证项目", verify.getVerifyItem(), "", "");
            XWPFTable table = document.createTable(checks.length + 1, 4);
            setCells(table, 0, "验证内容", "方法要求", "实验室能力", "是否满足");
            JSONArray entries = content.getJSONArray("checks");
            for (int i = 0; i < checks.length; i++) {
                JSONObject entry = findCheck(entries, checks[i][0]);
                Integer satisfied = entry == null ? null : entry.getInt("satisfied");
                setCells(table, i + 1, checks[i][1], field(entry, "requirement"),
                        field(entry, "capability"), satisfied == null ? "" : satisfied == 1 ? "是" : "否");
            }
            XWPFTable conclusion = document.createTable(1, 2);
            setCells(conclusion, 0, "验证结论", field(content, "conclusion"));
            XWPFTable decisions = document.createTable(2, 4);
            setCells(decisions, 0, "评审意见", field(content, "reviewDecision"),
                    "评审人员:" + field(content, "reviewer"), field(content, "reviewDate"));
            setCells(decisions, 1, "审批意见", field(content, "approvalDecision"),
                    "技术负责人:" + field(content, "approver"), field(content, "approvalDate"));
            document.createParagraph().createRun().setText("附件1 原始记录;附件2 验证结果(附件在系统中查看)");
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            String fileName = URLEncoder.encode("方法验证记录", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
            document.write(response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException("导出方法验证记录失败", e);
        }
    }
    private JSONObject findCheck(JSONArray entries, String key) {
        if (entries == null) return null;
        for (Object value : entries) {
            JSONObject check = JSONUtil.parseObj(value);
            if (key.equals(check.getStr("key"))) return check;
        }
        return null;
    }
    private String field(JSONObject object, String key) {
        return object == null ? "" : StrUtil.nullToEmpty(object.getStr(key));
    }
    private void setCells(XWPFTable table, int row, String... values) {
        for (int i = 0; i < values.length; i++) {
            XWPFTableCell cell = table.getRow(row).getCell(i);
            cell.setText(StrUtil.nullToEmpty(values[i]));
        }
    }
    private void validateWordVerification(ProcessMethodVerifyDto verify) {
        // 没有 verificationContent 的旧记录继续由旧表单维护。
        if (!Objects.equals(verify.getOperationType(), 1)
                || StringUtils.isBlank(verify.getVerificationContent())) return;
        if (StringUtils.isBlank(verify.getStandardName())
                || StringUtils.isBlank(verify.getStandardCode())
                || StringUtils.isBlank(verify.getVerifyItem())) {
            throw new ErrorException("请填写标准名称、标准编号和验证项目");
        }
        try {
            JSONUtil.parseObj(verify.getVerificationContent());
        } catch (Exception e) {
            throw new ErrorException("方法验证内容格式错误");
        }
        // 保留旧列供现有依赖 method_name 的查询使用。
        verify.setMethodName(verify.getStandardName());
    }
    private ProcessMethodVerifyExportWordDto getExportWordTemplate(ProcessMethodVerify processMethodVerify) {
@@ -424,7 +561,7 @@
                User user = userMapper.selectById(userId);
                ProcessMethodVerifyWorkFile workFile = new ProcessMethodVerifyWorkFile();
                workFile.setMethodVerifyId(methodVerifyDto.getMethodVerifyId());
                workFile.setType(1);
                workFile.setType(workName.matches("(?i).*\\.(png|jpe?g|gif|bmp|webp)$") ? 1 : 2);
                workFile.setFileUrl(workName);
                workFile.setFileName(workName);
                workFile.setUserId(user.getId());