diff --git a/detection/pom.xml b/detection/pom.xml index e6be0098..b615de17 100644 --- a/detection/pom.xml +++ b/detection/pom.xml @@ -74,6 +74,29 @@ poi-ooxml 4.1.2 + + + + org.docx4j + docx4j + 3.3.4 + + + com.fasterxml.jackson.core + jackson-databind + 2.12.0 + + + com.fasterxml.jackson.core + jackson-core + 2.12.0 + + + com.fasterxml.jackson.core + jackson-annotations + 2.12.0 + + diff --git a/detection/src/main/java/com/njcn/gather/detection/pojo/vo/DetectionData.java b/detection/src/main/java/com/njcn/gather/detection/pojo/vo/DetectionData.java index bbfcb2f6..e65b73be 100644 --- a/detection/src/main/java/com/njcn/gather/detection/pojo/vo/DetectionData.java +++ b/detection/src/main/java/com/njcn/gather/detection/pojo/vo/DetectionData.java @@ -20,7 +20,7 @@ public class DetectionData { private Double num; /** - * 是否是符合数据(1.合格 2.不合格 3.网络超时 4.无法处理 5.不参与误差比较) + * 1.合格 2.不合格 3.网络超时 4.无法处理 5.不参与误差比较 */ private Integer isData; diff --git a/detection/src/main/java/com/njcn/gather/device/service/impl/PqDevServiceImpl.java b/detection/src/main/java/com/njcn/gather/device/service/impl/PqDevServiceImpl.java index d42c7290..822133bd 100644 --- a/detection/src/main/java/com/njcn/gather/device/service/impl/PqDevServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/device/service/impl/PqDevServiceImpl.java @@ -43,6 +43,7 @@ import com.njcn.gather.system.dictionary.service.IDictDataService; import com.njcn.gather.system.dictionary.service.IDictTypeService; import com.njcn.gather.type.pojo.po.DevType; import com.njcn.gather.type.service.IDevTypeService; +import com.njcn.gather.user.user.service.ISysUserService; import com.njcn.web.factory.PageFactory; import com.njcn.web.utils.ExcelUtil; import com.njcn.web.utils.PoiUtil; @@ -75,6 +76,7 @@ public class PqDevServiceImpl extends ServiceImpl implements private final IDevTypeService devTypeService; private final ISysTestConfigService sysTestConfigService; private final IDictTypeService dictTypeService; + private final ISysUserService userService; @Override public Page listPqDevs(PqDevParam.QueryParam queryParam) { @@ -390,6 +392,7 @@ public class PqDevServiceImpl extends ServiceImpl implements return CheckStateEnum.UNCHECKED.getValue(); } +// // @Override // public List getPieData(String planId) { // List pqDevList = this.lambdaQuery().eq(PqDev::getPlanId, planId).eq(PqDev::getState, DataStateEnum.ENABLE.getCode()).list(); @@ -411,6 +414,9 @@ public class PqDevServiceImpl extends ServiceImpl implements @Override public PqDevVO getPqDevById(String id) { PqDev pqDev = this.getById(id); + if(StrUtil.isNotBlank(pqDev.getCheckBy())){ + pqDev.setCheckBy(userService.getById(pqDev.getCheckBy()).getName()); + } PqDevVO pqDevVO = new PqDevVO(); BeanUtil.copyProperties(pqDev, pqDevVO); diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/constant/PowerConstant.java b/detection/src/main/java/com/njcn/gather/report/pojo/constant/PowerConstant.java new file mode 100644 index 00000000..9e85a35e --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/constant/PowerConstant.java @@ -0,0 +1,77 @@ +package com.njcn.gather.report.pojo.constant; + + +import java.util.Arrays; +import java.util.List; + +/** + * 电能质量指标常用的一些常量池 + * + * @author hongawen + * @version 1.0 + * @data 2025/3/27 11:11 + */ +public interface PowerConstant { + + /** + * 有三相的指标 + */ + List THREE_PHASE = Arrays.asList("V", "HV", "HI", "HP", "HSV", "HSI", "I", "P", "F"); + + /** + * T相指标 + */ + List T_PHASE = Arrays.asList("VOLTAGE", "IMBV", "IMBA"); + + + /** + * 有次数的指标 + */ + List TIME = Arrays.asList("HV", "HI", "HP", "HSV", "HSI"); + + /** + * 没有次数的指标 + */ + List NO_TIME = Arrays.asList("V", "I", "P", "VOLTAGE", "IMBV", "IMBA", "F"); + + /** + * 有数据范围 + */ + List DATA_RANGE = Arrays.asList(1, 2); + + /** + * 暂态符号 + */ + String VOLTAGE = "VOLTAGE"; + + /** + * A相 + */ + String PHASE_A = "A"; + + /** + * B相 + */ + String PHASE_B = "B"; + + /** + * C相 + */ + String PHASE_C = "C"; + + /** + * T相 + */ + String PHASE_T = "T"; + + /** + * 电流单位 + */ + String CURRENT_UNIT = "A"; + + /** + * 电压单位 + */ + String VOLTAGE_UNIT = "V"; + +} diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/constant/ReportConstant.java b/detection/src/main/java/com/njcn/gather/report/pojo/constant/ReportConstant.java new file mode 100644 index 00000000..3b4cfc8b --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/constant/ReportConstant.java @@ -0,0 +1,22 @@ +package com.njcn.gather.report.pojo.constant; + +/** + * + * 报告相关的一些常量 + * + * @author hongawen + * @version 1.0 + * @data 2025/4/3 13:44 + */ +public interface ReportConstant { + + /** + * docx文档后缀 + */ + String DOCX = ".docx"; + + /** + * 报告模板中书签的起始标识 + */ + String BOOKMARK_START = "#{"; +} diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/AffectEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/AffectEnum.java new file mode 100644 index 00000000..0eaf122d --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/AffectEnum.java @@ -0,0 +1,43 @@ +package com.njcn.gather.report.pojo.enums; + +import lombok.Getter; + +/** + * 影响量枚举 + * @author hongawen + * @version 1.0 + * @data 2025/3/27 21:07 + */ +@Getter +public enum AffectEnum { + + + BASE("base", "额定工作条件下的检测"), + VOL("vol", "电压对XX测量的影响"), + FREQ("freq", "频率对XX测量的影响"), + HARM("single", "谐波对XX测量的影响"); + + private String key; + + private String desc; + + AffectEnum(String key, String desc) { + this.key = key; + this.desc = desc; + } + + /** + * 根据key找到适配的枚举 + * + * @param key 枚举的key + * @return 匹配的枚举实例,如果没有找到则返回null + */ + public static AffectEnum getByKey(String key) { + for (AffectEnum affectEnum : AffectEnum.values()) { + if (affectEnum.getKey().equalsIgnoreCase(key)) { + return affectEnum; + } + } + return null; + } +} 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 new file mode 100644 index 00000000..25a0b829 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/BaseReportKeyEnum.java @@ -0,0 +1,42 @@ +package com.njcn.gather.report.pojo.enums; + +import lombok.Getter; + +/** + * + * 本枚举用于记录模板中关键字的含义 + * 比如 ${manufacturer} 对应的设备厂家 + * + * @author hongawen + * @version 1.0 + * @data 2025/3/24 14:34 + * + * */ +@Getter +public enum BaseReportKeyEnum { + + DEV_TYPE("devType","设备型号、规格"), + DEV_CODE("createId","装置编号"), + POWER("power","工作电源"), + DEV_CURR("devCurr","额定电流"), + DEV_VOLT("devVolt","额定电压"), + COUNT("count","通道数"), + MANUFACTURER("manufacturer","设备厂家、制造厂商"), + SAMPLE_ID("sampleId","样品编号"), + ARRIVED_DATE("arrivedDate","收样日期"), + TEST_DATE("testDate","检测日期"), + INSPECTOR("inspector","检测员"), + YEAR("year","年份"), + MONTH("month","月份"), + DAY("day","日"), + YEAR_MONTH_DAY("year-month-day","年-月-日"); + + private String key; + + private String desc; + + BaseReportKeyEnum(String key, String desc) { + this.key = key; + this.desc = desc; + } +} diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/DocAnchorEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/DocAnchorEnum.java new file mode 100644 index 00000000..9e3143dd --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/DocAnchorEnum.java @@ -0,0 +1,50 @@ +package com.njcn.gather.report.pojo.enums; + +import lombok.Getter; + +/** + * 统计文档锚点类型 + * + * @author hongawen + * @version 1.0 + * @data 2025/3/24 18:42 + */ +@Getter +public enum DocAnchorEnum { + + + 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; + + DocAnchorEnum(String key, String desc, Integer sort) { + this.key = key; + this.desc = desc; + this.sort = sort; + } + + /** + * 根据key找到适配的枚举 + * + * @param key 枚举的key + * @return 匹配的枚举实例,如果没有找到则返回null + */ + public static DocAnchorEnum getByKey(String key) { + for (DocAnchorEnum docAnchorEnum : DocAnchorEnum.values()) { + if (docAnchorEnum.getKey().equalsIgnoreCase(key)) { + return docAnchorEnum; + } + } + return null; + } + +} diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/ItemReportKeyEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/ItemReportKeyEnum.java new file mode 100644 index 00000000..b7e1f068 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/ItemReportKeyEnum.java @@ -0,0 +1,70 @@ +package com.njcn.gather.report.pojo.enums; + +import lombok.Getter; + +/** + * 检测项模版枚举 + * @author hongawen + * @version 1.0 + * @data 2025/3/27 10:24 + */ +@Getter +public enum ItemReportKeyEnum { + + NAME("name", "检测项,比如:频率"), + NAME_DETAIL("nameDetail", "检测项详细,比如:频率测量准确度"), + ERROR_SCOPE("errorScope", "误差范围,注:在段落中时需加上(),表格中无需添加"), + ERROR_SCOPE_MAG("errorScopeMag", "特征幅值:误差范围"), + ERROR_SCOPE_DUR("errorScopeDur", "持续时间:误差范围"), + SCRIPT_DETAIL("scriptDetail", "脚本输出明细。比如:基波电压UN=57.74V,f=50Hz,谐波含有率Uh=10%UN=5.774V"), + TIME("time", "次数"), + STANDARD("standard", "标准值"), + STANDARD_A("standardA", "A相标准值"), + STANDARD_B("standardB", "B相标准值"), + STANDARD_C("standardC", "C相标准值"), + STANDARD_MAG("standardMag", "特征幅值的标准值"), + STANDARD_DUR("standardDur_ms", "持续时间的标准值"), + TEST("test", "测试值"), + TEST_MAG("testMag", "特征幅值测试值"), + TEST_DUR("testDur_ms", "持续时间测试值"), + TEST_A("testA", "A相测试值"), + TEST_B("testB", "B相测试值"), + TEST_C("testC", "C相测试值"), + ERROR("error", "误差"), + ERROR_MAG("errorMag", "特征幅值误差"), + ERROR_DUR("errorDur_ms", "持续时间误差"), + ERROR_A("errorA", "A相误差"), + ERROR_B("errorB", "B相误差"), + ERROR_C("errorC", "C相误差"), + RESULT("result", "结论 比如:合格/不合格"), + RESULT_A("resultA", "结论 比如:合格/不合格"), + RESULT_B("resultB", "结论 比如:合格/不合格"), + RESULT_C("resultC", "结论 比如:合格/不合格"), + RESULT_MAG("resultMag", "特征幅值结论 比如:合格/不合格"), + RESULT_DUR("resultDur", "持续时间结论 比如:合格/不合格"); + + private String key; + + private String desc; + + ItemReportKeyEnum(String key, String desc) { + this.key = key; + this.desc = desc; + } + + /** + * 根据key找到适配的枚举 + * + * @param key 枚举的key + * @return 匹配的枚举实例,如果没有找到则返回null + */ + public static ItemReportKeyEnum getByKey(String key) { + for (ItemReportKeyEnum itemReportKetEnum : ItemReportKeyEnum.values()) { + if (itemReportKetEnum.getKey().equalsIgnoreCase(key)) { + return itemReportKetEnum; + } + } + return null; + } + +} 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 new file mode 100644 index 00000000..5fbc0ee8 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/PowerIndexEnum.java @@ -0,0 +1,52 @@ +package com.njcn.gather.report.pojo.enums; + +import lombok.Getter; + +/** + * 电能质量测试大项枚举 + * @author hongawen + * @version 1.0 + * @data 2025/3/27 18:29 + */ +@Getter +public enum PowerIndexEnum { + + + UNKNOWN("UNKNOWN", "未知指标"), + FREQ("FREQ", "频率"), + V("V", "电压"), + I("I", "电流"), + IMBV("IMBV", "三相电压不平衡度"), + IMBA("IMBA", "三相电流不平衡度"), + F("F", "闪变"), + HP("HP", "谐波有功功率"), + HV("HV", "谐波电压"), + HI("HI", "谐波电流"), + HSV("HSV", "间谐波电压"), + HSI("HSI", "间谐波电流"), + VOLTAGE("VOLTAGE", "电压暂降、暂升及短时中断"); + + private String key; + + private String desc; + + PowerIndexEnum(String key, String desc) { + this.key = key; + this.desc = desc; + } + + /** + * 根据key找到适配的枚举 + * + * @param key 枚举的key + * @return 匹配的枚举实例,如果没有找到则返回null + */ + public static PowerIndexEnum getByKey(String key) { + for (PowerIndexEnum powerIndexEnum : PowerIndexEnum.values()) { + if (powerIndexEnum.getKey().equalsIgnoreCase(key)) { + return powerIndexEnum; + } + } + return null; + } +} diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/enums/ReportResponseEnum.java b/detection/src/main/java/com/njcn/gather/report/pojo/enums/ReportResponseEnum.java index ffbbf832..2892943e 100644 --- a/detection/src/main/java/com/njcn/gather/report/pojo/enums/ReportResponseEnum.java +++ b/detection/src/main/java/com/njcn/gather/report/pojo/enums/ReportResponseEnum.java @@ -22,7 +22,9 @@ public enum ReportResponseEnum { FILE_RENAME_FAILED("A012011", "文件重命名失败"), REPORT_NAME_PATTERN_ERROR("A012012","报告名称格式错误,可包含中文、字母、数字、中划线、点号、空格,长度不能超过32个字符"), REPORT_VERSION_PATTERN_ERROR("A012013","报告版本号格式错误,可包含中文、字母、数字、中划线、点号、空格,长度不能超过32个字符"), - FILE_SIZE_ERROR("A012014","文件大小不能超过5MB" ); + FILE_SIZE_ERROR("A012014","文件大小不能超过5MB" ), + GENERATE_REPORT_ERROR("A012015","生成报告失败"), + ; private String code; private String message; diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/result/SingleTestResult.java b/detection/src/main/java/com/njcn/gather/report/pojo/result/SingleTestResult.java new file mode 100644 index 00000000..ef9bf48b --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/result/SingleTestResult.java @@ -0,0 +1,40 @@ +package com.njcn.gather.report.pojo.result; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * + * 测试大项的检测结果 + * + * @author hongawen + * @version 1.0 + * @data 2025/4/7 20:17 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SingleTestResult implements Serializable { + + /** + * 大项名称 + */ + private String scriptCode; + + /** + * 是否合格 + */ + private boolean qualified; + + + /** + * 细节集合 + */ + private Map>>>> detail; + +} diff --git a/detection/src/main/java/com/njcn/gather/report/pojo/vo/Bookmark.java b/detection/src/main/java/com/njcn/gather/report/pojo/vo/Bookmark.java new file mode 100644 index 00000000..1a4fc8c6 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/pojo/vo/Bookmark.java @@ -0,0 +1,39 @@ +package com.njcn.gather.report.pojo.vo; + +import com.njcn.gather.report.pojo.enums.DocAnchorEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author hongawen + * @version 1.0 + * @data 2025/4/7 15:36 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Bookmark implements Serializable,Comparable{ + + /** + * 在文档中段落的索引 + */ + private Integer index; + + /** + * 对应枚举 + */ + private DocAnchorEnum docAnchorEnum; + + + /** + * 根据书签的排序字段进行排序 + * @param bookmark the object to be compared. + */ + @Override + public int compareTo(Bookmark bookmark) { + return Integer.compare(this.docAnchorEnum.getSort(), bookmark.docAnchorEnum.getSort()); + } +} 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 04db917a..5f79ab45 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 @@ -1,5 +1,6 @@ package com.njcn.gather.report.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateUtil; @@ -28,18 +29,24 @@ import com.njcn.gather.plan.service.IAdPlanService; import com.njcn.gather.pojo.enums.DetectionResponseEnum; import com.njcn.gather.report.mapper.PqReportMapper; import com.njcn.gather.report.pojo.DevReportParam; -import com.njcn.gather.report.pojo.enums.ReportResponseEnum; +import com.njcn.gather.report.pojo.constant.PowerConstant; +import com.njcn.gather.report.pojo.constant.ReportConstant; +import com.njcn.gather.report.pojo.enums.*; import com.njcn.gather.report.pojo.param.ReportParam; import com.njcn.gather.report.pojo.po.CellEntity; import com.njcn.gather.report.pojo.po.PqReport; +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.Docx4jUtil; import com.njcn.gather.report.utils.WordUtil; import com.njcn.gather.result.pojo.param.ResultParam; import com.njcn.gather.result.pojo.vo.ResultVO; import com.njcn.gather.result.service.IResultService; import com.njcn.gather.script.pojo.po.PqScriptCheckData; import com.njcn.gather.script.pojo.po.PqScriptDtls; +import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO; import com.njcn.gather.script.service.IPqScriptCheckDataService; import com.njcn.gather.script.service.IPqScriptDtlsService; import com.njcn.gather.storage.pojo.param.SingleNonHarmParam; @@ -56,22 +63,25 @@ import com.njcn.gather.system.dictionary.service.IDictTreeService; import com.njcn.gather.system.pojo.enums.DicDataEnum; import com.njcn.gather.type.pojo.po.DevType; import com.njcn.gather.type.service.IDevTypeService; -import com.njcn.gather.user.user.pojo.po.SysUser; import com.njcn.gather.user.user.service.ISysUserService; import com.njcn.web.factory.PageFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.poi.xwpf.usermodel.*; +import org.docx4j.jaxb.Context; +import org.docx4j.openpackaging.packages.WordprocessingMLPackage; +import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; +import org.docx4j.wml.*; import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.FileSystemResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBElement; import java.io.*; import java.lang.reflect.Field; import java.math.BigDecimal; @@ -229,10 +239,9 @@ public class PqReportServiceImpl extends ServiceImpl i // 删除对应的文件 this.deleteFile(ids); - boolean result = this.lambdaUpdate().in(CollectionUtil.isNotEmpty(ids), PqReport::getId, ids) + return this.lambdaUpdate().in(CollectionUtil.isNotEmpty(ids), PqReport::getId, ids) .set(PqReport::getState, DataStateEnum.DELETED.getCode()) .update(); - return result; } @Override @@ -497,62 +506,76 @@ public class PqReportServiceImpl extends ServiceImpl i @Override public void generateReport(DevReportParam devReportParam) { AdPlan plan = adPlanService.getById(devReportParam.getPlanId()); - if (StrUtil.isNotBlank(plan.getReportTemplateId())) { + if (plan.getAssociateReport() == 1) { this.generateReportByPlan(plan, devReportParam); - } else { - // 根据设备类型找到报告模板 - PqDevVO pqDevVO = iPqDevService.getPqDevById(devReportParam.getDevId()); - if (Objects.isNull(pqDevVO)) { - throw new BusinessException("请检查装置是否存在!"); - } - // 获取设备型号 - DevType devType = devTypeService.getById(pqDevVO.getDevType()); - if (Objects.isNull(devType)) { - throw new BusinessException("设备类型缺失,请联系管理员!"); - } - DictData reportName = devTypeService.getReportName(pqDevVO.getDevType()); - if (Objects.isNull(reportName)) { - throw new BusinessException("报告模板缺失,请联系管理员!"); - } - // 读取模板文件 - ClassPathResource resource = new ClassPathResource("/model/" + reportName.getCode() + ".docx"); - try (InputStream inputStream = resource.getInputStream()) { - // 加载Word文档 - XWPFDocument baseModelDocument = new XWPFDocument(inputStream); - // 处理基础模版中的信息 - dealBaseModel(baseModelDocument, pqDevVO, devType); - // 处理数据页中的信息 - dealDataModel(baseModelDocument, devReportParam, pqDevVO); - // 处理需要输出的目录地址 基础路径+设备类型+装置编号.docx - // 最终文件输出的路径 - String dirPath = reportPath.concat(File.separator).concat(devType.getName()); - ensureDirectoryExists(dirPath); // 确保目录存在 - FileOutputStream out = new FileOutputStream(dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(".docx")); - // 4. 保存新的Word文档 - try { - baseModelDocument.write(out); - } catch (IOException e) { - throw new BusinessException("生成报告文件失败"); - } - out.close(); + } else if (plan.getAssociateReport() == 0) { + this.generateReportByDevType(plan, devReportParam); + } + } - System.out.println("报告生成成功!"); - this.updateDevAndPlanState(devReportParam.getDevId(), devReportParam.getPlanId()); + /** + * 根据设备类型生成报告 + * 注:该方法目前仅支持楼下出厂检测场景,属于模板占位符替换方式,后期可能会有调整 + * + * @param plan 计划信息 + * @param devReportParam 被检设备信息 + */ + private void generateReportByDevType(AdPlan plan, DevReportParam devReportParam) { + // 根据设备类型找到报告模板 + PqDevVO pqDevVO = iPqDevService.getPqDevById(devReportParam.getDevId()); + if (Objects.isNull(pqDevVO)) { + throw new BusinessException(ReportResponseEnum.DEVICE_NOT_EXIST); + } + // 获取设备型号 + DevType devType = devTypeService.getById(pqDevVO.getDevType()); + if (Objects.isNull(devType)) { + throw new BusinessException(ReportResponseEnum.DEVICE_TYPE_NOT_EXIST); + } + DictData reportName = devTypeService.getReportName(pqDevVO.getDevType()); + if (Objects.isNull(reportName)) { + throw new BusinessException(ReportResponseEnum.REPORT_TEMPLATE_NOT_EXIST); + } + // 读取模板文件 + ClassPathResource resource = new ClassPathResource("/model/" + reportName.getCode() + ReportConstant.DOCX); + try (InputStream inputStream = resource.getInputStream()) { + // 加载Word文档 + XWPFDocument baseModelDocument = new XWPFDocument(inputStream); + // 处理基础模版中的信息 + Map baseModelDataMap = dealBaseModelData(pqDevVO, devType, "${", "}"); + // 替换模板中的信息,避免信息丢失,段落和表格均参与替换 + WordUtil.replacePlaceholders(baseModelDocument, baseModelDataMap); + // 处理数据页中的信息 + dealDataModel(baseModelDocument, devReportParam, pqDevVO); + // 处理需要输出的目录地址 基础路径+设备类型+装置编号.docx + // 最终文件输出的路径 + String dirPath = reportPath.concat(File.separator).concat(devType.getName()); + // 确保目录存在 + ensureDirectoryExists(dirPath); + FileOutputStream out = new FileOutputStream(dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(".docx")); + // 4. 保存新的Word文档 + try { + baseModelDocument.write(out); } catch (IOException e) { - log.error("生成报告文件失败", e); - throw new RuntimeException(e); + throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR); } + out.close(); + + this.updateDevAndPlanState(devReportParam.getDevId(), devReportParam.getPlanId()); + } catch (IOException e) { + log.error(ReportResponseEnum.GENERATE_REPORT_ERROR.getMessage(), e); + throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR); } } /** * 根据计划绑定的报告模板生成报告 + * 注:该方法目前属于同用信息占位符替换,数据页为面向对象动态填充拼凑方式 * - * @param plan - * @param devReportParam + * @param plan 计划信息 + * @param devReportParam 设备信息 */ private void generateReportByPlan(AdPlan plan, DevReportParam devReportParam) { - // 根据设备类型找到报告模板 + // 准备被检设备的基础信息 PqDevVO pqDevVO = iPqDevService.getPqDevById(devReportParam.getDevId()); if (Objects.isNull(pqDevVO)) { throw new BusinessException(ReportResponseEnum.DEVICE_NOT_EXIST); @@ -566,41 +589,397 @@ public class PqReportServiceImpl extends ServiceImpl i if (Objects.isNull(report)) { throw new BusinessException(ReportResponseEnum.REPORT_TEMPLATE_NOT_EXIST); } - - FileSystemResource resource = new FileSystemResource(report.getBasePath()); - try (InputStream inputStream = resource.getInputStream()) { - // 加载Word文档 - XWPFDocument baseModelDocument = new XWPFDocument(inputStream); - // 处理基础模版中的信息 - dealBaseModel(baseModelDocument, pqDevVO, devType); - // 处理数据页中的信息 - dealDataModelZJ(baseModelDocument, devReportParam, pqDevVO); - // 处理需要输出的目录地址 基础路径+设备类型+装置编号.docx - // 最终文件输出的路径 + try { + WordprocessingMLPackage baseModelDocument = WordprocessingMLPackage.load(new File(report.getBasePath())); + WordprocessingMLPackage detailModelDocument = WordprocessingMLPackage.load(new File(report.getDetailPath())); + // 获取文档基础部分,并替换占位符 + MainDocumentPart baseDocumentPart = baseModelDocument.getMainDocumentPart(); + Map baseModelDataMap = dealBaseModelData(pqDevVO, devType, "", ""); + baseDocumentPart.variableReplace(baseModelDataMap); + // 获取数据模版页内容,根据脚本动态组装数据页内容 + MainDocumentPart detailDocumentPart = detailModelDocument.getMainDocumentPart(); + dealDataModelScattered(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO); + // 保存新的文档 String dirPath = reportPath.concat(File.separator).concat(devType.getName()); - ensureDirectoryExists(dirPath); // 确保目录存在 - FileOutputStream out = new FileOutputStream(dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(".docx")); - // 4. 保存新的Word文档 - try { - baseModelDocument.write(out); - } catch (IOException e) { - throw new BusinessException("生成报告文件失败"); - } - out.close(); - - System.out.println("报告生成成功!"); - - this.updateDevAndPlanState(devReportParam.getDevId(), devReportParam.getPlanId()); - } catch (IOException e) { - log.error("生成报告文件失败", e); - throw new RuntimeException(e); + // 确保目录存在 + ensureDirectoryExists(dirPath); + baseModelDocument.save(new File(dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(ReportConstant.DOCX))); + } catch (Exception e) { + log.error(ReportResponseEnum.GENERATE_REPORT_ERROR.getMessage(), e); + throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR); } } + /** + * 通用基础信息文档里可能会存在的书签锚点 + * 1、目录信息 + * 2、准确度测试详情 + * 3、测试结果页 + * 上述3个锚点位置不固定,可能结果页在通用信息中间,也有可能在文档最末端。 + * 注:当存在目录信息时,目录最后生成。 + * + * @param baseDocumentPart 通用信息文档 + * @param detailDocumentPart 数据项模板文档 + * @param devReportParam 测试报告参数 + * @param pqDevVO 被检设备 + */ + private void dealDataModelScattered(MainDocumentPart baseDocumentPart, MainDocumentPart detailDocumentPart, DevReportParam devReportParam, PqDevVO pqDevVO) { + // 查找 base 文档中所有以#{开始的书签所在的段落,并收集整理 + List baseContent = baseDocumentPart.getContent(); + List bookmarks = new ArrayList<>(); + for (int i = 0; i < baseContent.size(); i++) { + Object obj = baseContent.get(i); + if (obj instanceof P) { + P p = (P) obj; + String text = Docx4jUtil.getTextFromP(p).trim(); + if (text.startsWith(ReportConstant.BOOKMARK_START)) { + Bookmark bookmark = new Bookmark(i, DocAnchorEnum.getByKey(text)); + bookmarks.add(bookmark); + } + } + } + if (CollUtil.isNotEmpty(bookmarks)) { + /* + * 从结构上分析,处理的顺序: + * 1、数据项 + * 2、结果信息 + * 3、目录信息 + * 所以要先先获取的书签进行操作排序 + * */ + Collections.sort(bookmarks); + // 定义个结果,以便存在结果信息的书签 + Map> resultMap = new HashMap<>(); + // 书签在文档的位置 + int position; + for (int i = 0; i < bookmarks.size(); i++) { + Bookmark bookmark = bookmarks.get(i); + if (i == 0) { + position = bookmark.getIndex(); + } else { + // 经过处理后,原本的书签位置,已经被处理,所以需要重新获取 + position = Docx4jUtil.getParagraphPosition(baseDocumentPart, bookmark.getDocAnchorEnum()); + } + switch (bookmark.getDocAnchorEnum()) { + case DATA_LINE: + dealDataLine(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO, position, resultMap); + break; + case DATA_SCRIPT: + break; + case TEST_RESULT_DEV: + // 判断是否已经处理过数据了,有了结论性的描述 + if (CollUtil.isEmpty(resultMap)) { + dealDataLine(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO, position, resultMap); + } + dealTestResultLine(baseDocumentPart, detailDocumentPart, position, resultMap, DocAnchorEnum.TEST_RESULT_DEV); + break; + case TEST_RESULT_LINE: + // 判断是否已经处理过数据了,有了结论性的描述 + if (CollUtil.isEmpty(resultMap)) { + dealDataLine(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO, position, resultMap); + } + dealTestResultLine(baseDocumentPart, detailDocumentPart, position, resultMap, DocAnchorEnum.TEST_RESULT_LINE); + break; + case TEST_RESULT_DETAIL: + // 判断是否已经处理过数据了,有了结论性的描述 + if (CollUtil.isEmpty(resultMap)) { + dealDataLine(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO, position, resultMap); + } + dealTestResultLine(baseDocumentPart, detailDocumentPart, position, resultMap, DocAnchorEnum.TEST_RESULT_DETAIL); + break; + case CATALOG: + break; + default: + break; + } + } + } + + } + + + /** + * 如何处理结果性数据进文档,各省级平台的结果表格不一致,如何做到一致 + * + * @param baseDocumentPart 基础模板文档 + * @param detailDocumentPart 数据模板文档 + * @param position 书签在基础文档的位置 + * @param resultMap 各测试项的结果 + */ + private void dealTestResultLine(MainDocumentPart baseDocumentPart, MainDocumentPart detailDocumentPart, int position, Map> resultMap, DocAnchorEnum docAnchorEnum) { + // 先判断数据有没有,如果没有,则不处理 + if (CollUtil.isEmpty(resultMap.get(PowerIndexEnum.UNKNOWN.getKey()))) { + List paragraphs = baseDocumentPart.getContent(); + ObjectFactory factory = Context.getWmlObjectFactory(); + // 结论 + P newParagraph = factory.createP(); + Docx4jUtil.createTitle(factory, newParagraph, "检测结论", 28, true); + //插入段落 + paragraphs.add(position++, newParagraph); + // 源文档的内容 + // 创建表格(示例为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; + } + + Tr titleRow = Docx4jUtil.createCustomRow(factory, title, "SimSun", "宋体", 21, true, false); + table.getContent().add(titleRow); + // 处理业务数据 + resultMap.forEach((key, value) -> { + List cellValues = new ArrayList<>(); + PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(key); + if (indexEnum != null) { + 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, "SimSun", "宋体", 21, false, false); + table.getContent().add(tempRow); + }); + TblPr tblPr = Docx4jUtil.getTblPr(factory); + table.setTblPr(tblPr); + paragraphs.add(position++, table); + // 标签的位置,以便清空原标签 + if (position >= 0 && position < paragraphs.size()) { + paragraphs.remove(position); + } else { + System.out.println("指定的索引超出范围"); + } + } + + + } + + + /** + * 处理以回路为维度的数据项 + * + * @param baseModelDocument 基础模板 + * @param detailModelDocument 数据项模板 + * @param devReportParam 测试报告参数 + * @param pqDevVO 被检设备 + * @param position 待处理书签的位置 + */ + private void dealDataLine(MainDocumentPart baseModelDocument, MainDocumentPart detailModelDocument, DevReportParam devReportParam, PqDevVO pqDevVO, int position, Map> resultMap) { + // 源文档的内容 + List paragraphs = baseModelDocument.getContent(); + // 以回路维度处理数据项 + Integer devChns = pqDevVO.getDevChns(); + ObjectFactory factory = new ObjectFactory(); + // 读取该计划的检测大项组装数据内容 + List pqScriptDtlsList = pqScriptDtlsService.getScriptDtlsDataList(devReportParam.getScriptId()); + Map> scriptMap = pqScriptDtlsList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptCode)); + 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 newParagraph = factory.createP(); + Integer lineNo = i + 1; + Docx4jUtil.createTitle(factory, newParagraph, "测量回路" + lineNo, 28, true); + //插入段落 + paragraphs.add(position++, newParagraph); + // 依次处理大项文档内容 + Iterator>> iterator = scriptMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> next = iterator.next(); + String scriptCode = next.getKey(); + List checkckItemList = 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 = checkckItemList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptIndex)); + for (List scriptDtlDataItem : scriptIndexMap.values()) { + singleTestResult = resultService.getFinalContent(scriptDtlDataItem, devReportParam.getPlanCode(), pqDevVO.getId(), lineNo, tableKeys); + position = fillContentInTemplate(singleTestResult.getDetail(), position, tempContent, factory, pKeyValueMap, tableKeys, paragraphs); + } + } else { + // 非谐波类 + singleTestResult = resultService.getFinalContent(checkckItemList, devReportParam.getPlanCode(), pqDevVO.getId(), lineNo, tableKeys); + position = fillContentInTemplate(singleTestResult.getDetail(), position, tempContent, factory, pKeyValueMap, tableKeys, paragraphs); + } + 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)); + } + // 标签的位置,以便清空原标签 + if (position >= 0 && position < paragraphs.size()) { + paragraphs.remove(position); + } else { + System.out.println("指定的索引超出范围"); + } + + } + + /** + * 将查询的所有有效数据填充到模板中 + */ + private int fillContentInTemplate(Map>>>> finalContent, int position, List tempContent, + ObjectFactory factory, Map pKeyValueMap, List tableKeys, List paragraphs) { + 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); + 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(")"); + } + // 目前段落只有名称+误差范围,如果有补充后续在这里加。todo... + } + Docx4jUtil.addPContent(factory, innerP, text, rPr); + } + //插入段落 + paragraphs.add(position++, 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) { + // 删除最后一行,这行用来填模板key的,无需展示 + // 获取现有行的样式 + 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(); + 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 { + // 纵向表格暂不考虑 + } + // 插入段落 + paragraphs.add(position++, copiedTableElement); + } + } + + // 全部渲染完毕后,添加几个换行 + P p = factory.createP(); + Docx4jUtil.addBr(factory, p, 2); + paragraphs.add(position++, p); + + } + } + } + } + } + return position; + } + + private void updateDevAndPlanState(String devId, String planId) { // 将改设备的报告生成状态调整为已生成 iPqDevService.updatePqDevReportState(devId, DevReportStateEnum.GENERATED.getValue()); - // 判断该计划下是否所有设备报告已生成,如果已生成则将计划的报告状态给为已生成 int count = iPqDevService.countUnReportDev(planId); LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); @@ -656,62 +1035,55 @@ public class PqReportServiceImpl extends ServiceImpl i } + /** * 处理基础模版中的信息,非数据页报告 - * - * @param baseModelDocument 模板文件 + * 此处为什么要抽出拼接的前缀&后缀,是因为Docx4j工具包替换时会默认增加${},故在使用docx4j时前后缀必须为空 */ - private void dealBaseModel(XWPFDocument baseModelDocument, PqDevVO pqDevVO, DevType devType) { + private Map dealBaseModelData(PqDevVO pqDevVO, DevType devType, String prefix, String suffix) { // 首先获取非数据页中需要的信息 - Map baseModelMap = new HashMap<>(16); + Map baseModelMap = new HashMap<>(32); // 获取设备型号 - baseModelMap.put("${devType}", devType.getName()); - baseModelMap.put("${device_type}", devType.getName()); - // 调试人员,todo... 待咨询曹泽辉如何获取当前用户信息,目前先写死 - //String userName = RequestUtil.getUserName(); - SysUser user = sysUserService.getById(pqDevVO.getCheckBy()); - baseModelMap.put("${userName}", user.getName()); + baseModelMap.put(prefix + BaseReportKeyEnum.DEV_TYPE.getKey() + suffix, devType.getName()); + // 检测员 + baseModelMap.put(prefix + BaseReportKeyEnum.INSPECTOR.getKey() + suffix, pqDevVO.getCheckBy()); // 调试日期 if (pqDevVO.getCheckTime() != null) { - baseModelMap.put("${testDate}", DateUtil.format(pqDevVO.getCheckTime(), DatePattern.CHINESE_DATE_PATTERN)); + baseModelMap.put(prefix + BaseReportKeyEnum.TEST_DATE.getKey() + suffix, DateUtil.format(pqDevVO.getCheckTime(), DatePattern.CHINESE_DATE_PATTERN)); } else { - baseModelMap.put("${testDate}", DateUtil.format(new Date(), DatePattern.CHINESE_DATE_PATTERN)); + baseModelMap.put(prefix + BaseReportKeyEnum.TEST_DATE.getKey() + suffix, DateUtil.format(new Date(), DatePattern.CHINESE_DATE_PATTERN)); } // 装置编码 - baseModelMap.put("${CreateId}", pqDevVO.getCreateId()); + baseModelMap.put(prefix + BaseReportKeyEnum.DEV_CODE.getKey() + suffix, pqDevVO.getCreateId()); // 工作电源 - baseModelMap.put("${power}", devType.getPower()); + baseModelMap.put(prefix + BaseReportKeyEnum.POWER.getKey() + suffix, devType.getPower()); // 额定电流 - baseModelMap.put("${devCurr}", pqDevVO.getDevCurr().toString().concat("A")); + baseModelMap.put(prefix + BaseReportKeyEnum.DEV_CURR.getKey() + suffix, pqDevVO.getDevCurr().toString().concat(PowerConstant.CURRENT_UNIT)); // 额定电压 - baseModelMap.put("${devVolt}", pqDevVO.getDevVolt().toString().concat("V")); - - // 共有多少通道参与测试 -// if (CollectionUtil.isEmpty(pqDevById.getMonitorList())) { -// baseModelMap.put("${count}", "0"); -// } else { -// baseModelMap.put("${count}", pqDevById.getMonitorList().size() + ""); -// } - - baseModelMap.put("${count}", pqDevVO.getDevChns().toString()); - + baseModelMap.put(prefix + BaseReportKeyEnum.DEV_VOLT.getKey() + suffix, pqDevVO.getDevVolt().toString().concat(PowerConstant.VOLTAGE_UNIT)); + // 通道数 + baseModelMap.put(prefix + BaseReportKeyEnum.COUNT.getKey() + suffix, pqDevVO.getDevChns().toString()); + // 制造厂家 DictData dictData = dictDataService.getDictDataById(pqDevVO.getManufacturer()); if (ObjectUtil.isNotNull(dictData)) { - baseModelMap.put("${manufacturer}", dictData.getName()); + baseModelMap.put(prefix + BaseReportKeyEnum.MANUFACTURER.getKey() + suffix, dictData.getName()); } else { - baseModelMap.put("${manufacturer}", "未知"); + baseModelMap.put(prefix + BaseReportKeyEnum.MANUFACTURER.getKey() + suffix, StrPool.TAB); } - baseModelMap.put("${sample_id}", String.valueOf(pqDevVO.getSampleId())); - baseModelMap.put("${arrived_date}", String.valueOf(pqDevVO.getArrivedDate())); - baseModelMap.put("${check_date}", String.valueOf(pqDevVO.getCheckTime()).substring(0, 10)); - baseModelMap.put("${tested_by}", user.getName()); - - // 替换模板中的信息,避免信息丢失,段落和表格均参与替换 - WordUtil.replacePlaceholdersInParagraphs(baseModelDocument, baseModelMap); - WordUtil.replacePlaceholdersInTables(baseModelDocument, baseModelMap); - + // 样品编号 + baseModelMap.put(prefix + BaseReportKeyEnum.SAMPLE_ID.getKey() + suffix, StrUtil.isEmpty(pqDevVO.getSampleId()) ? StrPool.TAB : pqDevVO.getSampleId()); + // 收样日期 + baseModelMap.put(prefix + BaseReportKeyEnum.ARRIVED_DATE.getKey() + suffix, Objects.isNull(pqDevVO.getArrivedDate()) ? StrPool.TAB : String.valueOf(pqDevVO.getArrivedDate())); + // 检测日期 + baseModelMap.put(prefix + BaseReportKeyEnum.TEST_DATE.getKey() + suffix, Objects.isNull(pqDevVO.getCheckTime()) ? StrPool.TAB : String.valueOf(pqDevVO.getCheckTime()).substring(0, 10)); + baseModelMap.put(prefix + BaseReportKeyEnum.YEAR.getKey() + suffix, DateUtil.format(new Date(), DatePattern.NORM_YEAR_PATTERN)); + baseModelMap.put(prefix + BaseReportKeyEnum.MONTH.getKey() + suffix, DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN).substring(4)); + baseModelMap.put(prefix + BaseReportKeyEnum.DAY.getKey() + suffix, DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN).substring(6)); + baseModelMap.put(prefix + BaseReportKeyEnum.YEAR_MONTH_DAY.getKey() + suffix, DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN)); + return baseModelMap; } + /** * 获取数据页的信息 * diff --git a/detection/src/main/java/com/njcn/gather/report/utils/Docx4jInsertParagraph.java b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jInsertParagraph.java new file mode 100644 index 00000000..fdc8cc5c --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jInsertParagraph.java @@ -0,0 +1,44 @@ +package com.njcn.gather.report.utils; + +/** + * @author hongawen + * @version 1.0 + * @data 2025/3/25 19:37 + */ +import org.docx4j.openpackaging.packages.WordprocessingMLPackage; +import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; +import org.docx4j.wml.*; + +import java.io.File; +import java.math.BigInteger; +import java.util.List; + +public class Docx4jInsertParagraph { + public static void main(String[] args) throws Exception { + // 加载现有的 Word 文档 + WordprocessingMLPackage wordPackage = WordprocessingMLPackage.load(new File("C:\\Users\\hongawen\\Desktop\\base_template.docx")); + MainDocumentPart documentPart = wordPackage.getMainDocumentPart(); + + // 获取文档中的所有段落 + List paragraphs = documentPart.getContent(); + + // 在中间插入一个新段落 + int insertIndex = paragraphs.size() / 2; + P newParagraph = createParagraph("This is a new paragraph inserted in the middle."); + paragraphs.add(insertIndex, newParagraph); + + // 保存修改后的文档 + wordPackage.save(new File("example_modified.docx")); + } + + private static P createParagraph(String text) { + ObjectFactory factory = new ObjectFactory(); + P paragraph = factory.createP(); + R run = factory.createR(); + Text t = factory.createText(); + t.setValue(text); + run.getContent().add(t); + paragraph.getContent().add(run); + return paragraph; + } +} \ 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 new file mode 100644 index 00000000..a20a40fc --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/report/utils/Docx4jUtil.java @@ -0,0 +1,537 @@ +package com.njcn.gather.report.utils; + +import cn.hutool.core.collection.CollUtil; +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; +import java.util.List; +import java.util.Map; + +/** + * @author hongawen + * @version 1.0 + * @data 2025/3/26 13:47 + */ +public class Docx4jUtil { + + /** + * 创建标题 + * + * @param factory 工厂 + * @param paragraph 段落容器 + * @param content 标题内容 + * @param fontSize 字体大小 + * @param isBold 是否加粗 + */ + public static void createTitle(ObjectFactory factory, P paragraph, String content, int fontSize, boolean isBold) { + R run = factory.createR(); + Text text = factory.createText(); + text.setValue(content); + // 创建运行属性 + RPr rPr = factory.createRPr(); + // 设置字体 + RFonts fonts = factory.createRFonts(); + fonts.setAscii("Arial"); + // 宋体 + fonts.setEastAsia("SimSun"); + rPr.setRFonts(fonts); + + // 设置字号 + HpsMeasure size = new HpsMeasure(); + // 12号字=24 + size.setVal(new BigInteger("" + fontSize)); + rPr.setSz(size); + rPr.setSzCs(size); + + // 设置粗体 + if (isBold) { + BooleanDefaultTrue b = new BooleanDefaultTrue(); + rPr.setB(b); + } + run.setRPr(rPr); + run.getContent().add(text); + // 换行 +// Br br = factory.createBr(); +// run.getContent().add(br); + paragraph.getContent().add(run); + } + + /** + * 提取Heading 5及其子内容 + * + * @param allContent 文档内所有内容 + */ + public static List extractHeading5Contents(List allContent) { + List result = new ArrayList<>(); + boolean inHeading5Section = false; + HeadingContent currentHeading = null; + + for (Object obj : allContent) { + + if (obj instanceof P) { + P paragraph = (P) obj; + if (isHeading5(paragraph)) { + // 发现新的Heading 5,保存前一个并创建新的 + if (currentHeading != null) { + result.add(currentHeading); + } + currentHeading = new HeadingContent(); + currentHeading.setHeadingText(getTextFromP(paragraph)); + inHeading5Section = true; + } else if (inHeading5Section) { + // 当前内容属于Heading 5的子内容 + currentHeading.addSubContent(paragraph); + } + } else if (obj instanceof JAXBElement && inHeading5Section) { + // 表格属于当前Heading 5的子内容 + JAXBElement jaxbElement = (JAXBElement) obj; + if (jaxbElement.getValue() instanceof Tbl) { + currentHeading.addSubContent(obj); + } + } else if (isHigherLevelHeading(obj)) { + // 遇到更高级别的标题,结束当前Heading 5的收集 + if (currentHeading != null) { + result.add(currentHeading); + currentHeading = null; + } + inHeading5Section = false; + } + + + } + + // 添加最后一个Heading 5 + if (currentHeading != null) { + result.add(currentHeading); + } + return result; + } + + // 判断段落是否为Heading 5 + private static boolean isHeading5(P paragraph) { + PPr ppr = paragraph.getPPr(); + if (ppr != null) { + PPrBase.PStyle pStyle = ppr.getPStyle(); + if (pStyle != null && "5".equals(pStyle.getVal())) { + return true; + } + } + return false; + } + + // 判断是否为更高级别的标题(1-4) + private static boolean isHigherLevelHeading(Object obj) { + if (obj instanceof P) { + PPr ppr = ((P) obj).getPPr(); + if (ppr != null) { + PPrBase.PStyle pStyle = ppr.getPStyle(); + if (pStyle != null) { + String style = pStyle.getVal(); + return style != null && style.matches("[1-4]"); + } + } + } + return false; + } + + /** + * 判断表格是否横向 + * + * @param obj row + */ + public static boolean judgeTableCross(Object obj) { + Tr row = (Tr) obj; + List content = row.getContent(); + // 取最后一个单元格,判断是否包含汉字,有汉字就是横向的 + Object cellObject = content.get(content.size() - 1); + JAXBElement cellElement = (JAXBElement) cellObject; + Tc cell = cellElement.getValue(); + String text = getTextFromCell(cell); + if (StrUtil.isBlank(text)) { + return true; + } + // 遍历字符串中的每个字符,存在中文就认为是横向的,理论上设置的key全是英文 + for (char c : text.toCharArray()) { + // 检查字符是否在中文Unicode范围内 + if (c >= '\u4E00' && c <= '\u9FFF') { + // 发现中文字符,返回 false + return true; + } + } + return false; + } + + /** + * 读取cell内的文本内容 + */ + public static String getTextFromCell(Tc cell) { + List cellContent = cell.getContent(); + StringBuilder cellText = new StringBuilder(); + for (Object content : cellContent) { + if (content instanceof P) { + P paragraph = (P) content; + cellText.append(getTextFromP(paragraph)); + } + } + return cellText.toString(); + } + + + /** + * 从段落中提取纯文本 + * + * @param paragraph 段落 + * @return 段落内容 + */ + public static String getTextFromP(P paragraph) { + StringBuilder textContent = new StringBuilder(); + for (Object runObj : paragraph.getContent()) { + if (runObj instanceof R) { + R run = (R) runObj; + for (Object textObj : run.getContent()) { + if (textObj instanceof Text) { + textContent.append(((Text) textObj).getValue()); + } else if (textObj instanceof JAXBElement) { + JAXBElement jaxbElement = (JAXBElement) textObj; + if (jaxbElement.getValue() instanceof Text) { + Text temp = (Text) jaxbElement.getValue(); + textContent.append(temp.getValue()); + } + } + } + } + } + return textContent.toString().trim(); + } + + /** + * 获取段落的样式 + * + * @param paragraph 段落 + */ + public static RPr getTcPrFromParagraph(P paragraph) { + // 1. 获取段落中的所有内容 + List content = paragraph.getContent(); + // 2. 清空原有内容但保留第一个Run的样式 + RPr preservedRPr = null; + if (!content.isEmpty()) { + Object firstObj = content.get(0); + if (firstObj instanceof R) { + // 保存第一个Run的样式 + preservedRPr = ((R) firstObj).getRPr(); + } + } + return preservedRPr; + } + + /** + * 段落中添加内容 + */ + public static void addPContent(ObjectFactory factory, P paragraph, String content, RPr rPr) { + R run = factory.createR(); + Text text = factory.createText(); + text.setValue(content); + run.setRPr(rPr); + run.getContent().add(text); + paragraph.getContent().add(run); + } + + /** + * 创建N个换行符 + */ + public static void addBr(ObjectFactory factory, P paragraph, int n) { + R run = factory.createR(); + for (int i = 0; i < n; i++) { + // 换行 + Br br = factory.createBr(); + run.getContent().add(br); + } + paragraph.getContent().add(run); + } + + /** + * 根据表格行获取需要填的值的key + */ + public static List getTableKey(Tr row) { + List keys = new ArrayList<>(); + // 横向的,最后一行为需要填充的数据后,前面的均是表头 + // 遍历获取出该row的所有key + List content = row.getContent(); + for (Object cellObject : content) { + if (cellObject instanceof JAXBElement) { + JAXBElement cellElement = (JAXBElement) cellObject; + Tc cell = cellElement.getValue(); + keys.add(Docx4jUtil.getTextFromCell(cell)); + } + } + return keys; + } + + /** + * 获取内容中需要填充的keys + * + * @param tempContent 标题下配置的内容 + */ + public static List> getFillKeys(List tempContent) { + List> keys = new ArrayList<>(); + List pKeys = new ArrayList<>(); + List tableKeys = new ArrayList<>(); + if (CollUtil.isNotEmpty(tempContent)) { + // 读取该表下模板里面的内容,这整个内容需要跟随误差范围循环的,确保内容的数据比较用的一个误差范围 + Docx4jUtil.HeadingContent headingContent = tempContent.get(0); + for (Object object : headingContent.getSubContent()) { + if (object instanceof P) { + // 如果是段落,渲染段落内容 + P paragraph = (P) object; + String textFromP = getTextFromP(paragraph); + String[] splitKeys = textFromP.split(StrPool.DASHED); + pKeys.addAll(Arrays.asList(splitKeys)); + } else if (object instanceof JAXBElement) { + // 复制表格元素 + JAXBElement copiedTableElement = (JAXBElement) object; + // 解析表格并插入对应数据,最关键的是得知道表格是横向还是纵向以及表头占了几行 + Tbl tbl = copiedTableElement.getValue(); + // 获取表格的行 + List rows = tbl.getContent(); + boolean isRow = Docx4jUtil.judgeTableCross(rows.get(0)); + if (isRow) { + // 获取需要填的值的key + List cellKeys = Docx4jUtil.getTableKey((Tr) rows.get(rows.size() - 1)); + tableKeys.addAll(cellKeys); + } else { + // 纵向表格暂不考虑 + } + } + } + } + keys.add(pKeys); + keys.add(tableKeys); + return keys; + + } + + /** + * 根据已知信息创建新航 + * + * @param factory 工厂 + * @param valueMap 数据 + * @param tableKeys keys + * @param trPr 行样式 + * @param tcPr 单元格样式 + */ + public static Tr createCustomRow(ObjectFactory factory, Map valueMap, List tableKeys, TrPr trPr, TcPr tcPr, boolean centerFlag) { + Tr row = factory.createTr(); + for (String tableKey : tableKeys) { + Tc cell = factory.createTc(); + P paragraph = factory.createP(); + R run = factory.createR(); + String value = valueMap.get(tableKey); + Text text = factory.createText(); + text.setValue(value); + run.getContent().add(text); + paragraph.getContent().add(run); + // 设置段落居中 + if (centerFlag) { + PPr pPr = factory.createPPr(); + Jc jc = factory.createJc(); + jc.setVal(JcEnumeration.CENTER); + pPr.setJc(jc); + paragraph.setPPr(pPr); + } + if (value.equals("不合格")) { + RPr rPr = factory.createRPr(); + Color color = factory.createColor(); + // 红色 + color.setVal("FF0000"); + rPr.setColor(color); + run.setRPr(rPr); + } + cell.getContent().add(paragraph); + cell.setTcPr(tcPr); + row.getContent().add(cell); + row.setTrPr(trPr); + } + return row; + } + + + /** + * 根据已知信息创建新行 + * + * @param factory 工厂 + * @param cellValues 数据 + * @param ascFontStyle 西文字体 + * @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) { + Tr row = factory.createTr(); + for (String value : cellValues) { + Tc cell = factory.createTc(); + P paragraph = factory.createP(); + R run = factory.createR(); + Text text = factory.createText(); + text.setValue(value); + run.getContent().add(text); + paragraph.getContent().add(run); + // 设置段落居中 + if (centerFlag) { + PPr pPr = factory.createPPr(); + Jc jc = factory.createJc(); + jc.setVal(JcEnumeration.CENTER); + pPr.setJc(jc); + paragraph.setPPr(pPr); + } + RPr rPr = factory.createRPr(); + if (value.equals("不合格")) { + Color color = factory.createColor(); + // 红色 + color.setVal("FF0000"); + rPr.setColor(color); + } + if(boldFlag){ + BooleanDefaultTrue bold = factory.createBooleanDefaultTrue(); + rPr.setB(bold); + } + RFonts fonts = factory.createRFonts(); + // 西文字体 + fonts.setAscii(ascFontStyle); + // 中文字体 + fonts.setEastAsia(eastFontStyle); + rPr.setRFonts(fonts); + + HpsMeasure fontSize = factory.createHpsMeasure(); + fontSize.setVal(BigInteger.valueOf(size)); + // 西文字号 + rPr.setSz(fontSize); + // 中文字号 + rPr.setSzCs(fontSize); + + run.setRPr(rPr); + cell.getContent().add(paragraph); + row.getContent().add(cell); + } + return row; + } + + public static JAXBElement deepCopyTbl(JAXBElement original) throws Exception { + // 使用 docx4j 的 XmlUtils 进行深拷贝 + WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); + Tbl clonedTbl = (Tbl) XmlUtils.deepCopy(original.getValue()); + + // 重新包装为 JAXBElement + return new JAXBElement( + original.getName(), + original.getDeclaredType(), + original.getScope(), + clonedTbl + ); + } + + + + // 存储Heading 5及其子内容的辅助类 + public static class HeadingContent { + private String headingText; + private List subContent = new ArrayList<>(); + + public void setHeadingText(String text) { + this.headingText = text; + } + + public String getHeadingText() { + return headingText; + } + + public void addSubContent(Object obj) { + subContent.add(obj); + } + + public List getSubContent() { + return subContent; + } + } + + /** + * 获取段落在文档中的位置 + */ + public static int getParagraphPosition(MainDocumentPart baseDocumentPart, DocAnchorEnum docAnchorEnum) { + List baseContent = baseDocumentPart.getContent(); + for (int i = 0; i < baseContent.size(); i++) { + Object obj = baseContent.get(i); + if (obj instanceof P) { + P p = (P) obj; + String text = getTextFromP(p).trim(); + if (text.startsWith(ReportConstant.BOOKMARK_START)) { + DocAnchorEnum anchorEnum = DocAnchorEnum.getByKey(text); + if (anchorEnum != null && anchorEnum.getKey().equalsIgnoreCase(docAnchorEnum.getKey())) { + return i; + } + } + } + } + return -1; + } + + /** + * 获取表格样式 + */ + public static TblPr getTblPr(ObjectFactory factory) { + // **关键步骤:设置黑色实线边框** + TblPr tblPr = factory.createTblPr(); + TblBorders borders = factory.createTblBorders(); + + // 定义边框样式(1磅黑色单实线) + CTBorder border = new CTBorder(); + // 实线类型 + border.setVal(STBorder.SINGLE); + // 1磅=4单位(1/8磅) + border.setSz(BigInteger.valueOf(4)); + // 黑色 + border.setColor("000000"); + + // 应用边框到所有边 + borders.setTop(border); + borders.setBottom(border); + borders.setLeft(border); + borders.setRight(border); + // 内部水平线 + borders.setInsideH(border); + // 内部垂直线 + borders.setInsideV(border); + + tblPr.setTblBorders(borders); + + + // 设置表格宽度为96% + TblWidth tblWidth = factory.createTblWidth(); + // 百分比类型 + tblWidth.setType("pct"); + // 96% = 4800/5000 (ISO标准) + tblWidth.setW(BigInteger.valueOf(5000)); + tblPr.setTblW(tblWidth); + + return tblPr; + } + + +} diff --git a/detection/src/main/java/com/njcn/gather/report/utils/WordUtil.java b/detection/src/main/java/com/njcn/gather/report/utils/WordUtil.java index 7fdae256..450add31 100644 --- a/detection/src/main/java/com/njcn/gather/report/utils/WordUtil.java +++ b/detection/src/main/java/com/njcn/gather/report/utils/WordUtil.java @@ -1,7 +1,13 @@ package com.njcn.gather.report.utils; import org.apache.poi.xwpf.usermodel.*; +import org.apache.xmlbeans.XmlCursor; +import org.docx4j.openpackaging.packages.WordprocessingMLPackage; +import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -45,54 +51,6 @@ public class WordUtil { }); } - private static void insertPageBreak(XWPFDocument target) { - if(!isDocumentEmpty(target)){ - // 获取最后一个页面的段落 - XWPFParagraph pageBreakParagraph = getLastPageParagraph(target); - // 设置分页符 - pageBreakParagraph.setPageBreak(true); - } - - } - - public static boolean isDocumentEmpty(XWPFDocument document) { - // 检查段落 - List paragraphs = document.getParagraphs(); - if (paragraphs != null && !paragraphs.isEmpty()) { - for (XWPFParagraph paragraph : paragraphs) { - if (paragraph.getText() != null && !paragraph.getText().trim().isEmpty()) { - return false; - } - } - } - - // 检查表格 - List tables = document.getTables(); - if (tables != null && !tables.isEmpty()) { - return false; - } - - return true; - } - - public static XWPFParagraph getLastPageParagraph(XWPFDocument document) { - XWPFParagraph lastPageParagraph = null; - for (XWPFParagraph paragraph : document.getParagraphs()) { - lastPageParagraph = paragraph; - } - - return lastPageParagraph; - } - - private static boolean containsPageBreak(XWPFParagraph paragraph) { - for (XWPFRun run : paragraph.getRuns()) { - if (run.getText(0) != null && run.getText(0).contains("\f")) { - return true; - } - } - return false; - } - /** * 替换表格中的占位符 @@ -145,6 +103,42 @@ public class WordUtil { } } + /** + * 替换文档中的占位符 + * @param document 文档 + * @param placeholders 待替换的占位符 + */ + public static void replacePlaceholders(XWPFDocument document, Map placeholders) { + replacePlaceholdersInParagraphs(document,placeholders); + replacePlaceholdersInTables(document,placeholders); + } + + + public static List findHeadingLevel5Paragraphs(XWPFDocument document) { + List headingLevel5Paragraphs = new ArrayList<>(); + for (XWPFParagraph paragraph : document.getParagraphs()) { + String style = paragraph.getStyle(); + if ("5".equals(style)) { + headingLevel5Paragraphs.add(paragraph); + } + } + return headingLevel5Paragraphs; + } + + + /** + * 获取段落的位置(通过遍历bodyElements) + */ + public static int getBodyElementPosition(XWPFDocument document, XWPFParagraph paragraph) { + List bodyElements = document.getBodyElements(); + for (int i = 0; i < bodyElements.size(); i++) { + if (bodyElements.get(i) instanceof XWPFParagraph && bodyElements.get(i).equals(paragraph)) { + return i; + } + } + return -1; + } + } diff --git a/detection/src/main/java/com/njcn/gather/result/service/IResultService.java b/detection/src/main/java/com/njcn/gather/result/service/IResultService.java index 3ac6f4b1..7e891e67 100644 --- a/detection/src/main/java/com/njcn/gather/result/service/IResultService.java +++ b/detection/src/main/java/com/njcn/gather/result/service/IResultService.java @@ -1,11 +1,14 @@ package com.njcn.gather.result.service; +import com.njcn.gather.report.pojo.result.SingleTestResult; import com.njcn.gather.result.pojo.param.ResultParam; import com.njcn.gather.result.pojo.vo.FormContentVO; import com.njcn.gather.result.pojo.vo.ResultVO; import com.njcn.gather.result.pojo.vo.TreeDataVO; +import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO; import java.util.List; +import java.util.Map; /** * @author caozehui @@ -75,4 +78,22 @@ public interface IResultService { * @param param */ void reCalculate(ResultParam.ChangeErrorSystemParam param); + + /** + * 获取某测试大项的检测项内容 + * + * @param checkDataVOList 检测项脚本 + * @param planCode 计划编号 + * @param devId 被检设备id + * @param lineNo 回路号 + * @param tableKeys 表格key + */ + SingleTestResult getFinalContent(List checkDataVOList, String planCode, String devId, Integer lineNo, List tableKeys); + + /** + * 获取段落中指定的key对应的值 + * @param itemCode 测试大项code + * @param pKeys 待填充的值 + */ + Map getParagraphKeysValue(String itemCode, List pKeys); } 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 8c6fa627..bb5f1080 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 @@ -4,20 +4,30 @@ import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DatePattern; +import cn.hutool.core.text.StrPool; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.njcn.common.pojo.enums.common.DataStateEnum; import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.utils.PubUtils; import com.njcn.gather.detection.pojo.enums.DetectionCodeEnum; import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum; import com.njcn.gather.detection.pojo.param.PreDetectionParam; import com.njcn.gather.detection.pojo.po.DevData; +import com.njcn.gather.detection.pojo.vo.DetectionData; import com.njcn.gather.detection.service.impl.DetectionServiceImpl; import com.njcn.gather.device.service.IPqDevService; import com.njcn.gather.plan.pojo.po.AdPlan; import com.njcn.gather.plan.service.IAdPlanService; import com.njcn.gather.pojo.enums.DetectionResponseEnum; +import com.njcn.gather.report.pojo.constant.PowerConstant; +import com.njcn.gather.report.pojo.enums.AffectEnum; +import com.njcn.gather.report.pojo.enums.ItemReportKeyEnum; +import com.njcn.gather.report.pojo.enums.PowerIndexEnum; +import com.njcn.gather.report.pojo.result.SingleTestResult; import com.njcn.gather.result.pojo.enums.ResultUnitEnum; import com.njcn.gather.result.pojo.param.ResultParam; import com.njcn.gather.result.pojo.vo.FormContentVO; @@ -30,10 +40,12 @@ import com.njcn.gather.script.pojo.param.PqScriptIssueParam; import com.njcn.gather.script.pojo.po.PqScriptCheckData; import com.njcn.gather.script.pojo.po.PqScriptDtls; import com.njcn.gather.script.pojo.po.SourceIssue; +import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO; import com.njcn.gather.script.service.IPqScriptCheckDataService; import com.njcn.gather.script.service.IPqScriptDtlsService; import com.njcn.gather.script.util.ScriptDtlsDesc; import com.njcn.gather.storage.mapper.TableGenMapper; +import com.njcn.gather.storage.pojo.param.SingleNonHarmParam; import com.njcn.gather.storage.pojo.param.StorageParam; import com.njcn.gather.storage.pojo.po.AdBaseResult; import com.njcn.gather.storage.pojo.po.AdHarmonicResult; @@ -910,6 +922,528 @@ public class ResultServiceImpl implements IResultService { this.calculateResult(param.getPlanId(), param.getScriptId(), param.getCode(), param.getErrorSysId(), param.getDeviceId()); } + /** + * 获取某测试大项的检测项内容,主要针对表格需要填充的值 + * 注:虽然测试项区是三相,他们的标准值可能不同,但是误差范围是一致的 + * 1、区分额定条件、单影响量条件、单影响量条件 + * 2、区分scriptIndex + * 3、区分谐波次数(有必要的情况下) + * + * @param dtlDataVOList 检测项脚本 + * @param planCode 计划编号 + * @param devId 被检设备id + * @param lineNo 回路号 + * @param tableKeys 表格key + */ + @Override + public SingleTestResult getFinalContent(List dtlDataVOList, String planCode, String devId, Integer lineNo, List tableKeys) { + SingleTestResult singleTestResult = new SingleTestResult(); + Map>>>> finalContent = new HashMap<>(); + if (CollUtil.isNotEmpty(dtlDataVOList)) { + // 首先区分测试条件 + Map> subTypeMap = dtlDataVOList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptSubType)); + subTypeMap.forEach((subType, scriptDtlDataVOList) -> { + AffectEnum affectEnum = AffectEnum.getByKey(subType); + if (Objects.nonNull(affectEnum)) { + String scriptCode = scriptDtlDataVOList.get(0).getScriptCode(); + String scriptId = scriptDtlDataVOList.get(0).getScriptId(); + PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(scriptCode); + if (Objects.nonNull(indexEnum)) { + String affectName = affectEnum.getDesc().replaceAll("XX", indexEnum.getDesc()); + // 同一个影响量下,获取出子脚本信息 + List indexList = scriptDtlDataVOList.stream().map(PqScriptDtlDataVO::getScriptIndex).distinct().collect(Collectors.toList()); + List scriptCheckDataList = pqScriptCheckDataService.listCheckData(scriptId, indexList); + List valueTypeList = scriptCheckDataList.stream().map(PqScriptCheckData::getValueType).distinct().collect(Collectors.toList()); + // 查询检测结果,区分下表。 + if (PowerConstant.TIME.contains(scriptCode)) { + // 谐波的测试项,肯定是三相的,可能会存在多次的,本处要填充的key全集为:time、standard、standardA、standardB、standardC、testA、testB、testC、errorA、errorB、errorC、result + // 查询结果数据,经过上层处理谐波类此处的scriptIndex确保只有一个 + if (indexList.size() == 1 && valueTypeList.size() == 1) { + // 获取谐波数据 + SingleNonHarmParam param = new SingleNonHarmParam(Integer.parseInt(planCode), devId, lineNo, valueTypeList.get(0), indexList.get(0)); + AdHarmonicResult singleResult = adHarmonicService.getSingleResult(param); + // 注:如果ABC的标准值一致,则同步到standard中 + Map> checkDataHarmNumMap = scriptCheckDataList.stream().collect(Collectors.groupingBy(PqScriptCheckData::getHarmNum)); + List> keyFillMapList = new ArrayList<>(); + checkDataHarmNumMap.forEach((harmNum, dtlsList) -> { + Map keyFillMap = new HashMap<>(); + // 次数需要区分谐波&间谐波 + String time; + if (harmNum % 1 == 0) { + // 谐波,需要转为正数字符串 + time = String.valueOf(harmNum.intValue()); + } else { + // 间谐波,保留小数位转为字符串 + time = String.format("%.1f", harmNum); + } + keyFillMap.put(ItemReportKeyEnum.TIME.getKey(), time); + // 将间谐波次数取整1.5取2,2.5取3 + double timeDouble = Math.round(harmNum); + int timeInt = (int) timeDouble; + DetectionData tempA = getResultData(singleResult, timeInt, PowerConstant.PHASE_A); + DetectionData tempB = getResultData(singleResult, timeInt, PowerConstant.PHASE_B); + DetectionData tempC = getResultData(singleResult, timeInt, PowerConstant.PHASE_C); + // 待填充Key + String standard = "/", standardA = "/", standardB = "/", standardC = "/", + testA = "/", testB = "/", testC = "/", + errorA = "/", errorB = "/", errorC = "/", + resultA = "/", resultB = "/", resultC = "/", result = "/", + errorScope = "/", unit = ""; + + 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(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 (errorScope.equals("/")) { + errorScope = tempB.getRadius(); + } + if (StrUtil.isBlank(unit)) { + unit = tempB.getUnit(); + } + if (standard.equals("/")) { + standard = 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 (errorScope.equals("/")) { + errorScope = tempC.getRadius(); + } + if (StrUtil.isBlank(unit)) { + unit = tempC.getUnit(); + } + if (standard.equals("/")) { + standard = PubUtils.doubleRoundStr(4, tempC.getResultData()); + } + } + if (standardA.equals(standardB) && standardA.equals(standardC)) { + standard = standardA; + } + // 标准值 + keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); + keyFillMap.put(ItemReportKeyEnum.STANDARD_A.getKey(), standardA); + keyFillMap.put(ItemReportKeyEnum.STANDARD_B.getKey(), standardB); + keyFillMap.put(ItemReportKeyEnum.STANDARD_C.getKey(), standardC); + // 测试值 + keyFillMap.put(ItemReportKeyEnum.TEST_A.getKey(), testA); + keyFillMap.put(ItemReportKeyEnum.TEST_B.getKey(), testB); + keyFillMap.put(ItemReportKeyEnum.TEST_C.getKey(), testC); + // 误差值 + keyFillMap.put(ItemReportKeyEnum.ERROR_A.getKey(), errorA); + keyFillMap.put(ItemReportKeyEnum.ERROR_B.getKey(), errorB); + keyFillMap.put(ItemReportKeyEnum.ERROR_C.getKey(), errorC); + // 结果 + keyFillMap.put(ItemReportKeyEnum.RESULT_A.getKey(), resultA); + keyFillMap.put(ItemReportKeyEnum.RESULT_B.getKey(), resultB); + keyFillMap.put(ItemReportKeyEnum.RESULT_C.getKey(), resultC); + if (resultA.equals("不合格") || resultB.equals("不合格") || resultC.equals("不合格")) { + result = "不合格"; + } else if (!resultA.equals("/") || !resultB.equals("/") || !resultC.equals("/")) { + result = "合格"; + } + keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result); + errorScope = dealErrorScope(errorScope).concat(unit); + keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope); + keyFillMapList.add(keyFillMap); + }); + // 按次数排序 + PubUtils.sortByDoubleValue(keyFillMapList, ItemReportKeyEnum.TIME.getKey()); + // 取出任意一次谐波数据的误差范围作为key + String titleScope = keyFillMapList.get(0).get(ItemReportKeyEnum.ERROR_SCOPE.getKey()); + Map>> errorScoperMap = new HashMap<>(); + errorScoperMap.put(titleScope, keyFillMapList); + List>>> errorScoperMapList = new ArrayList<>(); + errorScoperMapList.add(errorScoperMap); + finalContent.put(affectName, errorScoperMapList); + } else { + log.error("生成谐波类表格数据失败,脚本配置不支持,请核实。"); + throw new BusinessException("生成谐波类表格数据失败,脚本配置不支持,请核实。"); + } + } else { + // 非谐波的需要区分是否为ABC相还是T相 + if (PowerConstant.THREE_PHASE.contains(scriptCode)) { + if (valueTypeList.size() == 1) { + // 获取该三相的数据 + SingleNonHarmParam param = new SingleNonHarmParam(Integer.parseInt(planCode), devId, lineNo, valueTypeList, indexList); + List nonHarmList = adNonHarmonicService.queryByCondition(param); + // 三相的数据通常包含:standard、standardA、standardB、standardC、testA、testB、testC、errorA、errorB、errorC、resultA、resultB、resultC、result、errorScope + if (CollUtil.isNotEmpty(nonHarmList)) { + List> keyFillMapList = new ArrayList<>(); + for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { + Map keyFillMap = new HashMap<>(16); + DetectionData tempA = getResultData(adNonHarmonicResult, null, PowerConstant.PHASE_A); + DetectionData tempB = getResultData(adNonHarmonicResult, null, PowerConstant.PHASE_B); + DetectionData tempC = getResultData(adNonHarmonicResult, null, PowerConstant.PHASE_C); + // 待填充Key + String standard = "/", standardA = "/", standardB = "/", standardC = "/", + testA = "/", testB = "/", testC = "/", + errorA = "/", errorB = "/", errorC = "/", + resultA = "/", resultB = "/", resultC = "/", result = "/", + errorScope = "/", unit = ""; + 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(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 (errorScope.equals("/")) { + errorScope = tempB.getRadius(); + } + if (StrUtil.isBlank(unit)) { + unit = tempB.getUnit(); + } + if (standard.equals("/")) { + standard = 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 (errorScope.equals("/")) { + errorScope = tempC.getRadius(); + } + if (StrUtil.isBlank(unit)) { + unit = tempC.getUnit(); + } + if (standard.equals("/")) { + standard = PubUtils.doubleRoundStr(4, tempC.getResultData()); + } + } + if (standardA.equals(standardB) && standardA.equals(standardC)) { + standard = standardA; + } + // 标准值 + keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); + keyFillMap.put(ItemReportKeyEnum.STANDARD_A.getKey(), standardA); + keyFillMap.put(ItemReportKeyEnum.STANDARD_B.getKey(), standardB); + keyFillMap.put(ItemReportKeyEnum.STANDARD_C.getKey(), standardC); + // 测试值 + keyFillMap.put(ItemReportKeyEnum.TEST_A.getKey(), testA); + keyFillMap.put(ItemReportKeyEnum.TEST_B.getKey(), testB); + keyFillMap.put(ItemReportKeyEnum.TEST_C.getKey(), testC); + // 误差值 + keyFillMap.put(ItemReportKeyEnum.ERROR_A.getKey(), errorA); + keyFillMap.put(ItemReportKeyEnum.ERROR_B.getKey(), errorB); + keyFillMap.put(ItemReportKeyEnum.ERROR_C.getKey(), errorC); + // 结果 + keyFillMap.put(ItemReportKeyEnum.RESULT_A.getKey(), resultA); + keyFillMap.put(ItemReportKeyEnum.RESULT_B.getKey(), resultB); + keyFillMap.put(ItemReportKeyEnum.RESULT_C.getKey(), resultC); + if (resultA.equals("不合格") || resultB.equals("不合格") || resultC.equals("不合格")) { + result = "不合格"; + } else if (!resultA.equals("/") || !resultB.equals("/") || !resultC.equals("/")) { + result = "合格"; + } + keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result); + errorScope = dealErrorScope(errorScope).concat(unit); + keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope); + keyFillMapList.add(keyFillMap); + } + // 需要对所有的填充进行按误差范围分组 + Map>> errorScoperMap = keyFillMapList.stream() + .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()))); + // 分组后,还需要针对标准值进行一个升序 + errorScoperMap.forEach((errorScope, maps) -> { + PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD.getKey()); + }); + List>>> errorList = new ArrayList<>(); + errorList.add(errorScoperMap); + // 最后赋值返回 + finalContent.put(affectName, errorList); + } else { + log.error("生成三相类表格数据失败,结果表数据丢失,请核实。"); + } + } else { + log.error("生成三相类表格数据失败,脚本配置不支持,请核实。"); + throw new BusinessException("生成三相类表格数据失败,脚本配置不支持,请核实。"); + } + } else { + // 非三相的还需要特殊处理下暂态的 + if (PowerConstant.VOLTAGE.equalsIgnoreCase(scriptCode)) { + // 暂态的valueType通常只有2个,一个特征幅值,一个持续时间 + List> keyFillMapList = new ArrayList<>(); + for (Integer sort : indexList) { + SingleNonHarmParam param = new SingleNonHarmParam(Integer.parseInt(planCode), devId, lineNo, valueTypeList, Collections.singletonList(sort)); + List nonHarmList = adNonHarmonicService.queryByCondition(param); + // 暂态的数据通常包含:standardMag、standardDur、testMag、testDur、errorMag、errorDur、resultMag、resultDur、result、errorScope、errorScopeMag、errorScopeDur + if (CollUtil.isNotEmpty(nonHarmList)) { + String standardMag = "/", standardDur = "/", + testMag = "/", testDur = "/", + errorMag = "/", errorDur = "/", + resultMag = "/", resultDur = "/", result, + errorScope, errorScopeMag = "/", errorScopeDur = "/", + unitMag = "", unitDur = ""; + Map keyFillMap = new HashMap<>(16); + for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { + DetectionData tempT = getResultData(adNonHarmonicResult, null, PowerConstant.PHASE_T); + // 需要判断adNonHarmonicResult是特征幅值还是持续时间 + String adType = adNonHarmonicResult.getAdType(); + 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 ? "合格" : "不合格"; + unitMag = tempT.getUnit(); + errorScopeMag = tempT.getRadius(); + } + } else if (temp.getCode().equalsIgnoreCase("DUR")) { + // 持续时间,需要注意时间单位处理,默认是秒 + String timeUnit = "s"; + for (String tableKey : tableKeys) { + if (tableKey.contains(ItemReportKeyEnum.STANDARD_DUR.getKey())) { + //截取单位 + String[] tempStr = tableKey.split(StrPool.UNDERLINE); + if (tempStr.length > 1) { + if (tempStr[1].equalsIgnoreCase("ms")) { + timeUnit = "ms"; + } + } + } + } + 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 (timeUnit.equalsIgnoreCase("ms")) { + // 如果是ms,上述的一些数据需要重新处理 + if (!standardDur.equalsIgnoreCase("/")) { + standardDur = PubUtils.doubleRoundStr(4, Double.parseDouble(standardDur) * 1000); + } + if (!testDur.equalsIgnoreCase("/")) { + testDur = PubUtils.doubleRoundStr(4, Double.parseDouble(testDur) * 1000); + } + if (!errorDur.equalsIgnoreCase("/")) { + errorDur = PubUtils.doubleRoundStr(4, Double.parseDouble(errorDur) * 1000); + } + if(!errorScopeDur.equalsIgnoreCase("/")){ + if(errorScopeDur.contains("~")){ + String[] tempStr = errorScopeDur.split("~"); + errorScopeDur = PubUtils.doubleRoundStr(0, Double.parseDouble(tempStr[0]) * 1000).concat("~").concat(PubUtils.doubleRoundStr(0, Double.parseDouble(tempStr[1]) * 1000)); + } + } + unitDur = "ms"; + } + } + } + errorScopeMag = dealErrorScope(errorScopeMag).concat(unitMag); + errorScopeDur = dealErrorScope(errorScopeDur).concat(unitDur); + + errorScope = "特征幅值:".concat(errorScopeMag).concat(StrPool.COMMA).concat("持续时间:").concat(errorScopeDur); + keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope); + // 标准值 + keyFillMap.put(ItemReportKeyEnum.STANDARD_MAG.getKey(), standardMag); + keyFillMap.put(ItemReportKeyEnum.STANDARD_DUR.getKey(), standardDur); + // 测试值 + keyFillMap.put(ItemReportKeyEnum.TEST_MAG.getKey(), testMag); + keyFillMap.put(ItemReportKeyEnum.TEST_DUR.getKey(), testDur); + // 误差 + keyFillMap.put(ItemReportKeyEnum.ERROR_MAG.getKey(), errorMag); + keyFillMap.put(ItemReportKeyEnum.ERROR_DUR.getKey(), errorDur); + // 结果 + keyFillMap.put(ItemReportKeyEnum.RESULT_MAG.getKey(), resultMag); + keyFillMap.put(ItemReportKeyEnum.RESULT_DUR.getKey(), resultDur); + // 综合结果 + result = resultMag; + if (!resultDur.equals("/") && result.equals("合格")) { + if (resultDur.equals("不合格")) { + result = "不合格"; + } + } + keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result); + keyFillMapList.add(keyFillMap); + } + } + // 需要对所有填充进行按误差范围分组 + Map>> errorScoperMap = keyFillMapList.stream() + .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()))); + // 分组后,还需要针对特征幅值标准值进行一个升序 + errorScoperMap.forEach((errorScope, maps) -> { + PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD_MAG.getKey()); + }); + List>>> errorList = new ArrayList<>(); + errorList.add(errorScoperMap); + // 最后赋值返回 + finalContent.put(affectName, errorList); + } else { + // 非三相且非暂态,通常只有一个数据,所以直接赋值即可 + List> keyFillMapList = new ArrayList<>(); + SingleNonHarmParam param = new SingleNonHarmParam(Integer.parseInt(planCode), devId, lineNo, valueTypeList, indexList); + List nonHarmList = adNonHarmonicService.queryByCondition(param); + if (CollUtil.isNotEmpty(nonHarmList)) { + for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) { + String standard = "/", test = "/", error = "/", result = "/", errorScope = "/",unit = ""; + Map keyFillMap = new HashMap<>(8); + DetectionData tempT = getResultData(adNonHarmonicResult, null, 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(); + } + keyFillMap.put(ItemReportKeyEnum.STANDARD.getKey(), standard); + keyFillMap.put(ItemReportKeyEnum.TEST.getKey(), test); + keyFillMap.put(ItemReportKeyEnum.ERROR.getKey(), error); + keyFillMap.put(ItemReportKeyEnum.RESULT.getKey(), result); + errorScope = dealErrorScope(errorScope).concat(unit); + keyFillMap.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope); + keyFillMapList.add(keyFillMap); + } + } + // 需要对所有填充进行按误差范围分组 + Map>> errorScoperMap = keyFillMapList.stream() + .collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey()))); + // 分组后,还需要针对特征幅值标准值进行一个升序 + errorScoperMap.forEach((errorScope, maps) -> { + PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD.getKey()); + }); + List>>> errorList = new ArrayList<>(); + errorList.add(errorScoperMap); + // 最后赋值返回 + finalContent.put(affectName, errorList); + } + } + } + } else { + log.error("未找到合适的脚本信息"); + } + } else { + log.error("未找到合适的测量条件"); + } + }); + } + + // 返回之前做下总结性判断 + singleTestResult.setQualified(judgeQualified(finalContent)); + singleTestResult.setDetail(finalContent); + return singleTestResult; + } + + /** + * 处理下误差范围,如果正负数一致时调整为±的形式 + * 数据库中一般形式为:-0.1155~0.1155 + * + * @param errorScope 误差范围 + */ + private String dealErrorScope(String errorScope) { + if (errorScope.contains("~")) { + String[] split = errorScope.split("~"); + String begin = split[0]; + if (begin.contains(StrPool.DASHED)) { + begin = begin.substring(1); + } + String end = split[1]; + if (end.equalsIgnoreCase(begin)) { + return "±" + begin; + } + } + return errorScope; + } + + /** + * 遍历所有的结果,是否存在不合格,但凡有一个不合格就返回false + * + * @param finalContent 最终结果 + */ + private boolean judgeQualified(Map>>>> finalContent) { + List results = finalContent.values().parallelStream() + .flatMap(List::stream) + .flatMap(m -> m.values().stream()) + .flatMap(List::stream) + .filter(map -> map.containsKey(ItemReportKeyEnum.RESULT.getKey())) + .map(map -> map.get(ItemReportKeyEnum.RESULT.getKey())) + .collect(Collectors.toList()); + List qualifiedList = results.stream().filter("不合格"::equals).collect(Collectors.toList()); + return CollUtil.isEmpty(qualifiedList); + } + + /** + * 根据谐波结果数据获取局的测试数据 + * + * @param singleResult 谐波数据 + * @param timeInt 次数 + * @param phaseA 相别 + */ + private DetectionData getResultData(Object singleResult, Integer timeInt, String phaseA) { + String fieldName = phaseA.toLowerCase().concat("Value"); + if (Objects.nonNull(timeInt)) { + fieldName = fieldName.concat(String.valueOf(timeInt)); + } + String filedValue; + try { + filedValue = (String) ReflectUtil.getFieldValue(singleResult, fieldName); + } catch (Exception exception) { + throw new BusinessException("获取对象字段属性失败"); + } + return JSONUtil.toBean(filedValue, DetectionData.class); + } + + + /** + * 获取段落中指定的key对应的值,目前主要为测试大项名称服务,通过code匹配 + * + * @param itemCode 测试大项code + * @param pKeys 待填充的值 + */ + @Override + public Map getParagraphKeysValue(String itemCode, List pKeys) { + Map map = new HashMap<>(); + if (CollUtil.isNotEmpty(pKeys)) { + for (String pKey : pKeys) { + ItemReportKeyEnum reportKeyEnum = ItemReportKeyEnum.getByKey(pKey); + if (Objects.nonNull(reportKeyEnum)) { + if (reportKeyEnum.getKey().equals(ItemReportKeyEnum.NAME.getKey())) { + PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(itemCode); + if (Objects.nonNull(indexEnum)) { + map.put(reportKeyEnum.getKey(), indexEnum.getDesc()); + } else { + log.error("电能指标枚举未找到测试项"); + } + } else if (reportKeyEnum.getKey().equals(ItemReportKeyEnum.NAME_DETAIL.getKey())) { + PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(itemCode); + if (Objects.nonNull(indexEnum)) { + map.put(reportKeyEnum.getKey(), indexEnum.getDesc().concat("测量准确度")); + } else { + log.error("电能指标枚举未找到测试项"); + } + } + } else { + log.error("段落枚举未找到占用符"); + } + } + } + return map; + } + private Integer conform(Set numbers) { if (CollUtil.isNotEmpty(numbers)) { if (numbers.size() > 1) { diff --git a/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptCheckDataMapper.java b/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptCheckDataMapper.java index ca25a3fb..f578bf73 100644 --- a/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptCheckDataMapper.java +++ b/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptCheckDataMapper.java @@ -2,6 +2,10 @@ package com.njcn.gather.script.mapper; import com.github.yulichang.base.MPJBaseMapper; import com.njcn.gather.script.pojo.po.PqScriptCheckData; +import com.njcn.gather.script.pojo.vo.PqScriptCheckDataVO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; /** * @Description: diff --git a/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptDtlsMapper.java b/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptDtlsMapper.java index 13fca7f8..1b87ebfa 100644 --- a/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptDtlsMapper.java +++ b/detection/src/main/java/com/njcn/gather/script/mapper/PqScriptDtlsMapper.java @@ -2,8 +2,12 @@ package com.njcn.gather.script.mapper; import com.github.yulichang.base.MPJBaseMapper; import com.njcn.gather.script.pojo.po.PqScriptDtls; +import com.njcn.gather.script.pojo.vo.PqScriptCheckDataVO; +import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO; import org.apache.ibatis.annotations.Param; +import java.util.List; + /** * @author caozehui * @date 2024-11-18 @@ -17,5 +21,7 @@ public interface PqScriptDtlsMapper extends MPJBaseMapper { * @return */ Integer selectMaxIndex(@Param("scriptId") String scriptId); + + List getScriptDtlsDataList(@Param("scriptId")String scriptId); } diff --git a/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptCheckDataMapper.xml b/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptCheckDataMapper.xml index d06d03bf..5e1fe9de 100644 --- a/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptCheckDataMapper.xml +++ b/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptCheckDataMapper.xml @@ -2,6 +2,5 @@ - diff --git a/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptDtlsMapper.xml b/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptDtlsMapper.xml index 58e37fc8..e7464f82 100644 --- a/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptDtlsMapper.xml +++ b/detection/src/main/java/com/njcn/gather/script/mapper/mapping/PqScriptDtlsMapper.xml @@ -10,5 +10,21 @@ WHERE Script_Id = #{scriptId} + + diff --git a/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptCheckDataVO.java b/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptCheckDataVO.java new file mode 100644 index 00000000..44602ee3 --- /dev/null +++ b/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptCheckDataVO.java @@ -0,0 +1,24 @@ +package com.njcn.gather.script.pojo.vo; + +import com.njcn.gather.script.pojo.po.PqScriptCheckData; +import lombok.Data; + +/** + * @author hongawen + * @version 1.0 + * @data 2025/3/26 14:45 + */ +@Data +public class PqScriptCheckDataVO extends PqScriptCheckData { + + /** + * 脚本项名称 + */ + private String scriptName; + + /** + * 脚本项Code + */ + private String scriptCode; + +} diff --git a/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptDtlDataVO.java b/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptDtlDataVO.java index a9d3f507..b2995687 100644 --- a/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptDtlDataVO.java +++ b/detection/src/main/java/com/njcn/gather/script/pojo/vo/PqScriptDtlDataVO.java @@ -1,23 +1,23 @@ package com.njcn.gather.script.pojo.vo; +import com.njcn.gather.script.pojo.po.PqScriptDtls; import lombok.Data; import java.io.Serializable; @Data -public class PqScriptDtlDataVO implements Serializable { +public class PqScriptDtlDataVO extends PqScriptDtls implements Serializable { private static final long serialVersionUID = 1L; /** - * 这条检测脚本的序号 + * 脚本项名称 */ - private String index; - - - - - + private String scriptName; + /** + * 脚本项Code + */ + private String scriptCode; } \ No newline at end of file diff --git a/detection/src/main/java/com/njcn/gather/script/service/IPqScriptCheckDataService.java b/detection/src/main/java/com/njcn/gather/script/service/IPqScriptCheckDataService.java index 73b6c591..fe737e16 100644 --- a/detection/src/main/java/com/njcn/gather/script/service/IPqScriptCheckDataService.java +++ b/detection/src/main/java/com/njcn/gather/script/service/IPqScriptCheckDataService.java @@ -3,6 +3,7 @@ package com.njcn.gather.script.service; import com.baomidou.mybatisplus.extension.service.IService; import com.njcn.gather.script.pojo.param.PqScriptCheckDataParam; import com.njcn.gather.script.pojo.po.PqScriptCheckData; +import com.njcn.gather.script.pojo.vo.PqScriptCheckDataVO; import java.util.List; import java.util.Map; @@ -36,4 +37,11 @@ public interface IPqScriptCheckDataService extends IService { List listCheckDataCode(PqScriptCheckDataParam param); Double getCheckDataValue(PqScriptCheckDataParam param); + + /** + * 查询条件范围内的参与比较的脚本详情 + * @param scriptId 脚本id + * @param indexList 脚本下标集合 + */ + List listCheckData(String scriptId, List indexList); } diff --git a/detection/src/main/java/com/njcn/gather/script/service/IPqScriptDtlsService.java b/detection/src/main/java/com/njcn/gather/script/service/IPqScriptDtlsService.java index d9e3e881..f784820e 100644 --- a/detection/src/main/java/com/njcn/gather/script/service/IPqScriptDtlsService.java +++ b/detection/src/main/java/com/njcn/gather/script/service/IPqScriptDtlsService.java @@ -9,6 +9,8 @@ import com.njcn.gather.script.pojo.param.ScriptParam; import com.njcn.gather.script.pojo.po.PqScriptCheckData; import com.njcn.gather.script.pojo.po.PqScriptDtls; import com.njcn.gather.script.pojo.po.SourceIssue; +import com.njcn.gather.script.pojo.vo.PqScriptCheckDataVO; +import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO; import java.util.List; import java.util.Map; @@ -139,4 +141,9 @@ public interface IPqScriptDtlsService extends IService { * @return */ Map getScriptToIcdCheckInfo(PreDetectionParam param); + /** + * 根据脚本id获取脚本详情数据 + * @param scriptId 脚本id + */ + List getScriptDtlsDataList(String scriptId); } diff --git a/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptCheckDataServiceImpl.java b/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptCheckDataServiceImpl.java index cf693e31..408596c8 100644 --- a/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptCheckDataServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptCheckDataServiceImpl.java @@ -13,6 +13,8 @@ import com.njcn.gather.detection.pojo.enums.DetectionResponseEnum; import com.njcn.gather.script.mapper.PqScriptCheckDataMapper; import com.njcn.gather.script.pojo.param.PqScriptCheckDataParam; import com.njcn.gather.script.pojo.po.PqScriptCheckData; +import com.njcn.gather.script.pojo.po.PqScriptDtls; +import com.njcn.gather.script.pojo.vo.PqScriptCheckDataVO; import com.njcn.gather.script.service.IPqScriptCheckDataService; import com.njcn.gather.system.dictionary.mapper.DictTreeMapper; import com.njcn.gather.system.dictionary.pojo.po.DictTree; @@ -121,5 +123,16 @@ public class PqScriptCheckDataServiceImpl extends ServiceImpl listCheckData(String scriptId, List indexList) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(PqScriptCheckData::getScriptId, scriptId) + .eq(PqScriptCheckData::getEnable, DataStateEnum.ENABLE.getCode()) + .eq(PqScriptCheckData::getErrorFlag, 1) + .in(PqScriptCheckData::getScriptIndex, indexList) + .orderByAsc(PqScriptCheckData::getHarmNum); + return this.list(queryWrapper); + } + } diff --git a/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptDtlsServiceImpl.java b/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptDtlsServiceImpl.java index 80ea98d6..cd172ab7 100644 --- a/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptDtlsServiceImpl.java +++ b/detection/src/main/java/com/njcn/gather/script/service/impl/PqScriptDtlsServiceImpl.java @@ -29,6 +29,8 @@ import com.njcn.gather.script.pojo.po.PqScript; import com.njcn.gather.script.pojo.po.PqScriptCheckData; import com.njcn.gather.script.pojo.po.PqScriptDtls; import com.njcn.gather.script.pojo.po.SourceIssue; +import com.njcn.gather.script.pojo.vo.PqScriptCheckDataVO; +import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO; import com.njcn.gather.script.service.IPqScriptCheckDataService; import com.njcn.gather.script.service.IPqScriptDtlsService; import com.njcn.gather.script.util.ScriptDtlsDesc; @@ -739,6 +741,11 @@ public class PqScriptDtlsServiceImpl extends ServiceImpl getScriptDtlsDataList(String scriptId) { + return this.baseMapper.getScriptDtlsDataList(scriptId); + } + private void unbanCheck(List info, PqScriptDtlsParam.CheckData channelListDTO, List list, diff --git a/entrance/src/main/java/com/njcn/gather/advice/LogAdvice.java b/entrance/src/main/java/com/njcn/gather/advice/LogAdvice.java new file mode 100644 index 00000000..91c6daf4 --- /dev/null +++ b/entrance/src/main/java/com/njcn/gather/advice/LogAdvice.java @@ -0,0 +1,105 @@ +package com.njcn.gather.advice; + + +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.gather.system.log.service.ISysLogAuditService; +import com.njcn.web.utils.HttpServletUtil; +import com.njcn.web.utils.ReflectCommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +import javax.annotation.Nonnull; +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.*; + + +/** + * @author caozehui + * @data 2024-12-2 + */ +@Slf4j +@ControllerAdvice +public class LogAdvice implements ResponseBodyAdvice { + + @Autowired + private ISysLogAuditService logService; + + private final ThreadPoolExecutor executor = new ThreadPoolExecutor( + 4, 8, 30, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(100), + // 队列满时由主线程执行 + new ThreadPoolExecutor.CallerRunsPolicy() + ); + + + /** + * 无需审计记录的操作,比如根据客户端获取客户端信息 + */ + + private final static List UN_LOG_INFO = Collections.singletonList("未知业务"); + + + /** + * controller返回的响应体包含的状态码,而非全局异常捕获器处抛出来的状态码 + */ + private final static List FILTER_CODE = Arrays.asList(CommonResponseEnum.SUCCESS.getCode(), CommonResponseEnum.FAIL.getCode(), CommonResponseEnum.NO_DATA.getCode()); + + + /** + * 判断下结果,是不是成功 + * + * @param returnType 返回类型,包含大量信息,controller、method、result等等 + * @param converterType 消息转换器类型,目前配置的是Jackson + */ + @Override + public boolean supports(MethodParameter returnType, Class converterType) { + return true; + } + + /** + * 拦截所有请求成功的操作进行日志入库处理 + * 需要 用户标识、事件描述、事件结果、操作IP、事件类型、事件严重度、操作时间、操作类型 + * + * @param body . + * @param returnType . + * @param selectedContentType . + * @param selectedConverterType . + * @param request . + * @param response . + * @return . + */ + @Override + public Object beforeBodyWrite(Object body, @Nonnull MethodParameter returnType, @Nonnull MediaType selectedContentType, @Nonnull Class selectedConverterType, @Nonnull ServerHttpRequest request, @Nonnull ServerHttpResponse response) { + if (body instanceof HttpResult) { + HttpResult httpResult = (HttpResult) body; + if (FILTER_CODE.contains(httpResult.getCode())) { + // 传递上下文 + HttpServletRequest httpServletRequest = HttpServletUtil.getRequest(); + String methodDescribe = ReflectCommonUtil.getMethodDescribeByMethod(returnType.getMethod()); + if (!UN_LOG_INFO.contains(methodDescribe)) { + Future future = executor.submit(() -> { + HttpServletUtil.setRequest(httpServletRequest); + logService.recodeAdviceLog(returnType, httpResult, methodDescribe); + }); + try { + // 抛出 ExecutionException + future.get(); + } catch (ExecutionException | InterruptedException e) { + log.error("保存审计日志异常,异常为:"+e.getMessage()); + } + } + } + } + return body; + } +} diff --git a/entrance/src/main/java/com/njcn/gather/handler/GlobalBusinessExceptionHandler.java b/entrance/src/main/java/com/njcn/gather/handler/GlobalBusinessExceptionHandler.java index 9e7e6d8f..d45170b8 100644 --- a/entrance/src/main/java/com/njcn/gather/handler/GlobalBusinessExceptionHandler.java +++ b/entrance/src/main/java/com/njcn/gather/handler/GlobalBusinessExceptionHandler.java @@ -6,11 +6,14 @@ import com.njcn.common.pojo.enums.response.CommonResponseEnum; import com.njcn.common.pojo.exception.BusinessException; import com.njcn.common.pojo.response.HttpResult; import com.njcn.common.utils.LogUtil; +import com.njcn.gather.system.log.service.ISysLogAuditService; import com.njcn.web.utils.HttpResultUtil; +import com.njcn.web.utils.HttpServletUtil; import com.njcn.web.utils.ReflectCommonUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.json.JSONException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.ObjectError; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -18,6 +21,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.util.NestedServletException; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; @@ -25,6 +29,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -40,7 +45,16 @@ import java.util.stream.Stream; @RestControllerAdvice public class GlobalBusinessExceptionHandler { -// private final ILogService logService; + @Resource + private final ISysLogAuditService sysLogAuditService; + + private final ThreadPoolExecutor executor = new ThreadPoolExecutor( + 4, 8, 30, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(100), + // 队列满时由主线程执行 + new ThreadPoolExecutor.CallerRunsPolicy() + ); + /** * 捕获业务功能异常,通常为业务数据抛出的异常 @@ -48,16 +62,9 @@ public class GlobalBusinessExceptionHandler { * @param businessException 业务异常 */ @ExceptionHandler(BusinessException.class) - public HttpResult handleBusinessException(HttpServletRequest httpServletRequest, BusinessException businessException) { + public HttpResult handleBusinessException(BusinessException businessException) { String operate = ReflectCommonUtil.getMethodDescribeByException(businessException); -// logService.recodeBusinessExceptionLog(businessException, httpServletRequest, businessException.getMessage()); - //判断方法上是否有自定义注解,做特殊处理 - Method method = ReflectCommonUtil.getMethod(businessException); -// if (!Objects.isNull(method)){ -// if(method.isAnnotationPresent(ReturnMsg.class)){ -// return HttpResultUtil.assembleResult(businessException.getCode(), null, StrFormatter.format("{}",businessException.getMessage())); -// } -// } + recodeAdviceLog(businessException, businessException.getMessage()); return HttpResultUtil.assembleBusinessExceptionResult(businessException, null, operate); } @@ -68,9 +75,9 @@ public class GlobalBusinessExceptionHandler { * @param nullPointerException 空指针异常 */ @ExceptionHandler(NullPointerException.class) - public HttpResult handleNullPointerException(HttpServletRequest httpServletRequest, NullPointerException nullPointerException) { + public HttpResult handleNullPointerException(NullPointerException nullPointerException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.NULL_POINTER_EXCEPTION.getMessage(), nullPointerException); -// logService.recodeBusinessExceptionLog(nullPointerException, httpServletRequest, CommonResponseEnum.NULL_POINTER_EXCEPTION.getMessage()); + recodeAdviceLog(nullPointerException, CommonResponseEnum.NULL_POINTER_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.NULL_POINTER_EXCEPTION, null, ReflectCommonUtil.getMethodDescribeByException(nullPointerException)); } @@ -80,9 +87,9 @@ public class GlobalBusinessExceptionHandler { * @param arithmeticException 算数运算异常,由于除数为0引起的异常 */ @ExceptionHandler(ArithmeticException.class) - public HttpResult handleArithmeticException(HttpServletRequest httpServletRequest, ArithmeticException arithmeticException) { + public HttpResult handleArithmeticException(ArithmeticException arithmeticException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.ARITHMETIC_EXCEPTION.getMessage(), arithmeticException); -// logService.recodeBusinessExceptionLog(arithmeticException, httpServletRequest, CommonResponseEnum.ARITHMETIC_EXCEPTION.getMessage()); + recodeAdviceLog(arithmeticException, CommonResponseEnum.ARITHMETIC_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.ARITHMETIC_EXCEPTION, null, ReflectCommonUtil.getMethodDescribeByException(arithmeticException)); } @@ -92,9 +99,9 @@ public class GlobalBusinessExceptionHandler { * @param classCastException 类型转换异常 */ @ExceptionHandler(ClassCastException.class) - public HttpResult handleClassCastException(HttpServletRequest httpServletRequest, ClassCastException classCastException) { + public HttpResult handleClassCastException(ClassCastException classCastException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.CLASS_CAST_EXCEPTION.getMessage(), classCastException); -// logService.recodeBusinessExceptionLog(classCastException, httpServletRequest, CommonResponseEnum.CLASS_CAST_EXCEPTION.getMessage()); + recodeAdviceLog(classCastException, CommonResponseEnum.CLASS_CAST_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.CLASS_CAST_EXCEPTION, null, ReflectCommonUtil.getMethodDescribeByException(classCastException)); } @@ -105,9 +112,9 @@ public class GlobalBusinessExceptionHandler { * @param indexOutOfBoundsException 索引下标越界异常 */ @ExceptionHandler(IndexOutOfBoundsException.class) - public HttpResult handleIndexOutOfBoundsException(HttpServletRequest httpServletRequest, IndexOutOfBoundsException indexOutOfBoundsException) { + public HttpResult handleIndexOutOfBoundsException(IndexOutOfBoundsException indexOutOfBoundsException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.INDEX_OUT_OF_BOUNDS_EXCEPTION.getMessage(), indexOutOfBoundsException); -// logService.recodeBusinessExceptionLog(indexOutOfBoundsException, httpServletRequest, CommonResponseEnum.INDEX_OUT_OF_BOUNDS_EXCEPTION.getMessage()); + recodeAdviceLog(indexOutOfBoundsException, CommonResponseEnum.INDEX_OUT_OF_BOUNDS_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.INDEX_OUT_OF_BOUNDS_EXCEPTION, null, ReflectCommonUtil.getMethodDescribeByException(indexOutOfBoundsException)); } @@ -117,10 +124,10 @@ public class GlobalBusinessExceptionHandler { * @param httpMediaTypeNotSupportedException 请求中参数的媒体方式不支持异常 */ @ExceptionHandler(HttpMediaTypeNotSupportedException.class) - public HttpResult httpMediaTypeNotSupportedExceptionHandler(HttpServletRequest httpServletRequest, HttpMediaTypeNotSupportedException httpMediaTypeNotSupportedException) { + public HttpResult httpMediaTypeNotSupportedExceptionHandler(HttpMediaTypeNotSupportedException httpMediaTypeNotSupportedException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getMessage(), httpMediaTypeNotSupportedException); // 然后提取错误提示信息进行返回 -// logService.recodeBusinessExceptionLog(httpMediaTypeNotSupportedException, httpServletRequest, CommonResponseEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getMessage()); + recodeAdviceLog(httpMediaTypeNotSupportedException, CommonResponseEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION, null, ReflectCommonUtil.getMethodDescribeByException(httpMediaTypeNotSupportedException)); } @@ -131,13 +138,13 @@ public class GlobalBusinessExceptionHandler { * @param methodArgumentNotValidException 参数校验异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) - public HttpResult methodArgumentNotValidExceptionHandler(HttpServletRequest httpServletRequest, MethodArgumentNotValidException methodArgumentNotValidException) { + public HttpResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException methodArgumentNotValidException) { // 从异常对象中拿到allErrors数据 String messages = methodArgumentNotValidException.getBindingResult().getAllErrors() .stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(";")); // 然后提取错误提示信息进行返回 LogUtil.njcnDebug(log, "参数校验异常,异常为:{}", messages); -// logService.recodeBusinessExceptionLog(methodArgumentNotValidException, httpServletRequest, CommonResponseEnum.METHOD_ARGUMENT_NOT_VALID_EXCEPTION.getMessage()); + recodeAdviceLog(methodArgumentNotValidException, CommonResponseEnum.METHOD_ARGUMENT_NOT_VALID_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.METHOD_ARGUMENT_NOT_VALID_EXCEPTION, messages, ControllerUtil.getMethodArgumentNotValidException(methodArgumentNotValidException)); } @@ -148,7 +155,7 @@ public class GlobalBusinessExceptionHandler { * @param constraintViolationException 参数校验异常 */ @ExceptionHandler(ConstraintViolationException.class) - public HttpResult constraintViolationExceptionExceptionHandler(HttpServletRequest httpServletRequest, ConstraintViolationException constraintViolationException) { + public HttpResult constraintViolationExceptionExceptionHandler(ConstraintViolationException constraintViolationException) { String exceptionMessage = constraintViolationException.getMessage(); StringBuilder messages = new StringBuilder(); if (exceptionMessage.indexOf(StrUtil.COMMA) > 0) { @@ -161,7 +168,7 @@ public class GlobalBusinessExceptionHandler { } // 然后提取错误提示信息进行返回 LogUtil.njcnDebug(log, "参数校验异常,异常为:{}", messages); -// logService.recodeBusinessExceptionLog(constraintViolationException, httpServletRequest, CommonResponseEnum.METHOD_ARGUMENT_NOT_VALID_EXCEPTION.getMessage()); + recodeAdviceLog(constraintViolationException, CommonResponseEnum.METHOD_ARGUMENT_NOT_VALID_EXCEPTION.getMessage()); List> constraintViolationList = new ArrayList<>(constraintViolationException.getConstraintViolations()); ConstraintViolation constraintViolation = constraintViolationList.get(0); Class rootBeanClass = constraintViolation.getRootBeanClass(); @@ -182,24 +189,12 @@ public class GlobalBusinessExceptionHandler { * @param illegalArgumentException 参数校验异常 */ @ExceptionHandler(IllegalArgumentException.class) - public HttpResult handleIndexOutOfBoundsException(HttpServletRequest httpServletRequest, IllegalArgumentException illegalArgumentException) { + public HttpResult handleIndexOutOfBoundsException(IllegalArgumentException illegalArgumentException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION.getMessage(), illegalArgumentException); -// logService.recodeBusinessExceptionLog(illegalArgumentException, httpServletRequest, CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION.getMessage()); + recodeAdviceLog(illegalArgumentException, CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION, illegalArgumentException.getMessage(), ReflectCommonUtil.getMethodDescribeByException(illegalArgumentException)); } -// /** -// * 表格校验异常 -// * -// * @param excelAnalysisException 表格校验异常 -// */ -// @ExceptionHandler(ExcelAnalysisException.class) -// public HttpResult handleExcelAnalysisException(HttpServletRequest httpServletRequest, ExcelAnalysisException excelAnalysisException) { -// LogUtil.logExceptionStackInfo(CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION.getMessage(), excelAnalysisException); -// // logService.recodeBusinessExceptionLog(excelAnalysisException, httpServletRequest,CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION.getMessage()); -// return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.ILLEGAL_ARGUMENT_EXCEPTION, excelAnalysisException.getCause().getMessage(), ReflectCommonUtil.getMethodDescribeByException(excelAnalysisException)); -// } - /** * 未声明异常捕捉 @@ -207,7 +202,7 @@ public class GlobalBusinessExceptionHandler { * @param exception 未声明异常 */ @ExceptionHandler(Exception.class) - public HttpResult handleException(HttpServletRequest httpServletRequest, Exception exception) { + public HttpResult handleException(Exception exception) { //针对fallbackFactory降级异常特殊处理 Exception tempException = exception; String exceptionCause = CommonResponseEnum.UN_DECLARE.getMessage(); @@ -224,7 +219,7 @@ public class GlobalBusinessExceptionHandler { } } LogUtil.logExceptionStackInfo(exceptionCause, tempException); -// logService.recodeBusinessExceptionLog(tempException, httpServletRequest, exceptionCause); + recodeAdviceLog(exception, exceptionCause); //判断方法上是否有自定义注解,做特殊处理 // Method method = ReflectCommonUtil.getMethod(exception); // if (!Objects.isNull(method)){ @@ -236,18 +231,30 @@ public class GlobalBusinessExceptionHandler { } - - /** * json解析异常 * * @param jsonException json参数 */ @ExceptionHandler(JSONException.class) - public HttpResult handleIndexOutOfBoundsException(HttpServletRequest httpServletRequest, JSONException jsonException) { + public HttpResult handleIndexOutOfBoundsException(JSONException jsonException) { LogUtil.logExceptionStackInfo(CommonResponseEnum.JSON_CONVERT_EXCEPTION.getMessage(), jsonException); -// logService.recodeBusinessExceptionLog(jsonException, httpServletRequest, CommonResponseEnum.JSON_CONVERT_EXCEPTION.getMessage()); + recodeAdviceLog(jsonException, CommonResponseEnum.JSON_CONVERT_EXCEPTION.getMessage()); return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.JSON_CONVERT_EXCEPTION, jsonException.getMessage(), ReflectCommonUtil.getMethodDescribeByException(jsonException)); } + private void recodeAdviceLog(Exception businessException, String methodDescribe) { + HttpServletRequest httpServletRequest = HttpServletUtil.getRequest(); + Future future = executor.submit(() -> { + HttpServletUtil.setRequest(httpServletRequest); + sysLogAuditService.recodeBusinessExceptionLog(businessException, methodDescribe); + }); + try { + // 抛出 ExecutionException + future.get(); + } catch (ExecutionException | InterruptedException e) { + log.error("保存审计日志异常,异常为:" + e.getMessage()); + } + } + } diff --git a/entrance/src/main/resources/model/njcn_882.docx b/entrance/src/main/resources/model/njcn_882.docx index 7596037a..8abab757 100644 Binary files a/entrance/src/main/resources/model/njcn_882.docx and b/entrance/src/main/resources/model/njcn_882.docx differ diff --git a/entrance/src/main/resources/model/njcn_882A.docx b/entrance/src/main/resources/model/njcn_882A.docx index 6794cdc6..ce1d478f 100644 Binary files a/entrance/src/main/resources/model/njcn_882A.docx and b/entrance/src/main/resources/model/njcn_882A.docx differ diff --git a/entrance/src/main/resources/model/njcn_882B1.docx b/entrance/src/main/resources/model/njcn_882B1.docx index f7ff66d3..0a8f4bf4 100644 Binary files a/entrance/src/main/resources/model/njcn_882B1.docx and b/entrance/src/main/resources/model/njcn_882B1.docx differ diff --git a/entrance/src/main/resources/model/njcn_882B2.docx b/entrance/src/main/resources/model/njcn_882B2.docx index aca5f527..ae687011 100644 Binary files a/entrance/src/main/resources/model/njcn_882B2.docx and b/entrance/src/main/resources/model/njcn_882B2.docx differ diff --git a/entrance/src/main/resources/model/njcn_882B3.docx b/entrance/src/main/resources/model/njcn_882B3.docx index b020dcfc..9f4237bb 100644 Binary files a/entrance/src/main/resources/model/njcn_882B3.docx and b/entrance/src/main/resources/model/njcn_882B3.docx differ diff --git a/entrance/src/main/resources/model/njcn_882B4.docx b/entrance/src/main/resources/model/njcn_882B4.docx index ec679f67..2b7f1acd 100644 Binary files a/entrance/src/main/resources/model/njcn_882B4.docx and b/entrance/src/main/resources/model/njcn_882B4.docx differ diff --git a/entrance/src/main/resources/model/njcn_882B5.docx b/entrance/src/main/resources/model/njcn_882B5.docx index 03c28b55..295f0109 100644 Binary files a/entrance/src/main/resources/model/njcn_882B5.docx and b/entrance/src/main/resources/model/njcn_882B5.docx differ diff --git a/entrance/src/main/resources/model/njcn_882B6.docx b/entrance/src/main/resources/model/njcn_882B6.docx index d6cb8c40..4924d9a7 100644 Binary files a/entrance/src/main/resources/model/njcn_882B6.docx and b/entrance/src/main/resources/model/njcn_882B6.docx differ diff --git a/entrance/src/test/java/com/njcn/BaseJunitTest.java b/entrance/src/test/java/com/njcn/BaseJunitTest.java new file mode 100644 index 00000000..71c41933 --- /dev/null +++ b/entrance/src/test/java/com/njcn/BaseJunitTest.java @@ -0,0 +1,37 @@ +package com.njcn; + +import com.njcn.gather.EntranceApplication; +import com.njcn.gather.report.pojo.DevReportParam; +import com.njcn.gather.report.service.IPqReportService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.web.WebAppConfiguration; + + +/** + * @author hongawen + * @version 1.0.0 + * @date 2021年12月10日 15:05 + */ +@RunWith(SpringRunner.class) +@WebAppConfiguration +@SpringBootTest(classes = EntranceApplication.class) +public class BaseJunitTest { + + @Autowired + private IPqReportService pqReportService; + + @Test + public void test() { + DevReportParam devReportParam = new DevReportParam(); + devReportParam.setPlanId("ad3df9e4a90b4c3c8ce7d21a84ce6f59"); + devReportParam.setPlanCode("31"); + devReportParam.setScriptId("810e4050e1d445e3542c998a077a263a"); + devReportParam.setDevId("a46349a3b3cf4789a6b82690a6076afd"); + pqReportService.generateReport(devReportParam); + } + +} diff --git a/storage/src/main/java/com/njcn/gather/storage/pojo/param/SingleNonHarmParam.java b/storage/src/main/java/com/njcn/gather/storage/pojo/param/SingleNonHarmParam.java index fe93f8b7..252f2ae5 100644 --- a/storage/src/main/java/com/njcn/gather/storage/pojo/param/SingleNonHarmParam.java +++ b/storage/src/main/java/com/njcn/gather/storage/pojo/param/SingleNonHarmParam.java @@ -1,7 +1,9 @@ package com.njcn.gather.storage.pojo.param; import io.swagger.models.auth.In; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.List; @@ -12,6 +14,8 @@ import java.util.List; * @data 2025/1/10 16:06 */ @Data +@NoArgsConstructor +@AllArgsConstructor public class SingleNonHarmParam implements Serializable { private static final long serialVersionUID = 1L; @@ -36,6 +40,11 @@ public class SingleNonHarmParam implements Serializable { */ private String adType; + /** + * 测试项类型,暂态的存在多个 + */ + private List valueTypeList; + /** * 测试项所在脚本的位置 */ @@ -43,4 +52,35 @@ public class SingleNonHarmParam implements Serializable { private List sortList; + public SingleNonHarmParam(Integer planCode, String devId, Integer channelNo, String adType, Integer sort) { + this.planCode = planCode; + this.devId = devId; + this.channelNo = channelNo; + this.adType = adType; + this.sort = sort; + } + + public SingleNonHarmParam(Integer planCode, String devId, Integer channelNo, String adType, List sortList) { + this.planCode = planCode; + this.devId = devId; + this.channelNo = channelNo; + this.adType = adType; + this.sortList = sortList; + } + + public SingleNonHarmParam(Integer planCode, String devId, Integer channelNo, List valueTypeList, Integer sort) { + this.planCode = planCode; + this.devId = devId; + this.channelNo = channelNo; + this.valueTypeList = valueTypeList; + this.sort = sort; + } + + public SingleNonHarmParam(Integer planCode, String devId, Integer channelNo, List valueTypeList, List sortList) { + this.planCode = planCode; + this.devId = devId; + this.channelNo = channelNo; + this.valueTypeList = valueTypeList; + this.sortList = sortList; + } } diff --git a/storage/src/main/java/com/njcn/gather/storage/service/AdNonHarmonicService.java b/storage/src/main/java/com/njcn/gather/storage/service/AdNonHarmonicService.java index ea5c53b4..59beefbc 100644 --- a/storage/src/main/java/com/njcn/gather/storage/service/AdNonHarmonicService.java +++ b/storage/src/main/java/com/njcn/gather/storage/service/AdNonHarmonicService.java @@ -55,4 +55,12 @@ public interface AdNonHarmonicService extends IService { * @return */ List listAll(String scriptId,String code,String devId); + + /** + * 根据查询条件查找结果 + * @param param 查询条件 + */ + List queryByCondition(SingleNonHarmParam param); + + } diff --git a/storage/src/main/java/com/njcn/gather/storage/service/impl/AdHarmonicServiceImpl.java b/storage/src/main/java/com/njcn/gather/storage/service/impl/AdHarmonicServiceImpl.java index 5855b169..0946611b 100644 --- a/storage/src/main/java/com/njcn/gather/storage/service/impl/AdHarmonicServiceImpl.java +++ b/storage/src/main/java/com/njcn/gather/storage/service/impl/AdHarmonicServiceImpl.java @@ -230,6 +230,7 @@ public class AdHarmonicServiceImpl extends ServiceImpl adHarmonicResults = this.getBaseMapper().selectJoinList(AdHarmonicResult.class, wrapper); + DynamicTableNameHandler.remove(); if (CollectionUtil.isNotEmpty(adHarmonicResults)) { return adHarmonicResults.get(0); } diff --git a/storage/src/main/java/com/njcn/gather/storage/service/impl/AdNonHarmonicServiceImpl.java b/storage/src/main/java/com/njcn/gather/storage/service/impl/AdNonHarmonicServiceImpl.java index 0069b3d7..21f834e8 100644 --- a/storage/src/main/java/com/njcn/gather/storage/service/impl/AdNonHarmonicServiceImpl.java +++ b/storage/src/main/java/com/njcn/gather/storage/service/impl/AdNonHarmonicServiceImpl.java @@ -14,6 +14,7 @@ import com.njcn.gather.storage.mapper.AdNonHarmonicMapper; import com.njcn.gather.storage.pojo.param.SingleNonHarmParam; import com.njcn.gather.storage.pojo.param.StorageParam; import com.njcn.gather.storage.pojo.po.AdBaseResult; +import com.njcn.gather.storage.pojo.po.AdHarmonicResult; import com.njcn.gather.storage.pojo.po.AdNonHarmonicResult; import com.njcn.gather.storage.pojo.vo.RawDataVO; import com.njcn.gather.storage.pojo.vo.RawResultDataVO; @@ -164,6 +165,20 @@ public class AdNonHarmonicServiceImpl extends ServiceImpl queryByCondition(SingleNonHarmParam param) { + String prefix = "ad_non_harmonic_result_"; + DynamicTableNameHandler.setTableName(prefix + param.getPlanCode()); + MPJLambdaWrapper wrapper = new MPJLambdaWrapper<>(); + wrapper.like(AdNonHarmonicResult::getMonitorId, param.getDevId() + "_" + param.getChannelNo()) + .in(AdNonHarmonicResult::getSort, param.getSortList()) + .in(AdNonHarmonicResult::getAdType, param.getValueTypeList()); + List adNonHarmonicResults = this.getBaseMapper().selectJoinList(AdNonHarmonicResult.class, wrapper); + DynamicTableNameHandler.remove(); + return adNonHarmonicResults; + } + + private String unit(String code) { String unit = ""; switch (code) { diff --git a/system/src/main/java/com/njcn/gather/system/log/aop/LogAdvice.java b/system/src/main/java/com/njcn/gather/system/log/aop/LogAdvice.java deleted file mode 100644 index e6c23b0d..00000000 --- a/system/src/main/java/com/njcn/gather/system/log/aop/LogAdvice.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.njcn.gather.system.log.aop; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.njcn.common.pojo.annotation.OperateInfo; -import com.njcn.common.pojo.enums.response.CommonResponseEnum; -import com.njcn.common.pojo.exception.BusinessException; -import com.njcn.common.pojo.response.HttpResult; -import com.njcn.db.mybatisplus.constant.UserConstant; -import com.njcn.gather.system.log.pojo.enums.LogLevelEnum; -import com.njcn.gather.system.log.pojo.enums.LogOperationTypeEnum; -import com.njcn.gather.system.log.pojo.po.SysLogAudit; -import com.njcn.gather.system.log.service.ISysLogAuditService; -import com.njcn.gather.system.pojo.enums.SystemResponseEnum; -import com.njcn.gather.user.user.pojo.param.SysUserParam; -import com.njcn.gather.user.user.pojo.po.SysUser; -import com.njcn.gather.user.user.service.ISysUserService; -import com.njcn.web.utils.RequestUtil; -import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Method; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.TimeUnit; - -/** - * @author caozehui - * @data 2024-12-2 - */ - -@Aspect -@Component -@RequiredArgsConstructor -public class LogAdvice implements ApplicationListener { - - private final ISysLogAuditService sysLogAuditService; - private final ISysUserService sysUserService; - private final List IGNORE_METHOD = new ArrayList<>(Arrays.asList("login")); - - private BlockingQueue logQueue = new LinkedBlockingDeque<>(); - -// @Pointcut(value = "execution(* com.njcn.gather..controller.*.*(..)) && !execution(* com.njcn.gather..controller.AuthController.*(..))") - @Pointcut(value = "execution(* com.njcn.gather..controller.*.*(..))") - public void logPointcut() { - } - - @Around("logPointcut()") - public Object around(ProceedingJoinPoint joinPoint) throws Throwable { - String name = joinPoint.getSignature().getName(); - String username = ""; - // 因为刚开始登录时无法获取到token,针对login方法单独处理 - if (IGNORE_METHOD.contains(name)) { - Object[] args = joinPoint.getArgs(); - Object arg = args[0]; - if (arg instanceof SysUserParam.LoginParam) { - username = ((SysUserParam.LoginParam) arg).getUsername(); - } - } else { - String userId = RequestUtil.getUserId(); - if (StrUtil.isNotBlank(userId)) { - SysUser user = sysUserService.getById(RequestUtil.getUserId()); - if (ObjectUtil.isNotNull(user)) { - username = user.getName(); - } - } - } - - Object result = null; - try { - sysLogAuditService.scheduleRemoveLog(); - result = joinPoint.proceed(); - if (result instanceof HttpResult) { - HttpResult result1 = (HttpResult) result; - if (CommonResponseEnum.SUCCESS.getCode().equals(result1.getCode())) { - addLogToQueue(joinPoint, "".equals(username) ? UserConstant.UNKNOWN_USER_ID : username, LogOperationTypeEnum.OPERATE.getMsg(), 1, LogLevelEnum.INFO.getCode(), 0); - } else { - addLogToQueue(joinPoint, "".equals(username) ? UserConstant.UNKNOWN_USER_ID : username, LogOperationTypeEnum.OPERATE.getMsg(), 0, LogLevelEnum.INFO.getCode(), 0); - } - } else { - addLogToQueue(joinPoint, "".equals(username) ? UserConstant.UNKNOWN_USER_ID : username, LogOperationTypeEnum.OPERATE.getMsg(), 1, LogLevelEnum.INFO.getCode(), 0); - } - } catch (Throwable e) { - addLogToQueue(joinPoint, "".equals(username) ? UserConstant.UNKNOWN_USER_ID : username, LogOperationTypeEnum.OPERATE.getMsg(), 0, LogLevelEnum.ERROR.getCode(), 1); - throw e; - } - return result; - } - - private void addLogToQueue(ProceedingJoinPoint joinPoint, String username, String operationType, Integer result, Integer level, Integer warn) { - SysLogAudit sysLogAudit = new SysLogAudit(); - sysLogAudit.setOperateType(operationType); - sysLogAudit.setLevel(level); - sysLogAudit.setWarn(warn); //0-未告警,1-告警 - sysLogAudit.setCreateBy(username); - - sysLogAudit.setIp(RequestUtil.getUserIp()); - - MethodSignature signature = (MethodSignature) joinPoint.getSignature(); - Method method = signature.getMethod(); - OperateInfo operateInfo = method.getAnnotation(OperateInfo.class); - ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); - String resultStr = (result == 1 ? "成功" : "失败"); - if (operateInfo != null) { - //注解上的操作类型 - sysLogAudit.setResult(operateInfo.operateType() + resultStr); - } - if (apiOperation != null) { - //注解上的描述 - String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - sysLogAudit.setRemark(username + ":" + now + " " + apiOperation.value() + " " + resultStr); - } - //Object[] args = joinPoint.getArgs(); - logQueue.add(sysLogAudit); - } - - @Override - public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { - new Thread(new Runnable() { - @Override - public void run() { - while (true) { - try { - List logList = new ArrayList<>(); - SysLogAudit log; - while ((log = logQueue.poll(5, TimeUnit.MILLISECONDS)) != null) { - log.setSort(sysLogAuditService.getMaxSort() + 1); - logList.add(log); - } - if (!logList.isEmpty()) { - sysLogAuditService.saveBatch(logList); // 假设有一个批量保存的方法 - } - } catch (Exception e) { - throw new BusinessException(SystemResponseEnum.LOG_RECORD_FAILED); - } - } - } - }).start(); - } -} diff --git a/system/src/main/java/com/njcn/gather/system/log/pojo/po/SysLogAudit.java b/system/src/main/java/com/njcn/gather/system/log/pojo/po/SysLogAudit.java index 8f757ead..02367376 100644 --- a/system/src/main/java/com/njcn/gather/system/log/pojo/po/SysLogAudit.java +++ b/system/src/main/java/com/njcn/gather/system/log/pojo/po/SysLogAudit.java @@ -28,9 +28,16 @@ public class SysLogAudit implements Serializable { private String id; /** - * 操作类型 + * 登录名 */ - private String operateType; + private String loginName; + + + /** + * 用户名 + */ + private String userName; + /** * IP @@ -38,14 +45,31 @@ public class SysLogAudit implements Serializable { private String ip; /** - * 事件结果 + * 操作内容 + */ + private String operate; + + + /** + * 操作类型 (比如:查询、新增、删除、下载等等) + */ + private String operateType; + + /** + * 事件结果 0失败 1成功 */ private String result; /** - * 事件描述 + * 失败原因 */ - private String remark; + private String reason; + + /** + * 事件类型 + */ + private Integer type; + /** * 事件严重度(0.普通 1.中等 2.严重) @@ -57,25 +81,14 @@ public class SysLogAudit implements Serializable { */ private Integer warn; - /** - * 创建用户 - */ - @TableField(fill = FieldFill.INSERT) - private String createBy; /** - * 排序 - */ - - private Integer sort; - - /** - * 创建时间 + * 日志发生事件 */ @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonSerialize(using = LocalDateTimeSerializer.class) - private LocalDateTime createTime; + private LocalDateTime logTime; } diff --git a/system/src/main/java/com/njcn/gather/system/log/service/ISysLogAuditService.java b/system/src/main/java/com/njcn/gather/system/log/service/ISysLogAuditService.java index 0174a726..0a0619f4 100644 --- a/system/src/main/java/com/njcn/gather/system/log/service/ISysLogAuditService.java +++ b/system/src/main/java/com/njcn/gather/system/log/service/ISysLogAuditService.java @@ -2,8 +2,15 @@ package com.njcn.gather.system.log.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import com.njcn.common.pojo.exception.BusinessException; +import com.njcn.common.pojo.response.HttpResult; import com.njcn.gather.system.log.pojo.param.SysLogParam; import com.njcn.gather.system.log.pojo.po.SysLogAudit; +import com.njcn.gather.system.log.pojo.vo.SysLogVO; +import io.swagger.models.auth.In; +import org.aspectj.lang.JoinPoint; +import org.springframework.core.MethodParameter; +import org.springframework.http.server.ServerHttpRequest; /** * @author caozehui @@ -26,22 +33,20 @@ public interface ISysLogAuditService extends IService { */ void exportCSV(SysLogParam.QueryParam param); - /** - * 获取最大的排序值 - * - * @return - */ - Integer getMaxSort(); - - /** - * 按照 一定规则 清除日志 - */ - void scheduleRemoveLog(); - /** * 分析日志 * * @param param */ void analyse(SysLogParam.QueryParam param); + + void recodeAdviceLog(MethodParameter returnType, HttpResult httpResult, String methodDescribe); + + /** + * 全局异常拦截器的捕获的异常进行日志记录入库 + * + * @param businessException 异常 + * @param message 异常描述 + */ + void recodeBusinessExceptionLog(Exception businessException, String message); } diff --git a/system/src/main/java/com/njcn/gather/system/log/service/impl/SysLogAuditServiceImpl.java b/system/src/main/java/com/njcn/gather/system/log/service/impl/SysLogAuditServiceImpl.java index af8f6801..0ae2af11 100644 --- a/system/src/main/java/com/njcn/gather/system/log/service/impl/SysLogAuditServiceImpl.java +++ b/system/src/main/java/com/njcn/gather/system/log/service/impl/SysLogAuditServiceImpl.java @@ -6,31 +6,41 @@ import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.njcn.common.pojo.constant.LogInfo; +import com.njcn.common.pojo.enums.response.CommonResponseEnum; +import com.njcn.common.pojo.response.HttpResult; +import com.njcn.common.utils.PubUtils; +import com.njcn.db.mybatisplus.constant.UserConstant; import com.njcn.gather.system.log.mapper.SysLogAuditMapper; import com.njcn.gather.system.log.pojo.enums.LogLevelEnum; import com.njcn.gather.system.log.pojo.param.SysLogParam; import com.njcn.gather.system.log.pojo.po.SysLogAudit; import com.njcn.gather.system.log.service.ISysLogAuditService; import com.njcn.gather.system.log.util.CSVUtil; +import com.njcn.gather.user.user.pojo.po.SysUser; +import com.njcn.gather.user.user.service.ISysUserService; import com.njcn.web.factory.PageFactory; import com.njcn.web.utils.HttpServletUtil; +import com.njcn.web.utils.ReflectCommonUtil; +import com.njcn.web.utils.RequestUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer; +import org.springframework.core.MethodParameter; +import org.springframework.http.server.ServerHttpRequest; import org.springframework.stereotype.Service; +import org.springframework.web.bind.MethodArgumentNotValidException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.lang.reflect.Method; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.time.LocalDateTime; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -42,6 +52,8 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class SysLogAuditServiceImpl extends ServiceImpl implements ISysLogAuditService { + private final ISysUserService sysUserService; + @Override public Page listSysLogAudit(SysLogParam.QueryParam param) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -57,55 +69,41 @@ public class SysLogAuditServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); - if (ObjectUtil.isNotNull(param)) { - queryWrapper - .eq(StrUtil.isNotBlank(param.getOperateType()), "sys_log_audit.Operate_Type", param.getOperateType()) - .eq(StrUtil.isNotBlank(param.getCreateBy()), "sys_log_audit.Create_By", param.getCreateBy()) - .between(StrUtil.isAllNotBlank(param.getSearchBeginTime(), param.getSearchEndTime()), "sys_log_audit.Create_Time", param.getSearchBeginTime(), param.getSearchEndTime()); - } - queryWrapper.orderByDesc("sys_log_audit.Create_Time"); - List list = this.list(queryWrapper); - List> data = list.stream().map(item -> { - Map map = new HashMap<>(); - map.put("operateType", item.getOperateType()); - map.put("ip", item.getIp()); - map.put("result", item.getResult()); - map.put("remark", item.getRemark()); - map.put("level", LogLevelEnum.getEnum(item.getLevel()).getMsg()); - map.put("warn", item.getWarn() == 0 ? "未告警" : "告警"); - map.put("createBy", item.getCreateBy()); - //将 createTime 转换为 yyyy-MM-dd HH:mm:ss 格式 - map.put("createTime", item.getCreateTime() == null ? "" : item.getCreateTime().toString().replace("T", " ")); - return map; - }).collect(Collectors.toList()); - SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); - CSVUtil.export("日志数据" + sdf.format(new Date()) + ".csv", titles, keys, data); - } - - @Override - public Integer getMaxSort() { - SysLogAudit log = this.lambdaQuery().orderByDesc(SysLogAudit::getSort).last("limit 1").one(); - if (ObjectUtil.isNotNull(log)) { - return log.getSort(); - } - return 0; - } - - @Override - public void scheduleRemoveLog() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lt("Create_Time", LocalDateTime.now().minusDays(30 * 6)); - int count = this.count(); - if (count > 1e6) { - wrapper.or().orderByAsc("Create_Time").last("limit " + (count - 1e6)); - } - this.remove(wrapper); +// String[] titles = {"日志类型", "IP", "事件结果", "描述", "日志等级", "告警标准", "操作用户", "记录时间"}; +// String[] keys = {"operateType", "ip", "result", "remark", "level", "warn", "createBy", "createTime"}; +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// if (ObjectUtil.isNotNull(param)) { +// queryWrapper +// .eq(StrUtil.isNotBlank(param.getOperateType()), "sys_log_audit.Operate_Type", param.getOperateType()) +// .eq(StrUtil.isNotBlank(param.getCreateBy()), "sys_log_audit.Create_By", param.getCreateBy()) +// .between(StrUtil.isAllNotBlank(param.getSearchBeginTime(), param.getSearchEndTime()), "sys_log_audit.Create_Time", param.getSearchBeginTime(), param.getSearchEndTime()); +// } +// queryWrapper.orderByDesc("sys_log_audit.Create_Time"); +// List list = this.list(queryWrapper); +// List> data = list.stream().map(item -> { +// Map map = new HashMap<>(); +// map.put("operateType", item.getOperateType()); +// map.put("ip", item.getIp()); +// map.put("result", item.getResult()); +// map.put("remark", item.getRemark()); +// map.put("level", LogLevelEnum.getEnum(item.getLevel()).getMsg()); +// map.put("warn", item.getWarn() == 0 ? "未告警" : "告警"); +// map.put("createBy", item.getCreateBy()); +// //将 createTime 转换为 yyyy-MM-dd HH:mm:ss 格式 +// map.put("createTime", item.getCreateTime() == null ? "" : item.getCreateTime().toString().replace("T", " ")); +// return map; +// }).collect(Collectors.toList()); +// SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); +// CSVUtil.export("日志数据" + sdf.format(new Date()) + ".csv", titles, keys, data); } + /** + * 暂时废弃,有需要再重新写 + * + * @param param . + */ @Override + @Deprecated public void analyse(SysLogParam.QueryParam param) { QueryWrapper queryWrapper = new QueryWrapper<>(); if (ObjectUtil.isNotNull(param)) { @@ -114,11 +112,113 @@ public class SysLogAuditServiceImpl extends ServiceImpl list = this.list(queryWrapper); - Map collect = list.stream().collect(Collectors.groupingBy(SysLogAudit::getCreateBy, Collectors.counting())); + Map collect = list.stream().collect(Collectors.groupingBy(SysLogAudit::getLoginName, Collectors.counting())); this.exportAnalyseExcel("分析结果", collect); } + /** + * 记录controller全局拦截的日志,并非全局异常捕获的 + * + * @param returnType 返回类型 + * @param httpResult 返回结果 + * @param methodDescribe 方法描述 + */ + @Override + public void recodeAdviceLog(MethodParameter returnType, HttpResult httpResult, String methodDescribe) { + SysLogAudit sysLogAudit = new SysLogAudit(); + String userId = RequestUtil.getUserId(); + if (StrUtil.isBlank(userId)) { + String loginName = RequestUtil.getLoginName(); + if (loginName.equalsIgnoreCase(LogInfo.UNKNOWN_USER)) { + sysLogAudit.setUserName(UserConstant.UN_LOGIN); + sysLogAudit.setLoginName(UserConstant.UN_LOGIN); + } else { + sysLogAudit.setUserName(loginName); + sysLogAudit.setLoginName(loginName); + } + } else { + SysUser sysUser = sysUserService.getById(userId); + if (sysUser != null) { + sysLogAudit.setUserName(sysUser.getName()); + sysLogAudit.setLoginName(sysUser.getLoginName()); + } else { + sysLogAudit.setUserName(UserConstant.UN_LOGIN); + sysLogAudit.setLoginName(UserConstant.UN_LOGIN); + } + } + // 不是很重要,本地部署的,除非以后工具类C端有必要,到时候再丰富读IP的过程 + sysLogAudit.setIp(RequestUtil.getUserIp()); + // 操作内容 + sysLogAudit.setOperate(methodDescribe); + // 操作结果 + String result = httpResult.getCode().equalsIgnoreCase(CommonResponseEnum.FAIL.getCode()) ? CommonResponseEnum.FAIL.getMessage() : CommonResponseEnum.SUCCESS.getMessage(); + sysLogAudit.setResult(result); + // 事件类型 + String type = ReflectCommonUtil.getOperateInfoByMethod(returnType.getMethod()).getOperateType(); + sysLogAudit.setType(type.equalsIgnoreCase("业务事件") ? 0 : 1); + // 等级 + String level = ReflectCommonUtil.getOperateInfoByMethod(returnType.getMethod()).getOperateLevel(); + sysLogAudit.setLevel(levelStringToNumber(level)); + // 中等以上的需要置为未告警,但是告警功能暂未做 + if(sysLogAudit.getLevel() == 0){ + sysLogAudit.setWarn(1); + }else{ + sysLogAudit.setWarn(0); + } + // 操作类型 + String operateType = ReflectCommonUtil.getOperateTypeByMethod(returnType.getMethod()); + sysLogAudit.setOperateType(operateType); + sysLogAudit.setLogTime(LocalDateTime.now()); + this.save(sysLogAudit); + } + + @Override + public void recodeBusinessExceptionLog(Exception exception, String message) { + SysLogAudit sysLogAudit = new SysLogAudit(); + String userId = RequestUtil.getUserId(); + if (StrUtil.isBlank(userId)) { + String loginName = RequestUtil.getLoginName(); + if (loginName.equalsIgnoreCase(LogInfo.UNKNOWN_USER)) { + sysLogAudit.setUserName(UserConstant.UN_LOGIN); + sysLogAudit.setLoginName(UserConstant.UN_LOGIN); + } else { + sysLogAudit.setUserName(loginName); + sysLogAudit.setLoginName(loginName); + } + } else { + SysUser sysUser = sysUserService.getById(userId); + if (sysUser != null) { + sysLogAudit.setUserName(sysUser.getName()); + sysLogAudit.setLoginName(sysUser.getLoginName()); + } else { + sysLogAudit.setUserName(UserConstant.UN_LOGIN); + sysLogAudit.setLoginName(UserConstant.UN_LOGIN); + } + } + //根据异常获取method方法 + Method method = ReflectCommonUtil.getMethod(exception); + if (exception instanceof MethodArgumentNotValidException) { + MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) exception; + method = methodArgumentNotValidException.getParameter().getMethod(); + } + // 不是很重要,本地部署的,除非以后工具类C端有必要,到时候再丰富读IP的过程 + sysLogAudit.setIp(RequestUtil.getUserIp()); + sysLogAudit.setReason(message); + String result = CommonResponseEnum.FAIL.getMessage(); + sysLogAudit.setResult(result); + String methodDescribe = ReflectCommonUtil.getMethodDescribeByMethod(method); + sysLogAudit.setOperate(methodDescribe); + String type = ReflectCommonUtil.getOperateInfoByMethod(method).getOperateType(); + sysLogAudit.setType(type.equalsIgnoreCase("业务事件") ? 0 : 1); + String level = ReflectCommonUtil.getOperateInfoByMethod(method).getOperateLevel(); + sysLogAudit.setLevel(levelStringToNumber(level)); + String operateType = ReflectCommonUtil.getOperateTypeByMethod(method); + sysLogAudit.setOperateType(operateType); + sysLogAudit.setLogTime(LocalDateTime.now()); + this.save(sysLogAudit); + } + private void exportAnalyseExcel(String fileName, Map collect) { HttpServletResponse response = HttpServletUtil.getResponse(); XSSFWorkbook wb = new XSSFWorkbook(); @@ -140,95 +240,19 @@ public class SysLogAuditServiceImpl extends ServiceImpl categoryList, List sheetDataList) { -// int row1 = 0; -// int row2 = 8; -// int col1 = 0; -// int col2 = 30; -// // 设置图表列宽 -// for (int i = 0; i < row2; i++) { -// sheet.setColumnWidth(i, 6000); -// } -// //y轴显示数据 -// String[] headArray = categoryList.stream().collect(Collectors.toList()).toArray(new String[]{}); -// -// // Create a chart -// XSSFDrawing drawing = sheet.createDrawingPatriarch(); -// ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, col1, row1, row2, col2); -// XSSFChart chart = drawing.createChart(anchor); -// //标题是否覆盖图表 -// chart.setTitleOverlay(false); -// //设置图表标题 -// chart.setTitleText("分析结果"); -// // 创建图表系列 -// XDDFChartLegend legend = chart.getOrAddLegend(); -// legend.setPosition(LegendPosition.TOP); -// -// //动态数据 -// //x轴数据 -// XDDFDataSource xData = XDDFDataSourcesFactory.fromArray(headArray); -// //饼图数据 -// XDDFPieChartData data = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null); -// data.setVaryColors(true); -// -// Double[] yArray = sheetDataList.stream().collect(Collectors.toList()).toArray(new Double[]{}); -// //y轴数据 -// XDDFNumericalDataSource yData = XDDFDataSourcesFactory.fromArray(yArray); -// XDDFChartData.Series series = data.addSeries(xData, yData); -// -// //series.setTitle("title", null); -// series.setShowLeaderLines(true); -// // 隐藏图例标识、系列名称、分类名称和数值 -// XDDFPieChartData.Series s = (XDDFPieChartData.Series) series; -// CTPieSer ctPieSer = s.getCTPieSer(); -// showCateName(ctPieSer, false); -// showVal(ctPieSer, false); -// showLegendKey(ctPieSer, false); -// showSerName(ctPieSer, false); -// -// chart.plot(data); -// } - // 控制值系列名称是否显示 - private void showSerName(CTPieSer series, boolean val) { - if (series.getDLbls().isSetShowSerName()) { - series.getDLbls().getShowSerName().setVal(val); - } else { - series.getDLbls().addNewShowSerName().setVal(val); - } - } - // 控制分类名称是否显示 - private void showCateName(CTPieSer series, boolean val) { - if (series.getDLbls().isSetShowCatName()) { - series.getDLbls().getShowCatName().setVal(val); - } else { - series.getDLbls().addNewShowCatName().setVal(val); - } - } - - // 控制值是否显示 - private void showVal(CTPieSer series, boolean val) { - if (series.getDLbls().isSetShowVal()) { - series.getDLbls().getShowVal().setVal(val); - } else { - series.getDLbls().addNewShowVal().setVal(val); - } - } - - // 控制图例标识是否显示 - private void showLegendKey(CTPieSer series, boolean val) { - if (series.getDLbls().isSetShowLegendKey()) { - series.getDLbls().getShowLegendKey().setVal(val); - } else { - series.getDLbls().addNewShowLegendKey().setVal(val); + /** + * 严重度 文字 转 数字 + */ + private Integer levelStringToNumber(String level) { + switch (level) { + case "中等": + return 1; + case "严重": + return 2; + default: + return 0; } } } diff --git a/user/pom.xml b/user/pom.xml index e105249c..2503f30e 100644 --- a/user/pom.xml +++ b/user/pom.xml @@ -37,6 +37,7 @@ 1.2.83 + \ No newline at end of file diff --git a/user/src/main/java/com/njcn/gather/user/user/controller/AuthController.java b/user/src/main/java/com/njcn/gather/user/user/controller/AuthController.java index 3ff7ac47..2b1d08f4 100644 --- a/user/src/main/java/com/njcn/gather/user/user/controller/AuthController.java +++ b/user/src/main/java/com/njcn/gather/user/user/controller/AuthController.java @@ -30,6 +30,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; import java.security.KeyPair; import java.util.Base64; import java.util.HashMap; @@ -53,7 +54,7 @@ public class AuthController extends BaseController { @OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.AUTHENTICATE) @PostMapping("/login") @ApiOperation("登录") - public HttpResult login(@RequestBody SysUserParam.LoginParam param) { + public HttpResult login(@RequestBody SysUserParam.LoginParam param, HttpServletRequest request) { String methodDescribe = getMethodDescribe("login"); LogUtil.njcnDebug(log, "{},登录参数为:{}", methodDescribe, param); byte[] decode = Base64.getDecoder().decode(param.getUsername()); @@ -73,7 +74,8 @@ public class AuthController extends BaseController { } catch (Exception e) { throw new BusinessException(UserResponseEnum.RSA_DECRYT_ERROR); } - + // 因不确定是否能登陆成功先将登陆名保存到request,一遍记录谁执行了登录操作 + request.setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, username); SysUser user = sysUserService.getUserByLoginNameAndPassword(username, password); if (ObjectUtil.isNull(user)) { return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.FAIL, null, UserValidMessage.LOGIN_FAILED); @@ -112,9 +114,9 @@ public class AuthController extends BaseController { } @OperateInfo(info = LogEnum.SYSTEM_COMMON) - @ApiOperation("刷新token") + @ApiOperation("刷新accessToken") @GetMapping("/refreshToken") - public HttpResult refreshToken() { + public HttpResult refreshToken(HttpServletRequest request) { String methodDescribe = getMethodDescribe("refreshToken"); LogUtil.njcnDebug(log, "{},刷新token", methodDescribe); String accessToken = RequestUtil.getAccessToken(); @@ -125,7 +127,7 @@ public class AuthController extends BaseController { String userId = (String) map.get(SecurityConstants.USER_ID); SysUser user = sysUserService.getById(userId); String accessTokenNew = JwtUtil.getAccessToken(userId); - + request.setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, user.getLoginName()); //String refreshTokenNew = JwtUtil.getRefreshToken(accessTokenNew); token.setAccessToken(accessTokenNew); @@ -141,9 +143,11 @@ public class AuthController extends BaseController { @OperateInfo(info = LogEnum.SYSTEM_COMMON) @ApiOperation("获取RSA公钥") @GetMapping("/getPublicKey") - public HttpResult publicKey(@RequestParam("username") String username, @RequestParam("checked") Boolean checked) throws Exception { + public HttpResult publicKey(@RequestParam("username") String username, @RequestParam("checked") Boolean checked, HttpServletRequest request) throws Exception { String methodDescribe = getMethodDescribe("publicKey"); LogUtil.njcnDebug(log, "{},获取RSA公钥", methodDescribe); + // 因不确定是否能登陆成功先将登陆名保存到request,一遍记录谁执行了登录操作 + request.setAttribute(SecurityConstants.AUTHENTICATE_USERNAME, username); keyPair = RSAUtil.generateKeyPair(); if (checked) { Map map = new HashMap();