浙江报告与日志功能
This commit is contained in:
@@ -74,6 +74,29 @@
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.docx4j/docx4j -->
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j</artifactId>
|
||||
<version>3.3.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.12.0</version> <!-- 您可以根据需要选择其他版本 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>2.12.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public class DetectionData {
|
||||
private Double num;
|
||||
|
||||
/**
|
||||
* 是否是符合数据(1.合格 2.不合格 3.网络超时 4.无法处理 5.不参与误差比较)
|
||||
* 1.合格 2.不合格 3.网络超时 4.无法处理 5.不参与误差比较
|
||||
*/
|
||||
private Integer isData;
|
||||
|
||||
|
||||
@@ -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<PqDevMapper, PqDev> implements
|
||||
private final IDevTypeService devTypeService;
|
||||
private final ISysTestConfigService sysTestConfigService;
|
||||
private final IDictTypeService dictTypeService;
|
||||
private final ISysUserService userService;
|
||||
|
||||
@Override
|
||||
public Page<PqDevVO> listPqDevs(PqDevParam.QueryParam queryParam) {
|
||||
@@ -390,6 +392,7 @@ public class PqDevServiceImpl extends ServiceImpl<PqDevMapper, PqDev> implements
|
||||
return CheckStateEnum.UNCHECKED.getValue();
|
||||
}
|
||||
|
||||
//
|
||||
// @Override
|
||||
// public List getPieData(String planId) {
|
||||
// List<PqDev> pqDevList = this.lambdaQuery().eq(PqDev::getPlanId, planId).eq(PqDev::getState, DataStateEnum.ENABLE.getCode()).list();
|
||||
@@ -411,6 +414,9 @@ public class PqDevServiceImpl extends ServiceImpl<PqDevMapper, PqDev> 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);
|
||||
|
||||
|
||||
@@ -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<String> THREE_PHASE = Arrays.asList("V", "HV", "HI", "HP", "HSV", "HSI", "I", "P", "F");
|
||||
|
||||
/**
|
||||
* T相指标
|
||||
*/
|
||||
List<String> T_PHASE = Arrays.asList("VOLTAGE", "IMBV", "IMBA");
|
||||
|
||||
|
||||
/**
|
||||
* 有次数的指标
|
||||
*/
|
||||
List<String> TIME = Arrays.asList("HV", "HI", "HP", "HSV", "HSI");
|
||||
|
||||
/**
|
||||
* 没有次数的指标
|
||||
*/
|
||||
List<String> NO_TIME = Arrays.asList("V", "I", "P", "VOLTAGE", "IMBV", "IMBA", "F");
|
||||
|
||||
/**
|
||||
* 有数据范围
|
||||
*/
|
||||
List<Integer> 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";
|
||||
|
||||
}
|
||||
@@ -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 = "#{";
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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<String, List<Map<String, List<Map<String, String>>>>> detail;
|
||||
|
||||
}
|
||||
@@ -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<Bookmark>{
|
||||
|
||||
/**
|
||||
* 在文档中段落的索引
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -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<PqReportMapper, PqReport> 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<PqReportMapper, PqReport> 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<String, String> 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<PqReportMapper, PqReport> 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<String, String> 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<Object> baseContent = baseDocumentPart.getContent();
|
||||
List<Bookmark> 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<String/*指标名称*/, List<Boolean/*以回路的顺序填充结果*/>> 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<String, List<Boolean>> resultMap, DocAnchorEnum docAnchorEnum) {
|
||||
// 先判断数据有没有,如果没有,则不处理
|
||||
if (CollUtil.isEmpty(resultMap.get(PowerIndexEnum.UNKNOWN.getKey()))) {
|
||||
List<Object> 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<List<Boolean>> tempResultList = new ArrayList<>(resultMap.values());
|
||||
int lineNum = tempResultList.get(0).size();
|
||||
// 处理表头
|
||||
List<String> 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<String> cellValues = new ArrayList<>();
|
||||
PowerIndexEnum indexEnum = PowerIndexEnum.getByKey(key);
|
||||
if (indexEnum != null) {
|
||||
cellValues.add(indexEnum.getDesc().concat("测量准确度"));
|
||||
} else {
|
||||
cellValues.add(PowerIndexEnum.UNKNOWN.getDesc().concat("测量准确度"));
|
||||
}
|
||||
// 判断是否有不合格的
|
||||
List<Boolean> 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<String, List<Boolean>> resultMap) {
|
||||
// 源文档的内容
|
||||
List<Object> paragraphs = baseModelDocument.getContent();
|
||||
// 以回路维度处理数据项
|
||||
Integer devChns = pqDevVO.getDevChns();
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
// 读取该计划的检测大项组装数据内容
|
||||
List<PqScriptDtlDataVO> pqScriptDtlsList = pqScriptDtlsService.getScriptDtlsDataList(devReportParam.getScriptId());
|
||||
Map<String, List<PqScriptDtlDataVO>> scriptMap = pqScriptDtlsList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptCode));
|
||||
List<Object> allContent = detailModelDocument.getContent();
|
||||
List<Docx4jUtil.HeadingContent> headingContents = Docx4jUtil.extractHeading5Contents(allContent);
|
||||
Map<String, List<Docx4jUtil.HeadingContent>> 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<Map.Entry<String, List<PqScriptDtlDataVO>>> iterator = scriptMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, List<PqScriptDtlDataVO>> next = iterator.next();
|
||||
String scriptCode = next.getKey();
|
||||
List<PqScriptDtlDataVO> checkckItemList = next.getValue();
|
||||
List<Docx4jUtil.HeadingContent> tempContent = contentMap.get(scriptCode);
|
||||
// 获取需要填充keys,索引0对应的段落key,索引1对应的表格key
|
||||
List<List<String>> keys = Docx4jUtil.getFillKeys(tempContent);
|
||||
// 段落keys值赋值
|
||||
List<String> pKeys = keys.get(0);
|
||||
Map<String, String> pKeyValueMap = resultService.getParagraphKeysValue(scriptCode, pKeys);
|
||||
List<String> tableKeys = keys.get(1);
|
||||
/* tableKeys值赋值,注:由于谐波类检测数据与非谐波检测类数据的区别,此处要做区分
|
||||
* 1、谐波类每个scriptIndex对应一个Excel表格
|
||||
* 2、非谐波类则是一个误差范围对应一个Excel表格
|
||||
*/
|
||||
SingleTestResult singleTestResult = null;
|
||||
// 根据code找到名称
|
||||
List<Boolean> 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<Integer, List<PqScriptDtlDataVO>> scriptIndexMap = checkckItemList.stream().collect(Collectors.groupingBy(PqScriptDtlDataVO::getScriptIndex));
|
||||
for (List<PqScriptDtlDataVO> 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<String, List<Map<String, List<Map<String, String>>>>> finalContent, int position, List<Docx4jUtil.HeadingContent> tempContent,
|
||||
ObjectFactory factory, Map<String, String> pKeyValueMap, List<String> tableKeys, List<Object> paragraphs) {
|
||||
if (CollUtil.isNotEmpty(finalContent)) {
|
||||
Iterator<Map.Entry<String, List<Map<String, List<Map<String, String>>>>>> iterator1 = finalContent.entrySet().iterator();
|
||||
while (iterator1.hasNext()) {
|
||||
Map.Entry<String, List<Map<String, List<Map<String, String>>>>> next1 = iterator1.next();
|
||||
// 此处的key是影响量的文字描述
|
||||
String key = next1.getKey();
|
||||
List<Map<String, List<Map<String, String>>>> value = next1.getValue();
|
||||
for (Map<String, List<Map<String, String>>> stringListMap : value) {
|
||||
Iterator<Map.Entry<String, List<Map<String, String>>>> iterator2 = stringListMap.entrySet().iterator();
|
||||
while (iterator2.hasNext()) {
|
||||
Map.Entry<String, List<Map<String, String>>> next2 = iterator2.next();
|
||||
// 此处的key是误差范围
|
||||
String key1 = next2.getKey();
|
||||
List<Map<String, String>> 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<Tbl> temp = (JAXBElement<Tbl>) object;
|
||||
JAXBElement<Tbl> copiedTableElement;
|
||||
try {
|
||||
copiedTableElement = Docx4jUtil.deepCopyTbl(temp);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// 解析表格并插入对应数据,最关键的是得知道表格是横向还是纵向以及表头占了几行
|
||||
Tbl tbl = copiedTableElement.getValue();
|
||||
// 获取表格的行
|
||||
List<Object> 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<Tc> element = (JAXBElement<Tc>) existingRow.getContent().get(0);
|
||||
TcPr tcPr = element.getValue().getTcPr();
|
||||
tbl.getContent().remove(existingRow);
|
||||
// 迭代增加行,需要填充的表格keys在tableKeys集合中
|
||||
for (Map<String, String> 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<AdPlan> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
@@ -656,62 +1035,55 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理基础模版中的信息,非数据页报告
|
||||
*
|
||||
* @param baseModelDocument 模板文件
|
||||
* 此处为什么要抽出拼接的前缀&后缀,是因为Docx4j工具包替换时会默认增加${},故在使用docx4j时前后缀必须为空
|
||||
*/
|
||||
private void dealBaseModel(XWPFDocument baseModelDocument, PqDevVO pqDevVO, DevType devType) {
|
||||
private Map<String, String> dealBaseModelData(PqDevVO pqDevVO, DevType devType, String prefix, String suffix) {
|
||||
// 首先获取非数据页中需要的信息
|
||||
Map<String, String> baseModelMap = new HashMap<>(16);
|
||||
Map<String, String> 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取数据页的信息
|
||||
*
|
||||
|
||||
@@ -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<Object> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<HeadingContent> extractHeading5Contents(List<Object> allContent) {
|
||||
List<HeadingContent> 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<Object> content = row.getContent();
|
||||
// 取最后一个单元格,判断是否包含汉字,有汉字就是横向的
|
||||
Object cellObject = content.get(content.size() - 1);
|
||||
JAXBElement<Tc> cellElement = (JAXBElement<Tc>) 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<Object> 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<Object> 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<String> getTableKey(Tr row) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
// 横向的,最后一行为需要填充的数据后,前面的均是表头
|
||||
// 遍历获取出该row的所有key
|
||||
List<Object> content = row.getContent();
|
||||
for (Object cellObject : content) {
|
||||
if (cellObject instanceof JAXBElement) {
|
||||
JAXBElement<Tc> cellElement = (JAXBElement<Tc>) cellObject;
|
||||
Tc cell = cellElement.getValue();
|
||||
keys.add(Docx4jUtil.getTextFromCell(cell));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容中需要填充的keys
|
||||
*
|
||||
* @param tempContent 标题下配置的内容
|
||||
*/
|
||||
public static List<List<String>> getFillKeys(List<HeadingContent> tempContent) {
|
||||
List<List<String>> keys = new ArrayList<>();
|
||||
List<String> pKeys = new ArrayList<>();
|
||||
List<String> 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<Tbl> copiedTableElement = (JAXBElement<Tbl>) object;
|
||||
// 解析表格并插入对应数据,最关键的是得知道表格是横向还是纵向以及表头占了几行
|
||||
Tbl tbl = copiedTableElement.getValue();
|
||||
// 获取表格的行
|
||||
List<Object> rows = tbl.getContent();
|
||||
boolean isRow = Docx4jUtil.judgeTableCross(rows.get(0));
|
||||
if (isRow) {
|
||||
// 获取需要填的值的key
|
||||
List<String> 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<String, String> valueMap, List<String> 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<String> 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<Tbl> deepCopyTbl(JAXBElement<Tbl> original) throws Exception {
|
||||
// 使用 docx4j 的 XmlUtils 进行深拷贝
|
||||
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
|
||||
Tbl clonedTbl = (Tbl) XmlUtils.deepCopy(original.getValue());
|
||||
|
||||
// 重新包装为 JAXBElement
|
||||
return new JAXBElement<Tbl>(
|
||||
original.getName(),
|
||||
original.getDeclaredType(),
|
||||
original.getScope(),
|
||||
clonedTbl
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 存储Heading 5及其子内容的辅助类
|
||||
public static class HeadingContent {
|
||||
private String headingText;
|
||||
private List<Object> 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<Object> getSubContent() {
|
||||
return subContent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取段落在文档中的位置
|
||||
*/
|
||||
public static int getParagraphPosition(MainDocumentPart baseDocumentPart, DocAnchorEnum docAnchorEnum) {
|
||||
List<Object> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<XWPFParagraph> paragraphs = document.getParagraphs();
|
||||
if (paragraphs != null && !paragraphs.isEmpty()) {
|
||||
for (XWPFParagraph paragraph : paragraphs) {
|
||||
if (paragraph.getText() != null && !paragraph.getText().trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查表格
|
||||
List<XWPFTable> 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<String, String> placeholders) {
|
||||
replacePlaceholdersInParagraphs(document,placeholders);
|
||||
replacePlaceholdersInTables(document,placeholders);
|
||||
}
|
||||
|
||||
|
||||
public static List<XWPFParagraph> findHeadingLevel5Paragraphs(XWPFDocument document) {
|
||||
List<XWPFParagraph> 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<IBodyElement> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<PqScriptDtlDataVO> checkDataVOList, String planCode, String devId, Integer lineNo, List<String> tableKeys);
|
||||
|
||||
/**
|
||||
* 获取段落中指定的key对应的值
|
||||
* @param itemCode 测试大项code
|
||||
* @param pKeys 待填充的值
|
||||
*/
|
||||
Map<String, String> getParagraphKeysValue(String itemCode, List<String> pKeys);
|
||||
}
|
||||
|
||||
@@ -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<PqScriptDtlDataVO> dtlDataVOList, String planCode, String devId, Integer lineNo, List<String> tableKeys) {
|
||||
SingleTestResult singleTestResult = new SingleTestResult();
|
||||
Map<String/*subType影响量,额定或某单影响量*/, List<Map<String/*误差范围*/, List<Map<String/*填充key*/, String/*实际值*/>>>>> finalContent = new HashMap<>();
|
||||
if (CollUtil.isNotEmpty(dtlDataVOList)) {
|
||||
// 首先区分测试条件
|
||||
Map<String, List<PqScriptDtlDataVO>> 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<Integer> indexList = scriptDtlDataVOList.stream().map(PqScriptDtlDataVO::getScriptIndex).distinct().collect(Collectors.toList());
|
||||
List<PqScriptCheckData> scriptCheckDataList = pqScriptCheckDataService.listCheckData(scriptId, indexList);
|
||||
List<String> 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<Double, List<PqScriptCheckData>> checkDataHarmNumMap = scriptCheckDataList.stream().collect(Collectors.groupingBy(PqScriptCheckData::getHarmNum));
|
||||
List<Map<String, String>> keyFillMapList = new ArrayList<>();
|
||||
checkDataHarmNumMap.forEach((harmNum, dtlsList) -> {
|
||||
Map<String, String> 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<String, List<Map<String, String>>> errorScoperMap = new HashMap<>();
|
||||
errorScoperMap.put(titleScope, keyFillMapList);
|
||||
List<Map<String, List<Map<String, String>>>> 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<AdNonHarmonicResult> nonHarmList = adNonHarmonicService.queryByCondition(param);
|
||||
// 三相的数据通常包含:standard、standardA、standardB、standardC、testA、testB、testC、errorA、errorB、errorC、resultA、resultB、resultC、result、errorScope
|
||||
if (CollUtil.isNotEmpty(nonHarmList)) {
|
||||
List<Map<String, String>> keyFillMapList = new ArrayList<>();
|
||||
for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) {
|
||||
Map<String, String> 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<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
|
||||
.collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey())));
|
||||
// 分组后,还需要针对标准值进行一个升序
|
||||
errorScoperMap.forEach((errorScope, maps) -> {
|
||||
PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD.getKey());
|
||||
});
|
||||
List<Map<String, List<Map<String, String>>>> 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<Map<String, String>> keyFillMapList = new ArrayList<>();
|
||||
for (Integer sort : indexList) {
|
||||
SingleNonHarmParam param = new SingleNonHarmParam(Integer.parseInt(planCode), devId, lineNo, valueTypeList, Collections.singletonList(sort));
|
||||
List<AdNonHarmonicResult> 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<String, String> 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<String, List<Map<String, String>>> 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<Map<String, List<Map<String, String>>>> errorList = new ArrayList<>();
|
||||
errorList.add(errorScoperMap);
|
||||
// 最后赋值返回
|
||||
finalContent.put(affectName, errorList);
|
||||
} else {
|
||||
// 非三相且非暂态,通常只有一个数据,所以直接赋值即可
|
||||
List<Map<String, String>> keyFillMapList = new ArrayList<>();
|
||||
SingleNonHarmParam param = new SingleNonHarmParam(Integer.parseInt(planCode), devId, lineNo, valueTypeList, indexList);
|
||||
List<AdNonHarmonicResult> nonHarmList = adNonHarmonicService.queryByCondition(param);
|
||||
if (CollUtil.isNotEmpty(nonHarmList)) {
|
||||
for (AdNonHarmonicResult adNonHarmonicResult : nonHarmList) {
|
||||
String standard = "/", test = "/", error = "/", result = "/", errorScope = "/",unit = "";
|
||||
Map<String, String> 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<String, List<Map<String, String>>> errorScoperMap = keyFillMapList.stream()
|
||||
.collect(Collectors.groupingBy(map -> map.get(ItemReportKeyEnum.ERROR_SCOPE.getKey())));
|
||||
// 分组后,还需要针对特征幅值标准值进行一个升序
|
||||
errorScoperMap.forEach((errorScope, maps) -> {
|
||||
PubUtils.sortByDoubleValue(maps, ItemReportKeyEnum.STANDARD.getKey());
|
||||
});
|
||||
List<Map<String, List<Map<String, String>>>> 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<String, List<Map<String, List<Map<String, String>>>>> finalContent) {
|
||||
List<String> 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<String> 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<String, String> getParagraphKeysValue(String itemCode, List<String> pKeys) {
|
||||
Map<String, String> 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<Integer> numbers) {
|
||||
if (CollUtil.isNotEmpty(numbers)) {
|
||||
if (numbers.size() > 1) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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<PqScriptDtls> {
|
||||
* @return
|
||||
*/
|
||||
Integer selectMaxIndex(@Param("scriptId") String scriptId);
|
||||
|
||||
List<PqScriptDtlDataVO> getScriptDtlsDataList(@Param("scriptId")String scriptId);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,5 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.script.mapper.PqScriptCheckDataMapper">
|
||||
|
||||
|
||||
</mapper>
|
||||
|
||||
|
||||
@@ -10,5 +10,21 @@
|
||||
WHERE Script_Id = #{scriptId}
|
||||
|
||||
</select>
|
||||
|
||||
<select id="getScriptDtlsDataList" resultType="com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO" >
|
||||
SELECT
|
||||
t2.CODE scriptCode,
|
||||
t2.NAME scriptName,
|
||||
t1.*
|
||||
FROM
|
||||
pq_script_dtls t1,
|
||||
sys_dict_tree t2
|
||||
WHERE
|
||||
t1.Script_Type = t2.Id
|
||||
AND t1.Script_Id = #{scriptId}
|
||||
AND t1.ENABLE = 1
|
||||
ORDER BY
|
||||
t1.Script_Index ASC,t1.HarmNum ASC
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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<PqScriptCheckData> {
|
||||
List<PqScriptCheckData> listCheckDataCode(PqScriptCheckDataParam param);
|
||||
|
||||
Double getCheckDataValue(PqScriptCheckDataParam param);
|
||||
|
||||
/**
|
||||
* 查询条件范围内的参与比较的脚本详情
|
||||
* @param scriptId 脚本id
|
||||
* @param indexList 脚本下标集合
|
||||
*/
|
||||
List<PqScriptCheckData> listCheckData(String scriptId, List<Integer> indexList);
|
||||
}
|
||||
|
||||
@@ -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<PqScriptDtls> {
|
||||
* @return
|
||||
*/
|
||||
Map<String, Object> getScriptToIcdCheckInfo(PreDetectionParam param);
|
||||
/**
|
||||
* 根据脚本id获取脚本详情数据
|
||||
* @param scriptId 脚本id
|
||||
*/
|
||||
List<PqScriptDtlDataVO> getScriptDtlsDataList(String scriptId);
|
||||
}
|
||||
|
||||
@@ -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<PqScriptCheckDataM
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PqScriptCheckData> listCheckData(String scriptId, List<Integer> indexList) {
|
||||
LambdaQueryWrapper<PqScriptCheckData> queryWrapper = new LambdaQueryWrapper<PqScriptCheckData>()
|
||||
.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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<PqScriptDtlsMapper, PqS
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PqScriptDtlDataVO> getScriptDtlsDataList(String scriptId) {
|
||||
return this.baseMapper.getScriptDtlsDataList(scriptId);
|
||||
}
|
||||
|
||||
private void unbanCheck(List<PqScriptDtlsParam.CheckData> info,
|
||||
PqScriptDtlsParam.CheckData channelListDTO,
|
||||
List<PqScriptDtlsParam.ChannelListDTO> list,
|
||||
|
||||
Reference in New Issue
Block a user