| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * 标准方法验证 |
| | |
| | | if (methodVerifyDto.getOperationType() == null) { |
| | | throw new ErrorException("请选择是变更还是验证"); |
| | | } |
| | | validateWordVerification(methodVerifyDto); |
| | | // 新增 |
| | | baseMapper.insert(methodVerifyDto); |
| | | |
| | |
| | | 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; |
| | | } |
| | | |
| | | /** |
| | | * 修改标准方法验证 |
| | | * |
| | |
| | | */ |
| | | @Override |
| | | public boolean updateMethodVerify(ProcessMethodVerifyDto methodVerifyDto) { |
| | | validateWordVerification(methodVerifyDto); |
| | | baseMapper.updateById(methodVerifyDto); |
| | | |
| | | // 删除上岗证 |
| | |
| | | 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); |
| | |
| | | } |
| | | } |
| | | |
| | | /** 新版方法验证主表导出;原始记录和验证结果仍作为附件保存。 */ |
| | | 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) { |
| | | ProcessMethodVerifyExportWordDto processMethodVerifyExportWordDto = new ProcessMethodVerifyExportWordDto(); |
| | | BeanUtil.copyProperties(processMethodVerify, processMethodVerifyExportWordDto); |
| | |
| | | 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()); |