From 8bc8a97e83e538878301b60070a911cc19a0a033 Mon Sep 17 00:00:00 2001 From: hongawen <83944980@qq.com> Date: Mon, 26 May 2025 14:26:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- detection/pom.xml | 15 + .../report/pojo/enums/BaseReportKeyEnum.java | 5 +- .../report/pojo/enums/BookmarkEnum.java | 56 ++ .../report/pojo/enums/PowerIndexEnum.java | 6 +- .../service/impl/PqReportServiceImpl.java | 477 ++++++++++++++++-- .../gather/report/utils/BookmarkUtil.java | 293 +++++++++++ .../njcn/gather/report/utils/Docx4jUtil.java | 138 ++++- .../service/impl/ResultServiceImpl.java | 173 +++++-- entrance/src/main/resources/application.yml | 2 +- 9 files changed, 1040 insertions(+), 125 deletions(-) create mode 100644 detection/src/main/java/com/njcn/gather/report/pojo/enums/BookmarkEnum.java create mode 100644 detection/src/main/java/com/njcn/gather/report/utils/BookmarkUtil.java diff --git a/detection/pom.xml b/detection/pom.xml index b615de17..536458db 100644 --- a/detection/pom.xml +++ b/detection/pom.xml @@ -76,6 +76,21 @@ + + + + + + + jakarta.xml.bind + jakarta.xml.bind-api + 2.3.3 + + + org.glassfish.jaxb + jaxb-runtime + 2.3.3 + org.docx4j docx4j diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/BaseReportKeyEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/BaseReportKeyEnum.java index 5e3c00f1..53d2a24e 100644 --- a/detection/src/main/java/com/njcn/gather/report/pojo/enums/BaseReportKeyEnum.java +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/BaseReportKeyEnum.java @@ -30,8 +30,9 @@ public enum BaseReportKeyEnum { MONTH("month","月份"), DAY("day","日"), YEAR_MONTH_DAY("year-month-day","年-月-日"), - TEMPERATURE("temperature","温度"), - HUMIDITY("humidity","相对湿度"); + TEMPERATURE("temp","温度"), + HUMIDITY("hum","相对湿度"), + DELEGATE("delegate","委托方"); private String key; diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/BookmarkEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/BookmarkEnum.java new file mode 100644 index 00000000..3c41b291 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/BookmarkEnum.java @@ -0,0 +1,56 @@ +package com.njcn.gather.report.pojo.enums; + +/** + * @author hongawen + * @version 1.0 + * @data 2025/5/22 9:46 + */ + +import lombok.Getter; + +/** + * 统计文档锚点类型 + * + * @author hongawen + * @version 1.0 + * @data 2025/3/24 18:42 + */ +@Getter +public enum BookmarkEnum { + + + DATA_LINE("data_line", "准确度数据展示区域,以测试回路维度展示", 1), + DATA_SCRIPT("data_script", "准确度数据展示区域,以检测项维度展示", 1), + TEST_RESULT_DEV("testResult_dev", "检测结论,仅有设备结论", 2), + TEST_RESULT_LINE("testResult_line", "检测结论,仅有回路结论", 2), + TEST_RESULT_DETAIL("testResult_detail", "检测结论,包含回路、设备结论", 2), + CATALOG("catalog", "目录信息", 3); + + private String key; + + private String desc; + + private Integer sort; + + BookmarkEnum(String key, String desc, Integer sort) { + this.key = key; + this.desc = desc; + this.sort = sort; + } + + /** + * 根据key找到适配的枚举 + * + * @param key 枚举的key + * @return 匹配的枚举实例,如果没有找到则返回null + */ + public static BookmarkEnum getByKey(String key) { + for (BookmarkEnum bookmarkEnum : BookmarkEnum.values()) { + if (bookmarkEnum.getKey().equalsIgnoreCase(key)) { + return bookmarkEnum; + } + } + return null; + } + +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/PowerIndexEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/PowerIndexEnum.java index 5fbc0ee8..26c04d9a 100644 --- a/detection/src/main/java/com/njcn/gather/report/pojo/enums/PowerIndexEnum.java +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/PowerIndexEnum.java @@ -16,9 +16,9 @@ public enum PowerIndexEnum { FREQ("FREQ", "频率"), V("V", "电压"), I("I", "电流"), - IMBV("IMBV", "三相电压不平衡度"), - IMBA("IMBA", "三相电流不平衡度"), - F("F", "闪变"), + IMBV("IMBV", "负序电压不平衡度"), + IMBA("IMBA", "负序电流不平衡度"), + F("F", "短时电压闪变"), HP("HP", "谐波有功功率"), HV("HV", "谐波电压"), HI("HI", "谐波电流"), diff --git a/detection/src/main/java/com/njcn/gather/report/service/impl/PqReportServiceImpl.java b/detection/src/main/java/com/njcn/gather/report/service/impl/PqReportServiceImpl.java index c36c8de4..17f26bb0 100644 --- a/detection/src/main/java/com/njcn/gather/report/service/impl/PqReportServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/report/service/impl/PqReportServiceImpl.java @@ -42,6 +42,7 @@ import com.njcn.gather.report.pojo.result.SingleTestResult; import com.njcn.gather.report.pojo.vo.Bookmark; import com.njcn.gather.report.pojo.vo.PqReportVO; import com.njcn.gather.report.service.IPqReportService; +import com.njcn.gather.report.utils.BookmarkUtil; import com.njcn.gather.report.utils.Docx4jUtil; import com.njcn.gather.report.utils.WordUtil; import com.njcn.gather.result.service.IResultService; @@ -71,10 +72,14 @@ import com.njcn.web.factory.PageFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.poi.xwpf.usermodel.*; +import org.docx4j.TraversalUtil; +import org.docx4j.finders.RangeFinder; import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.*; +import org.docx4j.wml.CTBookmark; +import org.docx4j.wml.Document; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; @@ -611,7 +616,8 @@ public class PqReportServiceImpl extends ServiceImpl i baseDocumentPart.variableReplace(baseModelDataMap); // 获取数据模版页内容,根据脚本动态组装数据页内容 MainDocumentPart detailDocumentPart = detailModelDocument.getMainDocumentPart(); - dealDataModelScattered(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO); +// dealDataModelScattered(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO); + dealDataModelScatteredByBookmark(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO); // 保存新的文档 String dirPath = reportPath.concat(File.separator).concat(devType.getName()); // 确保目录存在 @@ -626,6 +632,107 @@ public class PqReportServiceImpl extends ServiceImpl i }); } + + /** + * 通过提前在模板文档里埋下书签 + * 1、目录信息 + * 2、准确度测试详情 + * 3、测试结果页 + * 上述3个锚点位置不固定,可能结果页在通用信息中间,也有可能在文档最末端。 + * 注:当存在目录信息时,目录最后生成。 + * + * @param baseDocumentPart 通用信息文档 + * @param detailDocumentPart 数据项模板文档 + * @param devReportParam 测试报告参数 + * @param pqDevVO 被检设备 + */ + private void dealDataModelScatteredByBookmark(MainDocumentPart baseDocumentPart, MainDocumentPart detailDocumentPart, DevReportParam devReportParam, PqDevVO pqDevVO) { + // 查找 base 文档中所有书签 + List bookmarks = BookmarkUtil.findAllBookmarks(baseDocumentPart); + if (CollUtil.isNotEmpty(bookmarks)) { + // 转换为枚举,便于排序,防止结论性的书签在文档的前面 + List bookmarkEnums = new ArrayList<>(); + for (BookmarkUtil.BookmarkInfo info : bookmarks) { + String name = info.bookmark.getName(); + BookmarkEnum bookmarkEnum = BookmarkEnum.getByKey(name); + if (Objects.nonNull(bookmarkEnum)) { + bookmarkEnums.add(bookmarkEnum); + } + } + /* + * 从结构上分析,处理的顺序: + * 1、数据项 + * 2、结果信息 + * 3、目录信息 + * 所以要先先获取的书签进行操作排序 + * */ + Collections.sort(bookmarkEnums); + // 定义个结果,以便存在结果信息的书签 + Map> resultMap = new HashMap<>(); + List todoInsertList = new ArrayList<>(); + BookmarkUtil.BookmarkInfo bookmarkInfo = null; + // 书签在文档的位置 + for (int i = 0; i < bookmarkEnums.size(); i++) { + BookmarkEnum bookmarkEnum = bookmarkEnums.get(i); + switch (bookmarkEnum) { + case DATA_LINE: + // 获取标签信息 + bookmarkInfo = BookmarkUtil.getBookmarkInfo(BookmarkEnum.DATA_LINE.getKey(), bookmarks); + todoInsertList = dealDataLine(detailDocumentPart, devReportParam, pqDevVO, resultMap); + if (Objects.nonNull(bookmarkInfo) && CollectionUtil.isNotEmpty(todoInsertList)) { + BookmarkUtil.insertElement(bookmarkInfo, todoInsertList); + BookmarkUtil.removeBookmark(bookmarkInfo); + } + break; + case DATA_SCRIPT: + break; + case TEST_RESULT_DEV: + // 判断是否已经处理过数据了,有了结论性的描述 + if (CollUtil.isEmpty(resultMap)) { + dealDataLine(baseDocumentPart, devReportParam, pqDevVO, resultMap); + } + bookmarkInfo = BookmarkUtil.getBookmarkInfo(BookmarkEnum.TEST_RESULT_DEV.getKey(), bookmarks); + todoInsertList = dealTestResultLine(baseDocumentPart, detailDocumentPart, devReportParam, resultMap, DocAnchorEnum.TEST_RESULT_DEV); + if (Objects.nonNull(bookmarkInfo) && CollectionUtil.isNotEmpty(todoInsertList)) { + BookmarkUtil.insertElement(bookmarkInfo, todoInsertList); + BookmarkUtil.removeBookmark(bookmarkInfo); + } + break; + case TEST_RESULT_LINE: + // 判断是否已经处理过数据了,有了结论性的描述 + if (CollUtil.isEmpty(resultMap)) { + dealDataLine(baseDocumentPart, devReportParam, pqDevVO, resultMap); + } + bookmarkInfo = BookmarkUtil.getBookmarkInfo(BookmarkEnum.TEST_RESULT_LINE.getKey(), bookmarks); + todoInsertList = dealTestResultLine(baseDocumentPart, detailDocumentPart, devReportParam, resultMap, DocAnchorEnum.TEST_RESULT_LINE); + if (Objects.nonNull(bookmarkInfo) && CollectionUtil.isNotEmpty(todoInsertList)) { + BookmarkUtil.insertElement(bookmarkInfo, todoInsertList); + BookmarkUtil.removeBookmark(bookmarkInfo); + } + break; + case TEST_RESULT_DETAIL: + // 判断是否已经处理过数据了,有了结论性的描述 + if (CollUtil.isEmpty(resultMap)) { + dealDataLine(baseDocumentPart, devReportParam, pqDevVO, resultMap); + } + bookmarkInfo = BookmarkUtil.getBookmarkInfo(BookmarkEnum.TEST_RESULT_LINE.getKey(), bookmarks); + todoInsertList = dealTestResultLine(baseDocumentPart, detailDocumentPart, devReportParam, resultMap, DocAnchorEnum.TEST_RESULT_DETAIL); + if (Objects.nonNull(bookmarkInfo) && CollectionUtil.isNotEmpty(todoInsertList)) { + BookmarkUtil.insertElement(bookmarkInfo, todoInsertList); + BookmarkUtil.removeBookmark(bookmarkInfo); + } + break; + case CATALOG: + break; + default: + break; + } + } + } + + } + + /** * 通用基础信息文档里可能会存在的书签锚点 * 1、目录信息 @@ -728,7 +835,7 @@ public class PqReportServiceImpl extends ServiceImpl i ObjectFactory factory = Context.getWmlObjectFactory(); // 结论 P newParagraph = factory.createP(); - Docx4jUtil.createTitle(factory, newParagraph, "检测结论", 28, true); + Docx4jUtil.createTitle(factory, newParagraph, "检测结论", 24, true); //插入段落 paragraphs.add(position++, newParagraph); // 源文档的内容 @@ -757,8 +864,10 @@ public class PqReportServiceImpl extends ServiceImpl i default: break; } + List centerFlag = new ArrayList<>(); + centerFlag.add(0); + Tr titleRow = Docx4jUtil.createCustomRow(factory, title, "Arial", "宋体", 21, true, centerFlag); - Tr titleRow = Docx4jUtil.createCustomRow(factory, title, "SimSun", "宋体", 21, true, false); table.getContent().add(titleRow); // 处理业务数据 resultMap.forEach((key, value) -> { @@ -790,7 +899,7 @@ public class PqReportServiceImpl extends ServiceImpl i default: break; } - Tr tempRow = Docx4jUtil.createCustomRow(factory, cellValues, "SimSun", "宋体", 21, false, false); + Tr tempRow = Docx4jUtil.createCustomRow(factory, cellValues, "Arial", "宋体", 21, false, centerFlag); table.getContent().add(tempRow); }); TblPr tblPr = Docx4jUtil.getTblPr(factory); @@ -807,6 +916,103 @@ public class PqReportServiceImpl extends ServiceImpl i } + /** + * 如何处理结果性数据进文档,各省级平台的结果表格不一致,如何做到一致 + * + * @param baseDocumentPart 基础模板文档 + * @param detailDocumentPart 数据模板文档 + * @param resultMap 各测试项的结果 + */ + private List dealTestResultLine(MainDocumentPart baseDocumentPart, MainDocumentPart detailDocumentPart, DevReportParam devReportParam, Map> resultMap, DocAnchorEnum docAnchorEnum) { + List todoInsertList = new ArrayList<>(); + // 先判断数据有没有,如果没有,则不处理 + if (CollUtil.isEmpty(resultMap.get(PowerIndexEnum.UNKNOWN.getKey()))) { + ObjectFactory factory = Context.getWmlObjectFactory(); + // 源文档的内容 + // 创建表格(示例为3列,列数可任意调整) + Tbl table = factory.createTbl(); + List> tempResultList = new ArrayList<>(resultMap.values()); + int lineNum = tempResultList.get(0).size(); + // 处理表头 + List title = new ArrayList<>(); + title.add("检测项目"); + switch (docAnchorEnum) { + case TEST_RESULT_DEV: + title.add("结论"); + break; + case TEST_RESULT_LINE: + for (int i = 1; i < lineNum + 1; i++) { + title.add("测量回路" + i); + } + break; + case TEST_RESULT_DETAIL: + for (int i = 1; i < lineNum + 1; i++) { + title.add("测量回路" + i); + } + title.add("结论"); + break; + default: + break; + } + List centerFlag = new ArrayList<>(); + centerFlag.add(0); + Tr titleRow = Docx4jUtil.createCustomRow(factory, title, "Arial", "宋体", 21, true, centerFlag); + table.getContent().add(titleRow); + + // 处理业务数据 + List pqScriptDtlsList = pqScriptDtlsService.getScriptDtlsDataList(devReportParam.getScriptId()); + pqScriptDtlsList.sort(Comparator.comparing(PqScriptDtlDataVO::getScriptIndex)); + Set scriptCodeSet = new HashSet<>(); + for (PqScriptDtlDataVO pqScriptDtlDataVO : pqScriptDtlsList) { + String scriptCode = pqScriptDtlDataVO.getScriptCode(); + if (scriptCodeSet.contains(scriptCode)) { + continue; + } else { + scriptCodeSet.add(scriptCode); + } + List value = resultMap.get(scriptCode); + List cellValues = new ArrayList<>(); + PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(scriptCode); + if (indexEnum != null) { + if (scriptCode.equals(PowerIndexEnum.VOLTAGE.getKey())) { + cellValues.add(indexEnum.getDesc()); + } else { + cellValues.add(indexEnum.getDesc().concat("测量准确度")); + } + } else { + cellValues.add(PowerIndexEnum.UNKNOWN.getDesc().concat("测量准确度")); + } + // 判断是否有不合格的 + List totalValue = value.stream().filter(item -> !item).collect(Collectors.toList()); + String total = !totalValue.isEmpty() ? "不合格" : "合格"; + switch (docAnchorEnum) { + case TEST_RESULT_DEV: + cellValues.add(total); + break; + case TEST_RESULT_LINE: + for (int i = 0; i < value.size(); i++) { + cellValues.add(value.get(i) ? "合格" : "不合格"); + } + break; + case TEST_RESULT_DETAIL: + for (int i = 0; i < value.size(); i++) { + cellValues.add(value.get(i) ? "合格" : "不合格"); + } + cellValues.add(total); + break; + default: + break; + } + Tr tempRow = Docx4jUtil.createCustomRow(factory, cellValues, "Arial", "宋体", 21, false, centerFlag); + table.getContent().add(tempRow); + } + TblPr tblPr = Docx4jUtil.getTblPr(factory); + table.setTblPr(tblPr); + todoInsertList.add(table); + } + return todoInsertList; + } + /** * 处理以回路为维度的数据项 @@ -895,6 +1101,87 @@ public class PqReportServiceImpl extends ServiceImpl i } + + /** + * 处理以回路为维度的数据项,书签占位符的方式 + * + * @param detailModelDocument 数据项模板 + * @param devReportParam 测试报告参数 + * @param pqDevVO 被检设备 + */ + private List dealDataLine(MainDocumentPart detailModelDocument, DevReportParam devReportParam, PqDevVO pqDevVO, Map> resultMap) { + List todoInsertList = new ArrayList<>(); + // 以回路维度处理数据项 + Integer devChns = pqDevVO.getDevChns(); + ObjectFactory factory = new ObjectFactory(); + // 读取该计划的检测大项组装数据内容 + List pqScriptDtlsList = pqScriptDtlsService.getScriptDtlsDataList(devReportParam.getScriptId()); + Map> scriptMap = pqScriptDtlsList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptCode, LinkedHashMap::new, Collectors.toList())); + List allContent = detailModelDocument.getContent(); + List headingContents = Docx4jUtil.extractHeading5Contents(allContent); + Map> contentMap = headingContents.stream().collect(Collectors.groupingBy(Docx4jUtil.HeadingContent::getHeadingText, Collectors.toList())); + for (int i = 0; i < devChns; i++) { + // 回路标题 + P titleParagraph = factory.createP(); + Integer lineNo = i + 1; + Docx4jUtil.createTitle(factory, titleParagraph, "测量回路" + lineNo, 28, true); + todoInsertList.add(titleParagraph); + // 依次处理大项文档内容 + Iterator>> iterator = scriptMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> next = iterator.next(); + String scriptCode = next.getKey(); + List dtlScriptItemList = next.getValue(); + List tempContent = contentMap.get(scriptCode); + // 获取需要填充keys,索引0对应的段落key,索引1对应的表格key + List> keys = Docx4jUtil.getFillKeys(tempContent); + // 段落keys值赋值 + List pKeys = keys.get(0); + Map pKeyValueMap = resultService.getParagraphKeysValue(scriptCode, pKeys); + List tableKeys = keys.get(1); + /* tableKeys值赋值,注:由于谐波类检测数据与非谐波检测类数据的区别,此处要做区分 + * 1、谐波类每个scriptIndex对应一个Excel表格 + * 2、非谐波类则是一个误差范围对应一个Excel表格 + */ + SingleTestResult singleTestResult = null; + // 根据code找到名称 + List scriptResult = resultMap.get(scriptCode); + boolean needFill = false; + if (CollUtil.isEmpty(scriptResult)) { + scriptResult = new ArrayList<>(); + needFill = true; + } else if (scriptResult.size() < lineNo) { + needFill = true; + } + if (PowerConstant.TIME.contains(scriptCode)) { + // 谐波类,以scriptIndex区分 + Map> scriptIndexMap = dtlScriptItemList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptIndex)); + for (List scriptDtlDataItem : scriptIndexMap.values()) { + singleTestResult = resultService.getFinalContent(scriptDtlDataItem, devReportParam.getPlanCode(), pqDevVO.getId(), lineNo, tableKeys); + List tempList = fillContentInTemplate(singleTestResult.getDetail(), tempContent, factory, pKeyValueMap, tableKeys); + todoInsertList.addAll(tempList); + } + } else { + // 非谐波类 + singleTestResult = resultService.getFinalContent(dtlScriptItemList, devReportParam.getPlanCode(), pqDevVO.getId(), lineNo, tableKeys); + List tempList = fillContentInTemplate(singleTestResult.getDetail(), tempContent, factory, pKeyValueMap, tableKeys); + todoInsertList.addAll(tempList); + } + if (Objects.nonNull(singleTestResult) && needFill) { + singleTestResult.setScriptCode(scriptCode); + scriptResult.add(singleTestResult.isQualified()); + resultMap.put(scriptCode, scriptResult); + } + } + } + // 如果经过一顿处理后,结果性数据集合还是空,塞个特殊数据进去,避免嵌套循环 + if (CollUtil.isEmpty(resultMap)) { + resultMap.put(PowerIndexEnum.UNKNOWN.getKey(), Collections.singletonList(false)); + } + return todoInsertList; + } + + /** * 将查询的所有有效数据填充到模板中 */ @@ -926,20 +1213,24 @@ public class PqReportServiceImpl extends ServiceImpl i P paragraph = (P) object; // 获取该段落的样式 RPr rPr = Docx4jUtil.getTcPrFromParagraph(paragraph); + PPr pPr = paragraph.getPPr(); String textFromP = Docx4jUtil.getTextFromP(paragraph); if (StrUtil.isNotBlank(textFromP)) { - // 如果是段落内容,渲染段落内容 - String[] splitP = textFromP.split(StrPool.DASHED); String text = ""; - for (String item : splitP) { - if (StrUtil.isNotBlank(pKeyValueMap.get(item))) { - text = text.concat(pKeyValueMap.get(item)); - } else if (item.equalsIgnoreCase(ItemReportKeyEnum.ERROR_SCOPE.getKey())) { - text = text.concat("(").concat("最大允许误差:").concat(key1).concat(")"); + if (textFromP.equalsIgnoreCase(ItemReportKeyEnum.SCRIPT_DETAIL.getKey())) { + text = value1.get(0).get(ItemReportKeyEnum.SCRIPT_DETAIL.getKey()); + } else if (textFromP.startsWith(ItemReportKeyEnum.NAME.getKey())) { + // 如果是段落内容,渲染段落内容 + String[] splitP = textFromP.split(StrPool.DASHED); + for (String item : splitP) { + if (StrUtil.isNotBlank(pKeyValueMap.get(item))) { + text = text.concat(pKeyValueMap.get(item)); + } else if (item.equalsIgnoreCase(ItemReportKeyEnum.ERROR_SCOPE.getKey())) { + text = text.concat("(").concat("最大允许误差:").concat(key1).concat(")"); + } } - // 目前段落只有名称+误差范围,如果有补充后续在这里加。todo... } - Docx4jUtil.addPContent(factory, innerP, text, rPr); + Docx4jUtil.addPContent(factory, innerP, text, rPr,pPr); } //插入段落 paragraphs.add(position++, innerP); @@ -978,15 +1269,13 @@ public class PqReportServiceImpl extends ServiceImpl i // 纵向表格暂不考虑 } // 插入段落,处理下样式 - - paragraphs.add(position++, copiedTableElement); } } // 全部渲染完毕后,添加几个换行 P p = factory.createP(); - Docx4jUtil.addBr(factory, p, 1); - paragraphs.add(position++, p); +// Docx4jUtil.addBr(factory, p, 1); +// paragraphs.add(position++, p); } } @@ -996,6 +1285,116 @@ public class PqReportServiceImpl extends ServiceImpl i return position; } + /** + * 将查询的所有有效数据填充到集合中,待后续填充文档 + */ + private List fillContentInTemplate(Map>>>> finalContent, List tempContent, + ObjectFactory factory, Map pKeyValueMap, List tableKeys) { + List todoInsertList = new ArrayList<>(); + if (CollUtil.isNotEmpty(finalContent)) { + Iterator>>>>> iterator1 = finalContent.entrySet().iterator(); + while (iterator1.hasNext()) { + Map.Entry>>>> next1 = iterator1.next(); + // 此处的key是影响量的文字描述 + String key = next1.getKey(); + List>>> value = next1.getValue(); + for (Map>> stringListMap : value) { + Iterator>>> iterator2 = stringListMap.entrySet().iterator(); + while (iterator2.hasNext()) { + Map.Entry>> next2 = iterator2.next(); + // 此处的key是误差范围 + String key1 = next2.getKey(); + List> value1 = next2.getValue(); + // 填充模板内容 + if (CollUtil.isNotEmpty(tempContent)) { + // 读取该表下模板里面的内容,并动态赋值渲染文档 + Docx4jUtil.HeadingContent headingContent = tempContent.get(0); + for (Object object : headingContent.getSubContent()) { + // 段落 + if (object instanceof P) { + P innerP = factory.createP(); + // 如果是段落,渲染段落内容 + P paragraph = (P) object; + // 获取该段落的样式 + RPr rPr = Docx4jUtil.getTcPrFromParagraph(paragraph); + PPr pPr = paragraph.getPPr(); + String textFromP = Docx4jUtil.getTextFromP(paragraph); + if (StrUtil.isNotBlank(textFromP)) { + String text = ""; + if (textFromP.equalsIgnoreCase(ItemReportKeyEnum.SCRIPT_DETAIL.getKey())) { + text = value1.get(0).get(ItemReportKeyEnum.SCRIPT_DETAIL.getKey()); + System.out.println(text); + } else if (textFromP.startsWith(ItemReportKeyEnum.NAME.getKey())) { + // 如果是段落内容,渲染段落内容 + String[] splitP = textFromP.split(StrPool.DASHED); + for (String item : splitP) { + if (StrUtil.isNotBlank(pKeyValueMap.get(item))) { + text = text.concat(pKeyValueMap.get(item)); + } else if (item.equalsIgnoreCase(ItemReportKeyEnum.ERROR_SCOPE.getKey())) { + text = text.concat("(").concat("最大允许误差:").concat(key1).concat(")"); + } + } + } + Docx4jUtil.addPContent(factory, innerP, text, rPr,pPr); + } + //插入段落 + todoInsertList.add(innerP); + } else if (object instanceof JAXBElement) { + // 表格需要注意深拷贝,避免修改了原对象 + JAXBElement temp = (JAXBElement) object; + JAXBElement copiedTableElement; + try { + copiedTableElement = Docx4jUtil.deepCopyTbl(temp); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 解析表格并插入对应数据,最关键的是得知道表格是横向还是纵向以及表头占了几行 + Tbl tbl = copiedTableElement.getValue(); + // 获取表格的行 + List rows = tbl.getContent(); + boolean isRow = Docx4jUtil.judgeTableCross(rows.get(0)); + if (isRow) { + // 获取现有行的样式 + Tr headerRow = (Tr) tbl.getContent().get(0); + // 设置表头行属性 + TrPr headerTrPr = factory.createTrPr(); + headerRow.setTrPr(headerTrPr); + + // 获取现有行的样式 + Tr existingRow = (Tr) tbl.getContent().get(rows.size() - 1); + // 获取现有样式 + TrPr trPr = existingRow.getTrPr(); + JAXBElement element = (JAXBElement) existingRow.getContent().get(0); + TcPr tcPr = element.getValue().getTcPr(); + TblWidth cellWidth = factory.createTblWidth(); + cellWidth.setType("dxa"); + cellWidth.setW(BigInteger.valueOf(5000 / tableKeys.size())); + tcPr.setTcW(cellWidth); + tbl.getContent().remove(existingRow); + // 迭代增加行,需要填充的表格keys在tableKeys集合中 + for (Map stringStringMap : value1) { + Tr newRow = Docx4jUtil.createCustomRow(factory, stringStringMap, tableKeys, trPr, tcPr, true); + tbl.getContent().add(newRow); + } + } else { + // 纵向表格暂不考虑 + } + // 插入段落,处理下样式 + todoInsertList.add(copiedTableElement); + } + } + // 全部渲染完毕后,添加几个换行 +// P p = factory.createP(); +// Docx4jUtil.addBr(factory, p, 1); +// todoInsertList.add(p); + } + } + } + } + } + return todoInsertList; + } + private void updateDevAndPlanState(String devId, String planId) { // 将改设备的报告生成状态调整为已生成 @@ -1146,6 +1545,24 @@ public class PqReportServiceImpl extends ServiceImpl i } else { baseModelMap.put(prefix + BaseReportKeyEnum.MANUFACTURER.getKey() + suffix, StrPool.TAB); } + // 委托方 + String delegate = pqDevVO.getDelegate(); + if(StrUtil.isNotBlank(delegate)){ + DictData delegateDictData = dictDataService.getDictDataById(pqDevVO.getManufacturer()); + if (ObjectUtil.isNotNull(delegateDictData)) { + baseModelMap.put(prefix + BaseReportKeyEnum.DELEGATE.getKey() + suffix, dictData.getName()); + } else { + baseModelMap.put(prefix + BaseReportKeyEnum.DELEGATE.getKey() + suffix, StrPool.TAB); + } + }else{ + baseModelMap.put(prefix + BaseReportKeyEnum.DELEGATE.getKey() + suffix, StrPool.TAB); + } + + // 实验室温度 + baseModelMap.put(prefix + BaseReportKeyEnum.TEMPERATURE.getKey() + suffix, Objects.isNull(pqDevVO.getTemperature()) ? StrPool.TAB : pqDevVO.getTemperature().toString()); + // 实验室湿度 + baseModelMap.put(prefix + BaseReportKeyEnum.TEMPERATURE.getKey() + suffix, Objects.isNull(pqDevVO.getTemperature()) ? StrPool.TAB : pqDevVO.getTemperature().toString()); + // 样品编号 baseModelMap.put(prefix + BaseReportKeyEnum.SAMPLE_ID.getKey() + suffix, StrUtil.isEmpty(pqDevVO.getSampleId()) ? StrPool.TAB : pqDevVO.getSampleId()); // 收样日期 @@ -2047,32 +2464,6 @@ public class PqReportServiceImpl extends ServiceImpl i } - public static void main(String[] args) throws IOException { - String path = "F:\\gitea\\fusionForce\\CN_Gather\\entrance\\src\\main\\resources\\model\\BaseDataModel.docx"; - FileInputStream dataModelFis = new FileInputStream(new File(path)); - XWPFDocument dataModelDocumentTemp = new XWPFDocument(dataModelFis); - Map dataModelMap = new HashMap<>(16); - dataModelMap.put("${CreateId}", "123"); - dataModelMap.put("${total}", "123"); - dataModelMap.put("${count}", "1"); - dataModelMap.put("${57Ua}", "123456"); - dataModelMap.put("${Uha1}", "123456"); - dataModelMap.put("${Uha2}", "123456"); - WordUtil.replacePlaceholdersInParagraphs(dataModelDocumentTemp, dataModelMap); - WordUtil.replacePlaceholdersInTables(dataModelDocumentTemp, dataModelMap); - //最终文件输出的路径 - FileOutputStream out = new FileOutputStream("C:\\Users\\hongawen\\Desktop\\testModel\\BaseDataModel" + DateUtil.format(new Date(), DatePattern.CHINESE_DATE_TIME_PATTERN) + ".docx"); - // 4. 保存新的Word文档 - try { - dataModelDocumentTemp.write(out); - } catch (IOException e) { - throw new BusinessException("生成报告文件失败"); - } - out.close(); - System.out.println("报告生成成功!"); - } - - /** * 获取测试小项的index * 注:测试项下发的ABCT的index均是一样的 diff --git a/detection/src/main/java/com/njcn/gather/report/utils/BookmarkUtil.java b/detection/src/main/java/com/njcn/gather/report/utils/BookmarkUtil.java new file mode 100644 index 00000000..88da3827 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/utils/BookmarkUtil.java @@ -0,0 +1,293 @@ +package com.njcn.gather.report.utils; + + +import com.njcn.gather.report.pojo.enums.BookmarkEnum; +import com.njcn.gather.report.pojo.enums.PowerIndexEnum; +import org.docx4j.openpackaging.packages.WordprocessingMLPackage; +import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; +import org.docx4j.wml.*; + +import javax.xml.bind.JAXBElement; +import java.util.*; + + +/** + * 递归查找所有书签,并在书签处插入内容 + */ +public class BookmarkUtil { + + + /** + * 书签信息 + */ + public static class BookmarkInfo { + public CTBookmark bookmark; + public P parentParagraph; + public ContentAccessor parentContainer; + } + + /** + * 递归查找所有书签 + */ + public static List findAllBookmarks(ContentAccessor contentAccessor) { + List result = new ArrayList<>(); + for (Object obj : contentAccessor.getContent()) { + Object realObj = (obj instanceof JAXBElement) ? ((JAXBElement>) obj).getValue() : obj; + if (realObj instanceof P) { + P p = (P) realObj; + for (Object o2 : p.getContent()) { + Object realO2 = (o2 instanceof JAXBElement) ? ((JAXBElement>) o2).getValue() : o2; + if (realO2 instanceof CTBookmark) { + BookmarkInfo info = new BookmarkInfo(); + info.bookmark = (CTBookmark) realO2; + info.parentParagraph = p; + info.parentContainer = contentAccessor; + result.add(info); + } + } + } else if (realObj instanceof ContentAccessor) { + result.addAll(findAllBookmarks((ContentAccessor) realObj)); + } + } + return result; + } + + + /** + * 在书签后插入段落 + */ + public static void insertParagraphsAfter(BookmarkInfo info, P paragraph) { + List parentContent = info.parentContainer.getContent(); + int idx = parentContent.indexOf(info.parentParagraph); + parentContent.add(idx + 1, paragraph); + } + + /** + * 在书签后插入表格 + */ + public static void insertTableAfter(BookmarkInfo info, Tbl table) { + List parentContent = info.parentContainer.getContent(); + int idx = parentContent.indexOf(info.parentParagraph); + parentContent.add(idx + 1, table); + } + + /** + * 在书签后插入元素,可能是段落、表格、图片、书签等 + */ + public static void insertElement(BookmarkInfo info, List elements) { + List parentContent = info.parentContainer.getContent(); + int idx = parentContent.indexOf(info.parentParagraph); + // 遍历元素,如果是通道回路这种大标题需要新起一个空的文档页 + for (int i = 0; i < elements.size(); i++) { + Object element = elements.get(i); + if (element instanceof P) { + P p = (P) element; + String textFromP = Docx4jUtil.getTextFromP(p); + if (textFromP.contains("测量回路")) { + if (!textFromP.contains("1")) { + // 另起一页 + P pagePara = Docx4jUtil.getPageBreak(); + idx = idx + 1; + parentContent.add(idx, pagePara); + } + idx = idx + 1; + parentContent.add(idx, p); + } else if (textFromP.startsWith(PowerIndexEnum.IMBV.getDesc()) + || textFromP.startsWith(PowerIndexEnum.HV.getDesc()) + || textFromP.startsWith(PowerIndexEnum.HI.getDesc()) + + ) { + // 另起一页 + P pagePara = Docx4jUtil.getPageBreak(); + idx = idx + 1; + parentContent.add(idx, pagePara); + idx = idx + 1; + parentContent.add(idx, element); + }else if(textFromP.startsWith("注:基波电流幅值5.000A,基波频率50.0Hz,各次间谐波电流含有率均为3.0%。")){ + idx = idx + 1; + parentContent.add(idx, element); + P pagePara = Docx4jUtil.getPageBreak(); + idx = idx + 1; + parentContent.add(idx, pagePara); + } else { + idx = idx + 1; + parentContent.add(idx, element); + } + } else { + idx = idx + 1; + parentContent.add(idx, element); + } + } + } + + /** + * 删除文档中的空白页 + * @param docx 要处理的Word文档 + */ + public static void removeBlankPages(MainDocumentPart mainDocumentPart) { + // 获取文档主体 + Document document = mainDocumentPart.getJaxbElement(); + Body body = document.getBody(); + + // 获取所有段落 + List paragraphs = body.getContent(); + + // 用于标记是否在空白页中 + boolean inBlankPage = false; + // 用于存储要删除的段落 + List paragraphsToRemove = new ArrayList<>(); + + for (Object paragraph : paragraphs) { + if (paragraph instanceof P){ + P paragraphtemp = (P) paragraph; + // 检查段落是否为空 + boolean isEmpty = isParagraphEmpty(paragraphtemp); + + if (isEmpty) { + if (!inBlankPage) { + inBlankPage = true; + } + paragraphsToRemove.add(paragraphtemp); + } else { + inBlankPage = false; + } + } + } + + // 删除空白段落 + for (P paragraph : paragraphsToRemove) { + body.getContent().remove(paragraph); + } + } + + /** + * 检查段落是否为空 + * @param paragraph 要检查的段落 + * @return 如果段落为空返回true,否则返回false + */ + private static boolean isParagraphEmpty(P paragraph) { + // 检查段落是否包含分节符 + if (paragraph.getPPr() != null && paragraph.getPPr().getSectPr() != null) { + return false; + } + + // 检查段落中的文本内容 + for (Object obj : paragraph.getContent()) { + if (obj instanceof R) { + R run = (R) obj; + // 在3.3.4版本中,使用getContent()获取文本内容 + for (Object runContent : run.getContent()) { + if (runContent instanceof Text) { + Text text = (Text) runContent; + if (text.getValue() != null && !text.getValue().trim().isEmpty()) { + return false; + } + } + } + } + } + return true; + } + + + /** + * 在插入前检查目标位置是否有分页符 + * + * @param position 目标位置 + * @return 是否包含分页符 + */ + private static boolean hasPageBreak(Object position) { + if (position instanceof P) { + P paragraph = (P) position; + for (Object run : paragraph.getContent()) { + if (run instanceof R) { + R r = (R) run; + for (Object element : r.getContent()) { + if (element instanceof Br && ((Br) element).getType() != null + && ((Br) element).getType().equals("page")) { + return true; + } + } + } + } + return false; + } + return false; + } + + /** + * 删除书签 + * + * @param bookmarkInfo 书签信息 + */ + public static void removeBookmark(BookmarkUtil.BookmarkInfo bookmarkInfo) { + try { + // 获取书签所在的段落 + P paragraph = bookmarkInfo.parentParagraph; + + // 遍历段落内容,找到并删除书签开始和结束标记 + List paragraphContent = new ArrayList<>(paragraph.getContent()); + for (Object obj : paragraphContent) { + if (obj instanceof JAXBElement) { + JAXBElement> element = (JAXBElement>) obj; + Object value = element.getValue(); + + // 删除书签开始标记 + if (value instanceof CTBookmark) { + paragraph.getContent().remove(obj); + } + // 删除书签结束标记 + else if (value instanceof CTMarkupRange) { + paragraph.getContent().remove(obj); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 使用 ObjectFactory 创建表格 + * + * @param factory ObjectFactory 实例 + * @param data 二维数组,表格内容 + * @return Tbl 表格对象 + */ + public static Tbl createTable(ObjectFactory factory, String[][] data) { + Tbl table = factory.createTbl(); + for (String[] rowData : data) { + Tr row = factory.createTr(); + for (String cellData : rowData) { + Tc cell = factory.createTc(); + P para = factory.createP(); + R run = factory.createR(); + Text text = factory.createText(); + text.setValue(cellData); + run.getContent().add(text); + para.getContent().add(run); + cell.getContent().add(para); + row.getContent().add(cell); + } + table.getContent().add(row); + } + return table; + } + + /** + * 获取指定标签的标签信息 + * + * @param key 标签名 + * @param bookmarks 所有标签信息 + */ + public static BookmarkInfo getBookmarkInfo(String key, List bookmarks) { + BookmarkUtil.BookmarkInfo bookmarkInfo = null; + for (BookmarkUtil.BookmarkInfo info : bookmarks) { + String name = info.bookmark.getName(); + if (key.equalsIgnoreCase(name)) { + bookmarkInfo = info; + } + } + return bookmarkInfo; + } +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java index a20a40fc..e1f49020 100644 --- a/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java +++ b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java @@ -5,19 +5,12 @@ import cn.hutool.core.text.StrPool; import cn.hutool.core.util.StrUtil; import com.njcn.gather.report.pojo.constant.ReportConstant; import com.njcn.gather.report.pojo.enums.DocAnchorEnum; -import com.njcn.gather.report.pojo.vo.Bookmark; import org.docx4j.XmlUtils; -import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.*; import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import java.io.StringReader; -import java.io.StringWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -244,13 +237,14 @@ public class Docx4jUtil { /** * 段落中添加内容 */ - public static void addPContent(ObjectFactory factory, P paragraph, String content, RPr rPr) { + public static void addPContent(ObjectFactory factory, P paragraph, String content, RPr rPr,PPr ppr) { R run = factory.createR(); Text text = factory.createText(); text.setValue(content); run.setRPr(rPr); run.getContent().add(text); paragraph.getContent().add(run); + paragraph.setPPr(ppr); } /** @@ -347,6 +341,20 @@ public class Docx4jUtil { text.setValue(value); run.getContent().add(text); paragraph.getContent().add(run); + // 字体 + // 设置字体 + RPr rPr = factory.createRPr(); + RFonts rFonts = factory.createRFonts(); + if (containsChinese(value)) { + rFonts.setEastAsia("宋体"); + rFonts.setAscii("宋体"); + rFonts.setHAnsi("宋体"); + } else { + rFonts.setEastAsia("Arial"); + rFonts.setAscii("Arial"); + rFonts.setHAnsi("Arial"); + } + rPr.setRFonts(rFonts); // 设置段落居中 if (centerFlag) { PPr pPr = factory.createPPr(); @@ -356,13 +364,17 @@ public class Docx4jUtil { paragraph.setPPr(pPr); } if (value.equals("不合格")) { - RPr rPr = factory.createRPr(); Color color = factory.createColor(); // 红色 color.setVal("FF0000"); rPr.setColor(color); run.setRPr(rPr); } + HpsMeasure sz = factory.createHpsMeasure(); + // 10号字体 = 20 half-points + sz.setVal(new BigInteger("20")); + rPr.setSz(sz); + cell.getContent().add(paragraph); cell.setTcPr(tcPr); row.getContent().add(cell); @@ -372,20 +384,39 @@ public class Docx4jUtil { } + /** + * 判断字符串是否包含中文 + * @param str 需要判断的字符串 + * @return 是否包含中文 + */ + private static boolean containsChinese(String str) { + if (str == null) { + return false; + } + for (char c : str.toCharArray()) { + if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) { + return true; + } + } + return false; + } + + /** * 根据已知信息创建新行 * - * @param factory 工厂 - * @param cellValues 数据 + * @param factory 工厂 + * @param cellValues 数据 * @param ascFontStyle 西文字体 - * @param eastFontStyle 中文字体 - * @param size 字体大小 - * @param boldFlag 是否加粗 - * @param centerFlag 是否居中 + * @param eastFontStyle 中文字体 + * @param size 字体大小 + * @param boldFlag 是否加粗 + * @param centerFlag 是否居中 */ - public static Tr createCustomRow(ObjectFactory factory, List cellValues, String ascFontStyle,String eastFontStyle, Integer size, boolean boldFlag, boolean centerFlag) { + public static Tr createCustomRow(ObjectFactory factory, List cellValues, String ascFontStyle, String eastFontStyle, Integer size, boolean boldFlag, List centerFlag) { Tr row = factory.createTr(); - for (String value : cellValues) { + for (int i = 0; i < cellValues.size(); i++) { + String value = cellValues.get(i); Tc cell = factory.createTc(); P paragraph = factory.createP(); R run = factory.createR(); @@ -394,7 +425,7 @@ public class Docx4jUtil { run.getContent().add(text); paragraph.getContent().add(run); // 设置段落居中 - if (centerFlag) { + if (!centerFlag.contains(i)) { PPr pPr = factory.createPPr(); Jc jc = factory.createJc(); jc.setVal(JcEnumeration.CENTER); @@ -408,7 +439,7 @@ public class Docx4jUtil { color.setVal("FF0000"); rPr.setColor(color); } - if(boldFlag){ + if (boldFlag) { BooleanDefaultTrue bold = factory.createBooleanDefaultTrue(); rPr.setB(bold); } @@ -425,9 +456,20 @@ public class Docx4jUtil { rPr.setSz(fontSize); // 中文字号 rPr.setSzCs(fontSize); - run.setRPr(rPr); cell.getContent().add(paragraph); + // 设置单元格边距 + TcPr cellProperties = factory.createTcPr(); + cell.setTcPr(cellProperties); + // 设置单元格上下边距(单位:缇) + TcMar mar = factory.createTcMar(); + TblWidth top = factory.createTblWidth(); + top.setW(BigInteger.valueOf(100)); + mar.setTop(top); + TblWidth bottom = factory.createTblWidth(); + bottom.setW(BigInteger.valueOf(100)); + mar.setBottom(bottom); + cellProperties.setTcMar(mar); row.getContent().add(cell); } return row; @@ -448,7 +490,6 @@ public class Docx4jUtil { } - // 存储Heading 5及其子内容的辅助类 public static class HeadingContent { private String headingText; @@ -471,6 +512,38 @@ public class Docx4jUtil { } } + + /** + * 获取指定书签在文档段落中的位置索引 + * + * @param documentPart 主文档部分 + * @param bookmarkName 书签名称 + * @return 段落索引,找不到返回 -1 + */ + public static int getParagraphPosition(MainDocumentPart documentPart, String bookmarkName) { + List content = documentPart.getContent(); + for (int i = 0; i < content.size(); i++) { + Object obj = content.get(i); + // 只处理段落 + if (obj instanceof P) { + P paragraph = (P) obj; + // 提取段落纯文本 + String text = getTextFromP(paragraph).trim(); + if (text.startsWith("#{") && text.endsWith("}")) { + // 提取书签名 + String name = text.substring(2, text.length() - 1); + if (name.equals(bookmarkName)) { + // 返回段落索引 + return i; + } + } + } + } + // 找不到返回 -1 + return -1; + } + + /** * 获取段落在文档中的位置 */ @@ -534,4 +607,27 @@ public class Docx4jUtil { } + /** + * 获取分页符 + */ + public static P getPageBreak() { + try { + ObjectFactory factory = new ObjectFactory(); + // 创建分页符 + R run = factory.createR(); + Br br = factory.createBr(); + br.setType(STBrType.PAGE); + // 直接添加 br 对象 + run.getContent().add(br); + // 创建包含分页符的段落 + P pageBreakParagraph = factory.createP(); + pageBreakParagraph.getContent().add(run); + return pageBreakParagraph; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + } diff --git a/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java b/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java index 07381351..c504df7e 100644 --- a/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java @@ -1015,10 +1015,8 @@ public class ResultServiceImpl implements IResultService { double timeDouble = Math.round(harmNum); int timeInt = (int) timeDouble; // 填充结果数据 - fillThreePhaseData(singleResult, timeInt, keyFillMap); - if (!keyFillMap.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()).equals("/")) { - keyFillMapList.add(keyFillMap); - } + fillThreePhaseData(singleResult, timeInt, keyFillMap, scriptCode); + keyFillMapList.add(keyFillMap); }); if (CollUtil.isNotEmpty(keyFillMapList)) { // 按次数排序 @@ -1045,10 +1043,8 @@ public class ResultServiceImpl implements IResultService { List> keyFillMapList = new ArrayList<>(); for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { Map keyFillMap = new HashMap<>(16); - fillThreePhaseData(adNonHarmonicResult, null, keyFillMap); - if (!keyFillMap.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()).equals("/")) { - keyFillMapList.add(keyFillMap); - } + fillThreePhaseData(adNonHarmonicResult, null, keyFillMap, scriptCode); + keyFillMapList.add(keyFillMap); } if (CollUtil.isNotEmpty(keyFillMapList)) { // 需要对所有的填充进行按误差范围分组 @@ -1075,9 +1071,7 @@ public class ResultServiceImpl implements IResultService { for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { Map keyFillMap = new HashMap<>(8); fillTPhaseData(adNonHarmonicResult, null, keyFillMap); - if (!keyFillMap.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()).equals("/")) { - keyFillMapList.add(keyFillMap); - } + keyFillMapList.add(keyFillMap); } } if (CollUtil.isNotEmpty(keyFillMapList)) { @@ -1120,7 +1114,7 @@ public class ResultServiceImpl implements IResultService { * @param timeInt 谐波类需要传指定次数 * @param keyFillMap 待填充的集合Map */ - private void fillThreePhaseData(Object singleResult, Integer timeInt, Map keyFillMap) { + private void fillThreePhaseData(Object singleResult, Integer timeInt, Map keyFillMap, String scriptCode) { DetectionData tempA = getResultData(singleResult, timeInt, PowerConstant.PHASE_A); DetectionData tempB = getResultData(singleResult, timeInt, PowerConstant.PHASE_B); DetectionData tempC = getResultData(singleResult, timeInt, PowerConstant.PHASE_C); @@ -1129,50 +1123,64 @@ public class ResultServiceImpl implements IResultService { testA = "/", testB = "/", testC = "/", errorA = "/", errorB = "/", errorC = "/", resultA = "/", resultB = "/", resultC = "/", result = "/", - errorScope = "/", unit = ""; + errorScope = "/", unit = "", scriptDetail = "/"; - if (Objects.nonNull(tempA) && (PowerConstant.DATA_RANGE.contains(tempA.getIsData()))) { - standardA = PubUtils.doubleRoundStr(4, tempA.getResultData()); - testA = PubUtils.doubleRoundStr(4, tempA.getData()); - errorA = PubUtils.doubleRoundStr(4, tempA.getErrorData().doubleValue()); - resultA = tempA.getIsData() == 1 ? "合格" : "不合格"; - errorScope = tempA.getRadius(); - unit = tempA.getUnit(); - standard = PubUtils.doubleRoundStr(4, tempA.getResultData()); + if (Objects.nonNull(tempA)) { + standardA = PubUtils.doubleRoundStr(4, tempA.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getResultData()); + testA = PubUtils.doubleRoundStr(4, tempA.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getData()); + if (Objects.nonNull(tempA.getErrorData())) { + errorA = PubUtils.doubleRoundStr(4, tempA.getErrorData().doubleValue()); + } + resultA = tempA.getIsData() == 1 ? "合格" : tempA.getIsData() == 0 ? "不合格" : "/"; + errorScope = tempA.getRadius() == null ? "/" : tempA.getRadius(); + unit = tempA.getUnit() == null ? "" : tempA.getUnit(); + standard = PubUtils.doubleRoundStr(4, tempA.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getResultData()); } - if (Objects.nonNull(tempB) && (PowerConstant.DATA_RANGE.contains(tempB.getIsData()))) { - standardB = PubUtils.doubleRoundStr(4, tempB.getResultData()); - testB = PubUtils.doubleRoundStr(4, tempB.getData()); - errorB = PubUtils.doubleRoundStr(4, tempB.getErrorData().doubleValue()); - resultB = tempB.getIsData() == 1 ? "合格" : "不合格"; + if (Objects.nonNull(tempB)) { + standardB = PubUtils.doubleRoundStr(4, tempB.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getResultData()); + testB = PubUtils.doubleRoundStr(4, tempB.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getData()); + if (Objects.nonNull(tempB.getErrorData())) { + errorB = PubUtils.doubleRoundStr(4, tempB.getErrorData().doubleValue()); + } + resultB = tempB.getIsData() == 1 ? "合格" : tempB.getIsData() == 0 ? "不合格" : "/"; if (errorScope.equals("/")) { - errorScope = tempB.getRadius(); + errorScope = tempB.getRadius() == null ? "/" : tempB.getRadius(); } if (StrUtil.isBlank(unit)) { - unit = tempB.getUnit(); + unit = tempB.getUnit() == null ? "" : tempB.getUnit(); } if (standard.equals("/")) { - standard = PubUtils.doubleRoundStr(4, tempB.getResultData()); + standard = PubUtils.doubleRoundStr(4, tempB.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getResultData()); } } - if (Objects.nonNull(tempC) && (PowerConstant.DATA_RANGE.contains(tempC.getIsData()))) { - standardC = PubUtils.doubleRoundStr(4, tempC.getResultData()); - testC = PubUtils.doubleRoundStr(4, tempC.getData()); - errorC = PubUtils.doubleRoundStr(4, tempC.getErrorData().doubleValue()); - resultC = tempC.getIsData() == 1 ? "合格" : "不合格"; + if (Objects.nonNull(tempC)) { + standardC = PubUtils.doubleRoundStr(4, tempC.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getResultData()); + testC = PubUtils.doubleRoundStr(4, tempC.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getData()); + if (Objects.nonNull(tempC.getErrorData())) { + errorC = PubUtils.doubleRoundStr(4, tempC.getErrorData().doubleValue()); + } + resultC = tempC.getIsData() == 1 ? "合格" : tempC.getIsData() == 0 ? "不合格" : "/"; if (errorScope.equals("/")) { - errorScope = tempC.getRadius(); + errorScope = tempC.getRadius() == null ? "/" : tempC.getRadius(); } if (StrUtil.isBlank(unit)) { - unit = tempC.getUnit(); + unit = tempC.getUnit() == null ? "" : tempC.getUnit(); } if (standard.equals("/")) { - standard = PubUtils.doubleRoundStr(4, tempC.getResultData()); + standard = PubUtils.doubleRoundStr(4, tempC.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getResultData()); } } + if (scriptCode.equalsIgnoreCase("I")) { + resultA = "/"; + resultB = "/"; + resultC = "/"; + } if (standardA.equals(standardB) && standardA.equals(standardC)) { standard = standardA; } + // 处理脚本输出 + scriptDetail = dealScriptDetail(scriptCode, standard); + keyFillMap.put(ItemReportKeyEnum.SCRIPT_DETAIL.getKey(), scriptDetail); // 标准值 keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); keyFillMap.put(ItemReportKeyEnum.STANDARD_A.getKey(), standardA); @@ -1200,6 +1208,45 @@ public class ResultServiceImpl implements IResultService { keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope); } + /** + * 针对浙江杭州处理脚本输出细节,todo... 需要更改更合理的方式,现在算是写死的了部分 + * 目前浙江这边就是(间)谐波电压/电流 + */ + private String dealScriptDetail(String scriptCode, String standard) { + String scriptDetail = ""; + PowerIndexEnum powerIndexEnum = PowerIndexEnum.getByKey(scriptCode); + if (powerIndexEnum != null) { + switch (powerIndexEnum) { + case HV: + case HSV: + // 注:基波电压幅值57.74V,基波频率50.0Hz。 + scriptDetail = "注:基波电压幅值57.74V,基波频率50.0Hz。"; + break; + case HI: + // 电流是幅值,需要与5A得出百分比 + try { + String temp = PubUtils.doubleRoundStr(1, (Double.parseDouble(standard) / 5.0) * 100); + scriptDetail = "注:基波电流幅值5.000A,基波频率50.0Hz,各次谐波电流含有率均为" + temp + "%。"; + } catch (Exception e) { + log.error("dealScriptDetail error:{}", e); + } + break; + case HSI: + // 电流是幅值,需要与5A得出百分比 + try { + String temp = PubUtils.doubleRoundStr(1, (Double.parseDouble(standard) / 5.0) * 100); + scriptDetail = "注:基波电流幅值5.000A,基波频率50.0Hz,各次间谐波电流含有率均为" + temp + "%。"; + } catch (Exception e) { + log.error("dealScriptDetail error:{}", e); + } + break; + default: + break; + } + } + return scriptDetail; + } + /** * T相的相关数据处理,非暂态数据 @@ -1212,13 +1259,15 @@ public class ResultServiceImpl implements IResultService { private void fillTPhaseData(Object singleResult, Integer timeInt, Map keyFillMap) { String standard = "/", test = "/", error = "/", result = "/", errorScope = "/", unit = ""; DetectionData tempT = getResultData(singleResult, timeInt, PowerConstant.PHASE_T); - if (Objects.nonNull(tempT) && PowerConstant.DATA_RANGE.contains(tempT.getIsData())) { - standard = PubUtils.doubleRoundStr(4, tempT.getResultData()); - test = PubUtils.doubleRoundStr(4, tempT.getData()); - error = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); - result = tempT.getIsData() == 1 ? "合格" : "不合格"; - unit = tempT.getUnit(); - errorScope = tempT.getRadius(); + if (Objects.nonNull(tempT)) { + standard = PubUtils.doubleRoundStr(4, tempT.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getResultData()); + test = PubUtils.doubleRoundStr(4, tempT.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getData()); + if (Objects.nonNull(tempT.getErrorData())) { + error = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); + } + result = tempT.getIsData() == 1 ? "合格" : tempT.getIsData() == 0 ? "不合格" : "/"; + unit = tempT.getUnit() == null ? "" : tempT.getUnit(); + errorScope = tempT.getRadius() == null ? "/" : tempT.getRadius(); } keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); keyFillMap.put(ItemReportKeyEnum.TEST.getKey(), test); @@ -1249,11 +1298,13 @@ public class ResultServiceImpl implements IResultService { DictTree temp = dictTreeService.getById(adType); if (temp.getCode().equalsIgnoreCase("MAG")) { // 特征幅值 - if (Objects.nonNull(tempT) && PowerConstant.DATA_RANGE.contains(tempT.getIsData())) { - standardMag = PubUtils.doubleRoundStr(4, tempT.getResultData()); - testMag = PubUtils.doubleRoundStr(4, tempT.getData()); - errorMag = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); - resultMag = tempT.getIsData() == 1 ? "合格" : "不合格"; + if (Objects.nonNull(tempT)) { + standardMag = PubUtils.doubleRoundStr(4, tempT.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getResultData()); + testMag = PubUtils.doubleRoundStr(4, tempT.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getData()); + if (Objects.nonNull(tempT.getErrorData())) { + errorMag = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); + } + resultMag = tempT.getIsData() == 1 ? "合格" : tempT.getIsData() == 0 ? "不合格" : "/"; unitMag = tempT.getUnit(); errorScopeMag = tempT.getRadius(); } @@ -1271,12 +1322,24 @@ public class ResultServiceImpl implements IResultService { } } } - standardDur = PubUtils.doubleRoundStr(4, tempT.getResultData()); - testDur = PubUtils.doubleRoundStr(4, tempT.getData()); - errorDur = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); - resultDur = tempT.getIsData() == 1 ? "合格" : "不合格"; - unitDur = tempT.getUnit(); - errorScopeDur = tempT.getRadius(); + if (Objects.nonNull(tempT.getResultData())) { + standardDur = PubUtils.doubleRoundStr(4, tempT.getResultData()); + } + if (Objects.nonNull(tempT.getData())) { + testDur = PubUtils.doubleRoundStr(4, tempT.getData()); + } + if (Objects.nonNull(tempT.getErrorData())) { + testDur = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); + } + if (Objects.nonNull(tempT.getIsData())) { + resultDur = tempT.getIsData() == 1 ? "合格" : "不合格"; + } + if (StrUtil.isNotBlank(tempT.getUnit())) { + unitDur = tempT.getUnit(); + } + if (StrUtil.isNotBlank(tempT.getRadius())) { + errorScopeDur = tempT.getRadius(); + } if (timeUnit.equalsIgnoreCase("ms")) { // 如果是ms,上述的一些数据需要重新处理 if (!standardDur.equalsIgnoreCase("/")) { diff --git a/entrance/src/main/resources/application.yml b/entrance/src/main/resources/application.yml index 28ec2188..150d16db 100644 --- a/entrance/src/main/resources/application.yml +++ b/entrance/src/main/resources/application.yml @@ -6,7 +6,7 @@ spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://192.168.1.24:13306/pqs91001?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT + url: jdbc:mysql://192.168.1.24:13306/pqs91003?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT username: root password: njcnpqs # url: jdbc:mysql://localhost:3306/pqs91001?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT
paragraphsToRemove = new ArrayList<>(); + + for (Object paragraph : paragraphs) { + if (paragraph instanceof P){ + P paragraphtemp = (P) paragraph; + // 检查段落是否为空 + boolean isEmpty = isParagraphEmpty(paragraphtemp); + + if (isEmpty) { + if (!inBlankPage) { + inBlankPage = true; + } + paragraphsToRemove.add(paragraphtemp); + } else { + inBlankPage = false; + } + } + } + + // 删除空白段落 + for (P paragraph : paragraphsToRemove) { + body.getContent().remove(paragraph); + } + } + + /** + * 检查段落是否为空 + * @param paragraph 要检查的段落 + * @return 如果段落为空返回true,否则返回false + */ + private static boolean isParagraphEmpty(P paragraph) { + // 检查段落是否包含分节符 + if (paragraph.getPPr() != null && paragraph.getPPr().getSectPr() != null) { + return false; + } + + // 检查段落中的文本内容 + for (Object obj : paragraph.getContent()) { + if (obj instanceof R) { + R run = (R) obj; + // 在3.3.4版本中,使用getContent()获取文本内容 + for (Object runContent : run.getContent()) { + if (runContent instanceof Text) { + Text text = (Text) runContent; + if (text.getValue() != null && !text.getValue().trim().isEmpty()) { + return false; + } + } + } + } + } + return true; + } + + + /** + * 在插入前检查目标位置是否有分页符 + * + * @param position 目标位置 + * @return 是否包含分页符 + */ + private static boolean hasPageBreak(Object position) { + if (position instanceof P) { + P paragraph = (P) position; + for (Object run : paragraph.getContent()) { + if (run instanceof R) { + R r = (R) run; + for (Object element : r.getContent()) { + if (element instanceof Br && ((Br) element).getType() != null + && ((Br) element).getType().equals("page")) { + return true; + } + } + } + } + return false; + } + return false; + } + + /** + * 删除书签 + * + * @param bookmarkInfo 书签信息 + */ + public static void removeBookmark(BookmarkUtil.BookmarkInfo bookmarkInfo) { + try { + // 获取书签所在的段落 + P paragraph = bookmarkInfo.parentParagraph; + + // 遍历段落内容,找到并删除书签开始和结束标记 + List paragraphContent = new ArrayList<>(paragraph.getContent()); + for (Object obj : paragraphContent) { + if (obj instanceof JAXBElement) { + JAXBElement> element = (JAXBElement>) obj; + Object value = element.getValue(); + + // 删除书签开始标记 + if (value instanceof CTBookmark) { + paragraph.getContent().remove(obj); + } + // 删除书签结束标记 + else if (value instanceof CTMarkupRange) { + paragraph.getContent().remove(obj); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 使用 ObjectFactory 创建表格 + * + * @param factory ObjectFactory 实例 + * @param data 二维数组,表格内容 + * @return Tbl 表格对象 + */ + public static Tbl createTable(ObjectFactory factory, String[][] data) { + Tbl table = factory.createTbl(); + for (String[] rowData : data) { + Tr row = factory.createTr(); + for (String cellData : rowData) { + Tc cell = factory.createTc(); + P para = factory.createP(); + R run = factory.createR(); + Text text = factory.createText(); + text.setValue(cellData); + run.getContent().add(text); + para.getContent().add(run); + cell.getContent().add(para); + row.getContent().add(cell); + } + table.getContent().add(row); + } + return table; + } + + /** + * 获取指定标签的标签信息 + * + * @param key 标签名 + * @param bookmarks 所有标签信息 + */ + public static BookmarkInfo getBookmarkInfo(String key, List bookmarks) { + BookmarkUtil.BookmarkInfo bookmarkInfo = null; + for (BookmarkUtil.BookmarkInfo info : bookmarks) { + String name = info.bookmark.getName(); + if (key.equalsIgnoreCase(name)) { + bookmarkInfo = info; + } + } + return bookmarkInfo; + } +} \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java index a20a40fc..e1f49020 100644 --- a/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java +++ b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java @@ -5,19 +5,12 @@ import cn.hutool.core.text.StrPool; import cn.hutool.core.util.StrUtil; import com.njcn.gather.report.pojo.constant.ReportConstant; import com.njcn.gather.report.pojo.enums.DocAnchorEnum; -import com.njcn.gather.report.pojo.vo.Bookmark; import org.docx4j.XmlUtils; -import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.*; import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import java.io.StringReader; -import java.io.StringWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; @@ -244,13 +237,14 @@ public class Docx4jUtil { /** * 段落中添加内容 */ - public static void addPContent(ObjectFactory factory, P paragraph, String content, RPr rPr) { + public static void addPContent(ObjectFactory factory, P paragraph, String content, RPr rPr,PPr ppr) { R run = factory.createR(); Text text = factory.createText(); text.setValue(content); run.setRPr(rPr); run.getContent().add(text); paragraph.getContent().add(run); + paragraph.setPPr(ppr); } /** @@ -347,6 +341,20 @@ public class Docx4jUtil { text.setValue(value); run.getContent().add(text); paragraph.getContent().add(run); + // 字体 + // 设置字体 + RPr rPr = factory.createRPr(); + RFonts rFonts = factory.createRFonts(); + if (containsChinese(value)) { + rFonts.setEastAsia("宋体"); + rFonts.setAscii("宋体"); + rFonts.setHAnsi("宋体"); + } else { + rFonts.setEastAsia("Arial"); + rFonts.setAscii("Arial"); + rFonts.setHAnsi("Arial"); + } + rPr.setRFonts(rFonts); // 设置段落居中 if (centerFlag) { PPr pPr = factory.createPPr(); @@ -356,13 +364,17 @@ public class Docx4jUtil { paragraph.setPPr(pPr); } if (value.equals("不合格")) { - RPr rPr = factory.createRPr(); Color color = factory.createColor(); // 红色 color.setVal("FF0000"); rPr.setColor(color); run.setRPr(rPr); } + HpsMeasure sz = factory.createHpsMeasure(); + // 10号字体 = 20 half-points + sz.setVal(new BigInteger("20")); + rPr.setSz(sz); + cell.getContent().add(paragraph); cell.setTcPr(tcPr); row.getContent().add(cell); @@ -372,20 +384,39 @@ public class Docx4jUtil { } + /** + * 判断字符串是否包含中文 + * @param str 需要判断的字符串 + * @return 是否包含中文 + */ + private static boolean containsChinese(String str) { + if (str == null) { + return false; + } + for (char c : str.toCharArray()) { + if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) { + return true; + } + } + return false; + } + + /** * 根据已知信息创建新行 * - * @param factory 工厂 - * @param cellValues 数据 + * @param factory 工厂 + * @param cellValues 数据 * @param ascFontStyle 西文字体 - * @param eastFontStyle 中文字体 - * @param size 字体大小 - * @param boldFlag 是否加粗 - * @param centerFlag 是否居中 + * @param eastFontStyle 中文字体 + * @param size 字体大小 + * @param boldFlag 是否加粗 + * @param centerFlag 是否居中 */ - public static Tr createCustomRow(ObjectFactory factory, List cellValues, String ascFontStyle,String eastFontStyle, Integer size, boolean boldFlag, boolean centerFlag) { + public static Tr createCustomRow(ObjectFactory factory, List cellValues, String ascFontStyle, String eastFontStyle, Integer size, boolean boldFlag, List centerFlag) { Tr row = factory.createTr(); - for (String value : cellValues) { + for (int i = 0; i < cellValues.size(); i++) { + String value = cellValues.get(i); Tc cell = factory.createTc(); P paragraph = factory.createP(); R run = factory.createR(); @@ -394,7 +425,7 @@ public class Docx4jUtil { run.getContent().add(text); paragraph.getContent().add(run); // 设置段落居中 - if (centerFlag) { + if (!centerFlag.contains(i)) { PPr pPr = factory.createPPr(); Jc jc = factory.createJc(); jc.setVal(JcEnumeration.CENTER); @@ -408,7 +439,7 @@ public class Docx4jUtil { color.setVal("FF0000"); rPr.setColor(color); } - if(boldFlag){ + if (boldFlag) { BooleanDefaultTrue bold = factory.createBooleanDefaultTrue(); rPr.setB(bold); } @@ -425,9 +456,20 @@ public class Docx4jUtil { rPr.setSz(fontSize); // 中文字号 rPr.setSzCs(fontSize); - run.setRPr(rPr); cell.getContent().add(paragraph); + // 设置单元格边距 + TcPr cellProperties = factory.createTcPr(); + cell.setTcPr(cellProperties); + // 设置单元格上下边距(单位:缇) + TcMar mar = factory.createTcMar(); + TblWidth top = factory.createTblWidth(); + top.setW(BigInteger.valueOf(100)); + mar.setTop(top); + TblWidth bottom = factory.createTblWidth(); + bottom.setW(BigInteger.valueOf(100)); + mar.setBottom(bottom); + cellProperties.setTcMar(mar); row.getContent().add(cell); } return row; @@ -448,7 +490,6 @@ public class Docx4jUtil { } - // 存储Heading 5及其子内容的辅助类 public static class HeadingContent { private String headingText; @@ -471,6 +512,38 @@ public class Docx4jUtil { } } + + /** + * 获取指定书签在文档段落中的位置索引 + * + * @param documentPart 主文档部分 + * @param bookmarkName 书签名称 + * @return 段落索引,找不到返回 -1 + */ + public static int getParagraphPosition(MainDocumentPart documentPart, String bookmarkName) { + List content = documentPart.getContent(); + for (int i = 0; i < content.size(); i++) { + Object obj = content.get(i); + // 只处理段落 + if (obj instanceof P) { + P paragraph = (P) obj; + // 提取段落纯文本 + String text = getTextFromP(paragraph).trim(); + if (text.startsWith("#{") && text.endsWith("}")) { + // 提取书签名 + String name = text.substring(2, text.length() - 1); + if (name.equals(bookmarkName)) { + // 返回段落索引 + return i; + } + } + } + } + // 找不到返回 -1 + return -1; + } + + /** * 获取段落在文档中的位置 */ @@ -534,4 +607,27 @@ public class Docx4jUtil { } + /** + * 获取分页符 + */ + public static P getPageBreak() { + try { + ObjectFactory factory = new ObjectFactory(); + // 创建分页符 + R run = factory.createR(); + Br br = factory.createBr(); + br.setType(STBrType.PAGE); + // 直接添加 br 对象 + run.getContent().add(br); + // 创建包含分页符的段落 + P pageBreakParagraph = factory.createP(); + pageBreakParagraph.getContent().add(run); + return pageBreakParagraph; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + } diff --git a/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java b/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java index 07381351..c504df7e 100644 --- a/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/result/service/impl/ResultServiceImpl.java @@ -1015,10 +1015,8 @@ public class ResultServiceImpl implements IResultService { double timeDouble = Math.round(harmNum); int timeInt = (int) timeDouble; // 填充结果数据 - fillThreePhaseData(singleResult, timeInt, keyFillMap); - if (!keyFillMap.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()).equals("/")) { - keyFillMapList.add(keyFillMap); - } + fillThreePhaseData(singleResult, timeInt, keyFillMap, scriptCode); + keyFillMapList.add(keyFillMap); }); if (CollUtil.isNotEmpty(keyFillMapList)) { // 按次数排序 @@ -1045,10 +1043,8 @@ public class ResultServiceImpl implements IResultService { List> keyFillMapList = new ArrayList<>(); for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { Map keyFillMap = new HashMap<>(16); - fillThreePhaseData(adNonHarmonicResult, null, keyFillMap); - if (!keyFillMap.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()).equals("/")) { - keyFillMapList.add(keyFillMap); - } + fillThreePhaseData(adNonHarmonicResult, null, keyFillMap, scriptCode); + keyFillMapList.add(keyFillMap); } if (CollUtil.isNotEmpty(keyFillMapList)) { // 需要对所有的填充进行按误差范围分组 @@ -1075,9 +1071,7 @@ public class ResultServiceImpl implements IResultService { for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { Map keyFillMap = new HashMap<>(8); fillTPhaseData(adNonHarmonicResult, null, keyFillMap); - if (!keyFillMap.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()).equals("/")) { - keyFillMapList.add(keyFillMap); - } + keyFillMapList.add(keyFillMap); } } if (CollUtil.isNotEmpty(keyFillMapList)) { @@ -1120,7 +1114,7 @@ public class ResultServiceImpl implements IResultService { * @param timeInt 谐波类需要传指定次数 * @param keyFillMap 待填充的集合Map */ - private void fillThreePhaseData(Object singleResult, Integer timeInt, Map keyFillMap) { + private void fillThreePhaseData(Object singleResult, Integer timeInt, Map keyFillMap, String scriptCode) { DetectionData tempA = getResultData(singleResult, timeInt, PowerConstant.PHASE_A); DetectionData tempB = getResultData(singleResult, timeInt, PowerConstant.PHASE_B); DetectionData tempC = getResultData(singleResult, timeInt, PowerConstant.PHASE_C); @@ -1129,50 +1123,64 @@ public class ResultServiceImpl implements IResultService { testA = "/", testB = "/", testC = "/", errorA = "/", errorB = "/", errorC = "/", resultA = "/", resultB = "/", resultC = "/", result = "/", - errorScope = "/", unit = ""; + errorScope = "/", unit = "", scriptDetail = "/"; - if (Objects.nonNull(tempA) && (PowerConstant.DATA_RANGE.contains(tempA.getIsData()))) { - standardA = PubUtils.doubleRoundStr(4, tempA.getResultData()); - testA = PubUtils.doubleRoundStr(4, tempA.getData()); - errorA = PubUtils.doubleRoundStr(4, tempA.getErrorData().doubleValue()); - resultA = tempA.getIsData() == 1 ? "合格" : "不合格"; - errorScope = tempA.getRadius(); - unit = tempA.getUnit(); - standard = PubUtils.doubleRoundStr(4, tempA.getResultData()); + if (Objects.nonNull(tempA)) { + standardA = PubUtils.doubleRoundStr(4, tempA.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getResultData()); + testA = PubUtils.doubleRoundStr(4, tempA.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getData()); + if (Objects.nonNull(tempA.getErrorData())) { + errorA = PubUtils.doubleRoundStr(4, tempA.getErrorData().doubleValue()); + } + resultA = tempA.getIsData() == 1 ? "合格" : tempA.getIsData() == 0 ? "不合格" : "/"; + errorScope = tempA.getRadius() == null ? "/" : tempA.getRadius(); + unit = tempA.getUnit() == null ? "" : tempA.getUnit(); + standard = PubUtils.doubleRoundStr(4, tempA.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempA.getResultData()); } - if (Objects.nonNull(tempB) && (PowerConstant.DATA_RANGE.contains(tempB.getIsData()))) { - standardB = PubUtils.doubleRoundStr(4, tempB.getResultData()); - testB = PubUtils.doubleRoundStr(4, tempB.getData()); - errorB = PubUtils.doubleRoundStr(4, tempB.getErrorData().doubleValue()); - resultB = tempB.getIsData() == 1 ? "合格" : "不合格"; + if (Objects.nonNull(tempB)) { + standardB = PubUtils.doubleRoundStr(4, tempB.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getResultData()); + testB = PubUtils.doubleRoundStr(4, tempB.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getData()); + if (Objects.nonNull(tempB.getErrorData())) { + errorB = PubUtils.doubleRoundStr(4, tempB.getErrorData().doubleValue()); + } + resultB = tempB.getIsData() == 1 ? "合格" : tempB.getIsData() == 0 ? "不合格" : "/"; if (errorScope.equals("/")) { - errorScope = tempB.getRadius(); + errorScope = tempB.getRadius() == null ? "/" : tempB.getRadius(); } if (StrUtil.isBlank(unit)) { - unit = tempB.getUnit(); + unit = tempB.getUnit() == null ? "" : tempB.getUnit(); } if (standard.equals("/")) { - standard = PubUtils.doubleRoundStr(4, tempB.getResultData()); + standard = PubUtils.doubleRoundStr(4, tempB.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempB.getResultData()); } } - if (Objects.nonNull(tempC) && (PowerConstant.DATA_RANGE.contains(tempC.getIsData()))) { - standardC = PubUtils.doubleRoundStr(4, tempC.getResultData()); - testC = PubUtils.doubleRoundStr(4, tempC.getData()); - errorC = PubUtils.doubleRoundStr(4, tempC.getErrorData().doubleValue()); - resultC = tempC.getIsData() == 1 ? "合格" : "不合格"; + if (Objects.nonNull(tempC)) { + standardC = PubUtils.doubleRoundStr(4, tempC.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getResultData()); + testC = PubUtils.doubleRoundStr(4, tempC.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getData()); + if (Objects.nonNull(tempC.getErrorData())) { + errorC = PubUtils.doubleRoundStr(4, tempC.getErrorData().doubleValue()); + } + resultC = tempC.getIsData() == 1 ? "合格" : tempC.getIsData() == 0 ? "不合格" : "/"; if (errorScope.equals("/")) { - errorScope = tempC.getRadius(); + errorScope = tempC.getRadius() == null ? "/" : tempC.getRadius(); } if (StrUtil.isBlank(unit)) { - unit = tempC.getUnit(); + unit = tempC.getUnit() == null ? "" : tempC.getUnit(); } if (standard.equals("/")) { - standard = PubUtils.doubleRoundStr(4, tempC.getResultData()); + standard = PubUtils.doubleRoundStr(4, tempC.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempC.getResultData()); } } + if (scriptCode.equalsIgnoreCase("I")) { + resultA = "/"; + resultB = "/"; + resultC = "/"; + } if (standardA.equals(standardB) && standardA.equals(standardC)) { standard = standardA; } + // 处理脚本输出 + scriptDetail = dealScriptDetail(scriptCode, standard); + keyFillMap.put(ItemReportKeyEnum.SCRIPT_DETAIL.getKey(), scriptDetail); // 标准值 keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); keyFillMap.put(ItemReportKeyEnum.STANDARD_A.getKey(), standardA); @@ -1200,6 +1208,45 @@ public class ResultServiceImpl implements IResultService { keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope); } + /** + * 针对浙江杭州处理脚本输出细节,todo... 需要更改更合理的方式,现在算是写死的了部分 + * 目前浙江这边就是(间)谐波电压/电流 + */ + private String dealScriptDetail(String scriptCode, String standard) { + String scriptDetail = ""; + PowerIndexEnum powerIndexEnum = PowerIndexEnum.getByKey(scriptCode); + if (powerIndexEnum != null) { + switch (powerIndexEnum) { + case HV: + case HSV: + // 注:基波电压幅值57.74V,基波频率50.0Hz。 + scriptDetail = "注:基波电压幅值57.74V,基波频率50.0Hz。"; + break; + case HI: + // 电流是幅值,需要与5A得出百分比 + try { + String temp = PubUtils.doubleRoundStr(1, (Double.parseDouble(standard) / 5.0) * 100); + scriptDetail = "注:基波电流幅值5.000A,基波频率50.0Hz,各次谐波电流含有率均为" + temp + "%。"; + } catch (Exception e) { + log.error("dealScriptDetail error:{}", e); + } + break; + case HSI: + // 电流是幅值,需要与5A得出百分比 + try { + String temp = PubUtils.doubleRoundStr(1, (Double.parseDouble(standard) / 5.0) * 100); + scriptDetail = "注:基波电流幅值5.000A,基波频率50.0Hz,各次间谐波电流含有率均为" + temp + "%。"; + } catch (Exception e) { + log.error("dealScriptDetail error:{}", e); + } + break; + default: + break; + } + } + return scriptDetail; + } + /** * T相的相关数据处理,非暂态数据 @@ -1212,13 +1259,15 @@ public class ResultServiceImpl implements IResultService { private void fillTPhaseData(Object singleResult, Integer timeInt, Map keyFillMap) { String standard = "/", test = "/", error = "/", result = "/", errorScope = "/", unit = ""; DetectionData tempT = getResultData(singleResult, timeInt, PowerConstant.PHASE_T); - if (Objects.nonNull(tempT) && PowerConstant.DATA_RANGE.contains(tempT.getIsData())) { - standard = PubUtils.doubleRoundStr(4, tempT.getResultData()); - test = PubUtils.doubleRoundStr(4, tempT.getData()); - error = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); - result = tempT.getIsData() == 1 ? "合格" : "不合格"; - unit = tempT.getUnit(); - errorScope = tempT.getRadius(); + if (Objects.nonNull(tempT)) { + standard = PubUtils.doubleRoundStr(4, tempT.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getResultData()); + test = PubUtils.doubleRoundStr(4, tempT.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getData()); + if (Objects.nonNull(tempT.getErrorData())) { + error = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); + } + result = tempT.getIsData() == 1 ? "合格" : tempT.getIsData() == 0 ? "不合格" : "/"; + unit = tempT.getUnit() == null ? "" : tempT.getUnit(); + errorScope = tempT.getRadius() == null ? "/" : tempT.getRadius(); } keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); keyFillMap.put(ItemReportKeyEnum.TEST.getKey(), test); @@ -1249,11 +1298,13 @@ public class ResultServiceImpl implements IResultService { DictTree temp = dictTreeService.getById(adType); if (temp.getCode().equalsIgnoreCase("MAG")) { // 特征幅值 - if (Objects.nonNull(tempT) && PowerConstant.DATA_RANGE.contains(tempT.getIsData())) { - standardMag = PubUtils.doubleRoundStr(4, tempT.getResultData()); - testMag = PubUtils.doubleRoundStr(4, tempT.getData()); - errorMag = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); - resultMag = tempT.getIsData() == 1 ? "合格" : "不合格"; + if (Objects.nonNull(tempT)) { + standardMag = PubUtils.doubleRoundStr(4, tempT.getResultData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getResultData()); + testMag = PubUtils.doubleRoundStr(4, tempT.getData()) == null ? "/" : PubUtils.doubleRoundStr(4, tempT.getData()); + if (Objects.nonNull(tempT.getErrorData())) { + errorMag = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); + } + resultMag = tempT.getIsData() == 1 ? "合格" : tempT.getIsData() == 0 ? "不合格" : "/"; unitMag = tempT.getUnit(); errorScopeMag = tempT.getRadius(); } @@ -1271,12 +1322,24 @@ public class ResultServiceImpl implements IResultService { } } } - standardDur = PubUtils.doubleRoundStr(4, tempT.getResultData()); - testDur = PubUtils.doubleRoundStr(4, tempT.getData()); - errorDur = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); - resultDur = tempT.getIsData() == 1 ? "合格" : "不合格"; - unitDur = tempT.getUnit(); - errorScopeDur = tempT.getRadius(); + if (Objects.nonNull(tempT.getResultData())) { + standardDur = PubUtils.doubleRoundStr(4, tempT.getResultData()); + } + if (Objects.nonNull(tempT.getData())) { + testDur = PubUtils.doubleRoundStr(4, tempT.getData()); + } + if (Objects.nonNull(tempT.getErrorData())) { + testDur = PubUtils.doubleRoundStr(4, tempT.getErrorData().doubleValue()); + } + if (Objects.nonNull(tempT.getIsData())) { + resultDur = tempT.getIsData() == 1 ? "合格" : "不合格"; + } + if (StrUtil.isNotBlank(tempT.getUnit())) { + unitDur = tempT.getUnit(); + } + if (StrUtil.isNotBlank(tempT.getRadius())) { + errorScopeDur = tempT.getRadius(); + } if (timeUnit.equalsIgnoreCase("ms")) { // 如果是ms,上述的一些数据需要重新处理 if (!standardDur.equalsIgnoreCase("/")) { diff --git a/entrance/src/main/resources/application.yml b/entrance/src/main/resources/application.yml index 28ec2188..150d16db 100644 --- a/entrance/src/main/resources/application.yml +++ b/entrance/src/main/resources/application.yml @@ -6,7 +6,7 @@ spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://192.168.1.24:13306/pqs91001?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT + url: jdbc:mysql://192.168.1.24:13306/pqs91003?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT username: root password: njcnpqs # url: jdbc:mysql://localhost:3306/pqs91001?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=CTT