| | |
| | | import com.ruoyi.inspect.pojo.*; |
| | | import com.ruoyi.inspect.service.*; |
| | | import com.ruoyi.inspect.util.HackLoopTableRenderPolicy; |
| | | import com.ruoyi.inspect.util.PreserveReportPicturePlaceholderHandler; |
| | | import com.ruoyi.inspect.vo.InsOrderPlanTaskSwitchVo; |
| | | import com.ruoyi.inspect.vo.InsOrderPlanVO; |
| | | import com.ruoyi.inspect.vo.InsSampleUserVO; |
| | |
| | | InsOrder order = insOrderMapper.selectOne(Wrappers.<InsOrder>lambdaQuery() |
| | | .eq(InsOrder::getId, orderId) |
| | | .last("FOR UPDATE")); |
| | | InsReport existingReport = insReportMapper.selectOne(Wrappers.<InsReport>lambdaQuery() |
| | | .eq(InsReport::getInsOrderId, orderId)); |
| | | if (existingReport != null && existingReport.getReportType() != null |
| | | && !Objects.equals(existingReport.getReportType(), reportType)) { |
| | | throw new ErrorException("同一检验订单只能使用一种报告类型"); |
| | | } |
| | | boolean isInspectionReport = Objects.equals(INSPECTION_REPORT, reportType); |
| | | registerInsResults = isInspectionReport && Boolean.TRUE.equals(registerInsResults); |
| | | // 1. 判断是否有重复编号, 有重复编号做提醒 |
| | |
| | | }) |
| | | .ne(InsProduct::getIsBinding, 1)); |
| | | if (Objects.equals(reportType, INSPECTION_REPORT)) { |
| | | insProducts.addAll(insProductMapper.selectFiberInsProduct(InsSampleIds, laboratory)); |
| | | List<InsProduct> insProducts1 = insProductMapper.selectFiberInsProduct(InsSampleIds, laboratory); |
| | | insProducts.addAll(insProducts1); |
| | | } |
| | | if (insProducts.size() > 0) { |
| | | String str = ""; |
| | |
| | | // 修改换行和合并问题 |
| | | updaeMerge(template.getXWPFDocument(), true); |
| | | String name = insReport.getCode().replace("/", "") + (showResult ? "-J.docx" : "-C.docx"); |
| | | template.writeAndClose(Files.newOutputStream(Paths.get(wordUrl + "/" + name))); |
| | | Files.createDirectories(Paths.get(wordUrl)); |
| | | template.writeAndClose(Files.newOutputStream(Paths.get(wordUrl, name))); |
| | | insReport.setUrl("/word/" + name); |
| | | insReport.setIsPass(0); |
| | | insReport.setWriteUserId(SecurityUtils.getUserId().intValue());//提交人 |
| | |
| | | } |
| | | } |
| | | } |
| | | // 新版检测报告直接使用固定四列结果行,不再构造旧版可变列 TableRenderData。 |
| | | // 检验报告仍沿用下方原有的大表格逻辑。 |
| | | if (!showResult) { |
| | | return; |
| | | } |
| | | // 收样日期 |
| | | List<RowRenderData> rows = new ArrayList<>(); |
| | | List<TextRenderData> text = new ArrayList<>(); |
| | |
| | | for (String s : standardMethod) { |
| | | standardMethod2.append("、").append(s); |
| | | } |
| | | standardMethod2.replace(0, 1, ""); |
| | | if (standardMethod2.length() > 0) { |
| | | standardMethod2.deleteCharAt(0); |
| | | } |
| | | tables.forEach(table -> { |
| | | table.put("tableSize", tables.size() + 1); |
| | | }); |
| | |
| | | // 抽样日期 |
| | | // 成品是抽样时间 |
| | | LocalDateTime sendTime = insOrder.getSendTime(); |
| | | if (insOrder.getTypeSource() != null && insOrder.getTypeSource().equals(1)) { |
| | | IfsInventoryQuantity reportInventory = null; |
| | | if (insOrder.getIfsInventoryId() != null) { |
| | | reportInventory = ifsInventoryQuantityMapper.selectById(insOrder.getIfsInventoryId()); |
| | | } |
| | | if (insOrder.getTypeSource() != null && insOrder.getTypeSource().equals(1) && reportInventory != null) { |
| | | // 原材料收样日期是报检日期 |
| | | IfsInventoryQuantity ifsInventoryQuantity = ifsInventoryQuantityMapper.selectById(insOrder.getIfsInventoryId()); |
| | | sendTime = ifsInventoryQuantity.getDeclareDate(); |
| | | sendTime = reportInventory.getDeclareDate(); |
| | | } |
| | | |
| | | // 检验时间 抽样时间-提交时间 |
| | |
| | | List<Map<String, String>> finalDeviceList = deviceList; |
| | | String finalModelStr = modelStr; |
| | | |
| | | InputStream inputStream = this.getClass().getResourceAsStream(showResult ? "/static/report-template.docx" : "/static/detection-report-template.docx"); |
| | | List<Map<String, String>> detectionResultRows = buildDetectionResultRows(samples); |
| | | String productName = defaultReportText(insOrder.getSampleView(), insOrder.getSample()); |
| | | String customerName = defaultReportText(custom == null ? null : custom.getCompany(), insOrder.getCompany()); |
| | | String detectionCategory = defaultReportText(finalOrderType, "委托检测"); |
| | | String sampleCode = samples.stream() |
| | | .map(SampleProductDto::getSampleCode) |
| | | .filter(StringUtils::isNotBlank) |
| | | .distinct() |
| | | .collect(Collectors.joining("、")); |
| | | String productAndModel = productName; |
| | | if (StringUtils.isNotBlank(finalModelStr) && !Objects.equals(productName, finalModelStr)) { |
| | | productAndModel = productName + " " + finalModelStr; |
| | | } |
| | | String standardMethodText = "null".equals(standardMethod2.toString()) ? "" : standardMethod2.toString(); |
| | | String productionDate = "/"; |
| | | String batchNo = "/"; |
| | | if (reportInventory != null) { |
| | | if (reportInventory.getProductDate() != null) { |
| | | productionDate = reportInventory.getProductDate().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); |
| | | } |
| | | batchNo = defaultReportText(reportInventory.getUpdateBatchNo(), reportInventory.getLotBatchNo()); |
| | | } |
| | | boolean containsOrganicChlorine = detectionResultRows.stream() |
| | | .map(row -> row.get("itemName")) |
| | | .filter(Objects::nonNull) |
| | | .anyMatch(name -> name.contains("有机氯")); |
| | | String resultRemark = containsOrganicChlorine |
| | | ? "微库仑法,有机氯含量小于0.005%时,以未检出报出。" |
| | | : defaultReportText(insOrder.getRemark(), "/"); |
| | | |
| | | // 检测报告和检验报告统一使用新版报告模板 |
| | | String templateName = "/static/detection-report-template-v2.docx"; |
| | | InputStream inputStream = this.getClass().getResourceAsStream(templateName); |
| | | if (inputStream == null) { |
| | | throw new RuntimeException("找不到报告模板: " + templateName); |
| | | } |
| | | Configure configure = Configure.builder() |
| | | .bind("deviceList", new HackLoopTableRenderPolicy()) |
| | | .bind("r", new HackLoopTableRenderPolicy(true)) |
| | | .setValidErrorHandler(new PreserveReportPicturePlaceholderHandler()) |
| | | .useSpringEL(true) |
| | | .build(); |
| | | |
| | | String finalProductAndModel = productAndModel; |
| | | String finalProductName = productName; |
| | | String finalCustomerName = customerName; |
| | | String finalDetectionCategory = detectionCategory; |
| | | String finalSampleCode = defaultReportText(sampleCode, "/"); |
| | | String finalStandardMethodText = defaultReportText(standardMethodText, "/"); |
| | | String finalProductionDate = productionDate; |
| | | String finalBatchNo = batchNo; |
| | | String finalResultRemark = resultRemark; |
| | | String equipmentText = buildEquipmentText(finalDeviceList); |
| | | String issueDate = now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); |
| | | XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render( |
| | | new HashMap<String, Object>() {{ |
| | | put("order", insOrder); |
| | |
| | | put("sampleSize", insOrder.getTestQuantity()); |
| | | put("tables", tables); |
| | | put("tableSize", tables.size() + 1); |
| | | put("standardMethod", (standardMethod2.toString().equals("null") ? "" : standardMethod2)); |
| | | put("standardMethod", finalStandardMethodText); |
| | | put("deviceList", finalDeviceList); |
| | | put("twoCode", null); |
| | | put("models", finalModelStr); |
| | |
| | | put("resultCh", finalResultCh); |
| | | put("resultEn", finalResultEn); |
| | | put("sampleStatus", sampleStatus); |
| | | // 新版检测报告模板(参照《有机氯检测报告》)使用的扁平字段。 |
| | | put("no", insReport.getCode()); |
| | | put("cover", finalProductAndModel); |
| | | put("product", finalProductName); |
| | | put("model", defaultReportText(finalModelStr, "/")); |
| | | put("customer", finalCustomerName); |
| | | put("category", finalDetectionCategory); |
| | | put("date", issueDate); |
| | | put("maker", defaultReportText(insOrder.getProduction(), "/")); |
| | | put("env", finalEnvironment); |
| | | put("qty", defaultReportText(insOrder.getTestQuantity(), "/")); |
| | | put("receive", finalSendTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); |
| | | put("sampleNo", finalSampleCode); |
| | | put("appearance", defaultReportText(sampleStatus, "/")); |
| | | put("sender", defaultReportText(insOrder.getPrepareUser(), "/")); |
| | | put("produced", finalProductionDate); |
| | | put("batch", finalBatchNo); |
| | | put("phone", defaultReportText(insOrder.getPhone(), "/")); |
| | | put("testDate", insTime); |
| | | put("entrustNo", defaultReportText(insOrder.getEntrustCode(), "/")); |
| | | put("sampling", "/"); |
| | | put("standard", finalStandardMethodText); |
| | | put("equipment", equipmentText); |
| | | put("conclusion", "样品按委托方要求进行检测,数据见检测结果。"); |
| | | put("remark", "本报告检测结果仅对当日所接收样品负责。"); |
| | | put("r", detectionResultRows); |
| | | put("resultNote", finalResultRemark); |
| | | }}); |
| | | try { |
| | | // 修改换行和合并问题 |
| | | updaeMerge(template.getXWPFDocument(), false); |
| | | String name = insReport.getCode().replace("/", "") + (showResult ? ".docx" : "-C.docx"); |
| | | template.writeAndClose(Files.newOutputStream(Paths.get(wordUrl + "/" + name))); |
| | | Files.createDirectories(Paths.get(wordUrl)); |
| | | template.writeAndClose(Files.newOutputStream(Paths.get(wordUrl, name))); |
| | | insReport.setUrl("/word/" + name); |
| | | insReport.setWriteUserId(SecurityUtils.getUserId().intValue());//提交人 |
| | | insReport.setWriteTime(LocalDateTime.now());//提交时间 |
| | |
| | | } catch (IOException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 新版检测报告的结果表固定为四列:序号、检测项目、单位、检测结果。 |
| | | */ |
| | | private static List<Map<String, String>> buildDetectionResultRows(List<SampleProductDto> samples) { |
| | | List<Map<String, String>> rows = new ArrayList<>(); |
| | | if (CollectionUtils.isEmpty(samples)) { |
| | | return rows; |
| | | } |
| | | |
| | | boolean multipleSamples = samples.size() > 1; |
| | | int sequence = 1; |
| | | for (SampleProductDto sample : samples) { |
| | | if (CollectionUtils.isEmpty(sample.getInsProduct())) { |
| | | continue; |
| | | } |
| | | for (InsProduct product : sample.getInsProduct()) { |
| | | // 绑定项目仅参与计算,不应出现在报告中。 |
| | | if (product == null || Objects.equals(product.getIsBinding(), 1)) { |
| | | continue; |
| | | } |
| | | |
| | | String itemName = defaultReportText( |
| | | product.getInspectionItemSubclass(), |
| | | defaultReportText(product.getInspectionItem(), product.getInspectionItemClass())); |
| | | if (multipleSamples && StringUtils.isNotBlank(sample.getSampleCode())) { |
| | | itemName = sample.getSampleCode() + " - " + itemName; |
| | | } |
| | | |
| | | Map<String, String> row = new LinkedHashMap<>(); |
| | | row.put("seq", String.valueOf(sequence++)); |
| | | row.put("itemName", itemName); |
| | | row.put("unit", defaultReportText(product.getUnit(), "/")); |
| | | row.put("result", defaultReportText(product.getLastValue(), "/")); |
| | | rows.add(row); |
| | | } |
| | | } |
| | | return rows; |
| | | } |
| | | |
| | | private static String buildEquipmentText(List<Map<String, String>> deviceList) { |
| | | if (CollectionUtils.isEmpty(deviceList)) { |
| | | return "/"; |
| | | } |
| | | Set<String> lines = new LinkedHashSet<>(); |
| | | int sequence = 1; |
| | | for (Map<String, String> device : deviceList) { |
| | | String name = getMapText(device, "deviceName", "device_name"); |
| | | String managementNumber = getMapText(device, "managementNumber", "management_number"); |
| | | String line = sequence++ + ". " + defaultReportText(name, "/"); |
| | | if (StringUtils.isNotBlank(managementNumber)) { |
| | | line += ":" + managementNumber; |
| | | } |
| | | lines.add(line); |
| | | } |
| | | return String.join("\n", lines); |
| | | } |
| | | |
| | | private static String getMapText(Map<String, String> map, String... keys) { |
| | | if (map == null) { |
| | | return null; |
| | | } |
| | | for (String key : keys) { |
| | | String value = map.get(key); |
| | | if (StringUtils.isNotBlank(value)) { |
| | | return value; |
| | | } |
| | | for (Map.Entry<String, String> entry : map.entrySet()) { |
| | | if (entry.getKey() != null && entry.getKey().equalsIgnoreCase(key) |
| | | && StringUtils.isNotBlank(entry.getValue())) { |
| | | return entry.getValue(); |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private static String defaultReportText(String value, String fallback) { |
| | | if (StringUtils.isNotBlank(value)) { |
| | | return value; |
| | | } |
| | | return StringUtils.isNotBlank(fallback) ? fallback : "/"; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | } |
| | | // 检测报告不展示“结论”列,首行也要同步减少一个单元格, |
| | | // 否则首行为 max + 6 列、其余行为 max + 5 列,poi-tl 无法渲染表格。 |
| | | if (!showResult && !text.isEmpty()) { |
| | | text.remove(text.size() - 1); |
| | | } |
| | | TextRenderData[] text2 = text.toArray(new TextRenderData[0]); |
| | | rowRenderData = Rows.of(text2).center().rowAtleastHeight(1).create(); |
| | | rows.add(rowRenderData); |