package cn.iocoder.yudao.module.mes.service.qc.indicatorresult; import cn.iocoder.yudao.module.mes.controller.admin.qc.indicatorresult.vo.MesQcQcReportRespVO; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link MesQcProductReportWordBuilder} 的单元测试(版式冒烟:生成可读回 + 关键内容断言) * * 生成的样例文件会输出到 target/MesQcProductReportWordBuilder-sample.docx,可用 Word 人工核对版式。 */ public class MesQcProductReportWordBuilderTest { @Test public void testBuild() throws IOException { byte[] docx = MesQcProductReportWordBuilder.build(randomReport()); assertTrue(docx.length > 0); // 输出样例文件,便于人工用 Word 打开核对 Path sample = Path.of("target", "MesQcProductReportWordBuilder-sample.docx"); Files.createDirectories(sample.getParent()); try (OutputStreamHolder ignored = new OutputStreamHolder(sample, docx)) { // no-op } try (InputStream in = new ByteArrayInputStream(docx); XWPFDocument doc = new XWPFDocument(in)) { List tables = doc.getTables(); assertEquals(4, tables.size(), "表头/检验项目/判定结论/备注 共 4 张表"); // 表头首行:生产单位 + 公司名 assertTrue(tables.get(0).getRow(0).getCell(0).getText().contains("生产单位")); assertTrue(tables.get(0).getRow(0).getCell(1).getText().contains("宁夏九泓化工科技有限公司")); // 检验项目表:表头行 + 外观 + 分组展开的录入项(酸含量分组被隐藏) XWPFTable itemTable = tables.get(1); assertEquals(4, itemTable.getNumberOfRows()); assertEquals("外观", itemTable.getRow(1).getCell(0).getText().trim()); assertEquals("透明液体,无可见杂质", itemTable.getRow(1).getCell(1).getText().trim()); // 平行测量顿号合并 assertEquals("10.023、10.115", itemTable.getRow(2).getCell(1).getText().trim()); assertEquals("/", itemTable.getRow(3).getCell(1).getText().trim()); // 判定结论/质检专用章留空 assertTrue(itemTable.getRow(2).getCell(0).getText().contains("试样质量 m /g")); assertEquals("判定结论:", tables.get(2).getRow(0).getCell(0).getText().trim()); assertEquals("质检专用章:", tables.get(2).getRow(0).getCell(1).getText().trim()); // 备注默认文案 assertTrue(tables.get(3).getRow(0).getCell(1).getText().contains("检验结果仅对样品本身或本批次负责")); // 签字行留空(打印后手写),不得出现姓名 String signLine = doc.getParagraphs().stream() .filter(p -> p.getText().contains("批准:")) .findFirst().orElseThrow().getText(); assertTrue(signLine.contains("检验:") && signLine.contains("复核:")); assertTrue(!signLine.contains("李博") && !signLine.contains("周亚洁") && !signLine.contains("包翠萍"), "签字行应留空,不输出检验/复核/批准姓名"); } } private static MesQcQcReportRespVO randomReport() { MesQcQcReportRespVO report = new MesQcQcReportRespVO(); report.setQcType(3).setDocCode("OQC20260106001").setItemName("工业用正丁醇") .setBatchNo("20260100001").setSamplingLocation("成品正丁醇储罐(V0008A)") .setExecuteStandard("GB/T 6027-2023") .setSamplingTime(LocalDateTime.of(2026, 1, 6, 9, 0)) .setInspectDate(LocalDateTime.of(2026, 1, 6, 15, 0)) .setDocCreateTime(LocalDateTime.of(2026, 1, 6, 8, 0)) .setInspectorName("李博").setAuditName("周亚洁").setApproveName("包翠萍"); MesQcQcReportRespVO.ReportItem appearance = new MesQcQcReportRespVO.ReportItem(); appearance.setIndicatorName("外观").setItemType(1).setSortOrder(10); appearance.setMeasures(List.of(measure(1, "透明液体,无可见杂质"))); MesQcQcReportRespVO.ReportItem acidGroup = new MesQcQcReportRespVO.ReportItem(); acidGroup.setIndicatorName("酸含量").setItemType(2).setSortOrder(20); acidGroup.setFormulaText("w3 = c × V × 0.06005 / m × 100%"); MesQcQcReportRespVO.ReportItem mass = new MesQcQcReportRespVO.ReportItem(); mass.setIndicatorName("试样质量 m /g").setItemType(1).setSortOrder(1); mass.setMeasures(List.of(measure(1, "10.023"), measure(2, "10.115"))); acidGroup.setChildren(List.of(mass)); MesQcQcReportRespVO.ReportItem water = new MesQcQcReportRespVO.ReportItem(); water.setIndicatorName("水分,w/%,≤").setItemType(1).setSortOrder(30); water.setMeasures(List.of()); report.setItems(List.of(appearance, acidGroup, water)); report.setBatchQuantity(null); return report; } private static MesQcQcReportRespVO.ReportMeasure measure(int measureNo, String value) { MesQcQcReportRespVO.ReportMeasure measure = new MesQcQcReportRespVO.ReportMeasure(); measure.setMeasureNo(measureNo); measure.setValue(value); return measure; } /** try-with-resources 辅助:写出样例文件 */ private static class OutputStreamHolder implements AutoCloseable { OutputStreamHolder(Path path, byte[] content) throws IOException { Files.write(path, content); } @Override public void close() { } } }