表格调整部分代码
This commit is contained in:
@@ -61,7 +61,6 @@ import com.njcn.gather.plan.service.IAdPlanSourceService;
|
||||
import com.njcn.gather.plan.service.IAdPlanStandardDevService;
|
||||
import com.njcn.gather.plan.service.IAdPlanTestConfigService;
|
||||
import com.njcn.gather.pojo.enums.DetectionResponseEnum;
|
||||
import com.njcn.gather.report.pojo.constant.ReportConstant;
|
||||
import com.njcn.gather.report.pojo.po.PqReport;
|
||||
import com.njcn.gather.report.service.IPqReportService;
|
||||
import com.njcn.gather.script.pojo.po.PqScript;
|
||||
@@ -82,6 +81,7 @@ import com.njcn.gather.system.dictionary.pojo.po.DictType;
|
||||
import com.njcn.gather.system.dictionary.service.IDictDataService;
|
||||
import com.njcn.gather.system.dictionary.service.IDictTreeService;
|
||||
import com.njcn.gather.system.dictionary.service.IDictTypeService;
|
||||
import com.njcn.gather.tools.report.model.constant.ReportConstant;
|
||||
import com.njcn.gather.type.pojo.po.DevType;
|
||||
import com.njcn.gather.type.service.IDevTypeService;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUser;
|
||||
|
||||
@@ -160,7 +160,7 @@ public class ReportController extends BaseController {
|
||||
@OperateInfo
|
||||
@PostMapping("/uploadReportToCloud")
|
||||
@ApiOperation("批量上传检测报告到云端")
|
||||
@ApiImplicitParam(name = "deviceIds", value = "被检设备ID列表,为空时上传所有已生成报告的设备", required = false)
|
||||
@ApiImplicitParam(name = "deviceIds", value = "被检设备ID列表,为空时上传所有已生成报告的设备")
|
||||
public HttpResult<Object> uploadReportToCloud(@RequestBody(required = false) List<String> deviceIds) {
|
||||
String methodDescribe = getMethodDescribe("uploadReportToCloud");
|
||||
LogUtil.njcnDebug(log, "{},设备ID列表为:{}", methodDescribe, deviceIds);
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
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 = "#{";
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -21,7 +20,6 @@ import com.njcn.common.pojo.constant.PatternRegex;
|
||||
import com.njcn.common.pojo.enums.common.DataStateEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.common.utils.images.ImageConverter;
|
||||
import com.njcn.gather.detection.handler.SocketDevResponseService;
|
||||
import com.njcn.gather.detection.pojo.constant.DetectionCommunicateConstant;
|
||||
import com.njcn.gather.detection.pojo.enums.DetectionCodeEnum;
|
||||
import com.njcn.gather.detection.pojo.enums.SourceOperateCodeEnum;
|
||||
@@ -29,10 +27,7 @@ import com.njcn.gather.detection.pojo.param.PreDetectionParam;
|
||||
import com.njcn.gather.detection.pojo.vo.DetectionData;
|
||||
import com.njcn.gather.detection.pojo.vo.SocketMsg;
|
||||
import com.njcn.gather.detection.util.socket.SocketManager;
|
||||
import com.njcn.gather.detection.util.socket.cilent.NettyClient;
|
||||
import com.njcn.gather.detection.util.socket.cilent.NettyDevClientHandler;
|
||||
import com.njcn.gather.device.mapper.PqDevMapper;
|
||||
import com.njcn.gather.device.mapper.PqDevSubMapper;
|
||||
import com.njcn.gather.device.pojo.enums.CheckStateEnum;
|
||||
import com.njcn.gather.device.pojo.enums.DevReportStateEnum;
|
||||
import com.njcn.gather.device.pojo.param.PqDevParam;
|
||||
@@ -48,20 +43,15 @@ 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.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.PqReport;
|
||||
import com.njcn.gather.report.pojo.result.SingleTestResult;
|
||||
import com.njcn.gather.report.pojo.vo.PqReportVO;
|
||||
import com.njcn.gather.report.service.IPqReportService;
|
||||
import com.njcn.gather.report.utils.BookmarkUtil;
|
||||
import com.njcn.gather.report.utils.Docx4jUtil;
|
||||
import com.njcn.gather.report.utils.WordUtil;
|
||||
import com.njcn.gather.result.service.IResultService;
|
||||
import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO;
|
||||
import com.njcn.gather.script.service.IPqScriptDtlsService;
|
||||
import com.njcn.gather.storage.pojo.param.SingleNonHarmParam;
|
||||
import com.njcn.gather.storage.pojo.po.SimAndDigHarmonicResult;
|
||||
import com.njcn.gather.storage.pojo.po.SimAndDigNonHarmonicResult;
|
||||
import com.njcn.gather.storage.service.SimAndDigHarmonicService;
|
||||
@@ -70,6 +60,12 @@ import com.njcn.gather.system.cfg.pojo.enums.SceneEnum;
|
||||
import com.njcn.gather.system.cfg.service.ISysTestConfigService;
|
||||
import com.njcn.gather.system.dictionary.pojo.po.DictData;
|
||||
import com.njcn.gather.system.dictionary.service.IDictDataService;
|
||||
import com.njcn.gather.tools.report.model.constant.ReportConstant;
|
||||
import com.njcn.gather.tools.report.service.IWordReportService;
|
||||
import com.njcn.gather.tools.report.util.BookmarkUtil;
|
||||
import com.njcn.gather.tools.report.util.Docx4jUtil;
|
||||
import com.njcn.gather.tools.report.util.DocxMergeUtil;
|
||||
import com.njcn.gather.tools.report.util.WordDocumentUtil;
|
||||
import com.njcn.gather.type.pojo.po.DevType;
|
||||
import com.njcn.gather.type.service.IDevTypeService;
|
||||
import com.njcn.http.util.RestTemplateUtil;
|
||||
@@ -80,13 +76,11 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPReply;
|
||||
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.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -94,6 +88,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import java.awt.*;
|
||||
@@ -108,14 +103,11 @@ import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author makejava
|
||||
* @author caozehui
|
||||
* @date 2025-03-19
|
||||
*/
|
||||
@Slf4j
|
||||
@@ -161,37 +153,20 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
private final IPqDevService iPqDevService;
|
||||
private final PqDevMapper pqDevMapper;
|
||||
private final IPqDevSubService iPqDevSubService;
|
||||
|
||||
private final IDictDataService dictDataService;
|
||||
|
||||
private final IAdPlanService adPlanService;
|
||||
|
||||
private final IPqScriptDtlsService pqScriptDtlsService;
|
||||
|
||||
private final SimAndDigNonHarmonicService adNonHarmonicService;
|
||||
|
||||
private final SimAndDigHarmonicService adHarmonicService;
|
||||
|
||||
private final IDevTypeService devTypeService;
|
||||
|
||||
private final IResultService resultService;
|
||||
|
||||
private final ISysTestConfigService sysTestConfigService;
|
||||
|
||||
private final SocketDevResponseService socketDevResponseService;
|
||||
private final SocketManager socketManager;
|
||||
private final IWordReportService wordReportService;
|
||||
|
||||
@Autowired
|
||||
@Resource
|
||||
private RestTemplateUtil restTemplateUtil;
|
||||
|
||||
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
||||
4, 8, 30, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(100),
|
||||
// 队列满时由主线程执行
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()
|
||||
);
|
||||
|
||||
private final long FILE_SIZE_LIMIT = 5 * 1024 * 1024;
|
||||
|
||||
@Override
|
||||
public Page<PqReportVO> list(ReportParam.QueryParam queryParam) {
|
||||
@@ -309,22 +284,23 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
/**
|
||||
* 上传文件,并设置pqReport的basePath和detailPath属性
|
||||
*
|
||||
* @param reportParam
|
||||
* @param pqReport
|
||||
* @param isAdd
|
||||
* @param reportParam 报告参数
|
||||
* @param pqReport 报告信息
|
||||
* @param isAdd 是否添加
|
||||
*/
|
||||
private void uploadFile(ReportParam reportParam, PqReport pqReport, boolean isAdd) {
|
||||
MultipartFile baseFile = reportParam.getBaseFile();
|
||||
MultipartFile detailFile = reportParam.getDetailFile();
|
||||
String newDir = templatePath + File.separator + reportParam.getName() + File.separator + reportParam.getVersion() + File.separator;
|
||||
|
||||
long FILE_SIZE_LIMIT = 5 * 1024 * 1024;
|
||||
if (isAdd) {
|
||||
if (ObjectUtil.isNotNull(baseFile) && !baseFile.isEmpty() && ObjectUtil.isNotNull(detailFile) && !detailFile.isEmpty()) {
|
||||
|
||||
String baseOriginalFilename = baseFile.getOriginalFilename();
|
||||
String detailOriginalFilename = detailFile.getOriginalFilename();
|
||||
|
||||
if (!baseOriginalFilename.endsWith(".docx") || !detailOriginalFilename.endsWith(".docx")) {
|
||||
if (!baseOriginalFilename.endsWith(ReportConstant.DOCX) || !detailOriginalFilename.endsWith(ReportConstant.DOCX)) {
|
||||
throw new BusinessException(ReportResponseEnum.FILE_SUFFIX_ERROR);
|
||||
}
|
||||
if (baseOriginalFilename.equals(detailOriginalFilename)) {
|
||||
@@ -351,7 +327,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
String baseFileOriginalFilename = "";
|
||||
if (ObjectUtil.isNotNull(baseFile) && !baseFile.isEmpty()) {
|
||||
baseFileOriginalFilename = baseFile.getOriginalFilename();
|
||||
if (!baseFileOriginalFilename.endsWith(".docx")) {
|
||||
if (!baseFileOriginalFilename.endsWith(ReportConstant.DOCX)) {
|
||||
throw new BusinessException(ReportResponseEnum.FILE_SUFFIX_ERROR);
|
||||
}
|
||||
if (baseFile.getSize() > FILE_SIZE_LIMIT) {
|
||||
@@ -362,7 +338,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
String detailFileOriginalFilename = "";
|
||||
if (ObjectUtil.isNotNull(detailFile) && !detailFile.isEmpty()) {
|
||||
detailFileOriginalFilename = detailFile.getOriginalFilename();
|
||||
if (!detailFileOriginalFilename.endsWith(".docx")) {
|
||||
if (!detailFileOriginalFilename.endsWith(ReportConstant.DOCX)) {
|
||||
throw new BusinessException(ReportResponseEnum.FILE_SUFFIX_ERROR);
|
||||
}
|
||||
if (detailFile.getSize() > FILE_SIZE_LIMIT) {
|
||||
@@ -370,17 +346,17 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
}
|
||||
}
|
||||
|
||||
if (!"".equals(baseFileOriginalFilename) && !"".equals(detailFileOriginalFilename)) {
|
||||
if (!baseFileOriginalFilename.isEmpty() && !detailFileOriginalFilename.isEmpty()) {
|
||||
if (baseFileOriginalFilename.equals(detailFileOriginalFilename)) {
|
||||
throw new BusinessException(ReportResponseEnum.FILE_NAME_SAME_ERROR);
|
||||
}
|
||||
}
|
||||
if (!"".equals(baseFileOriginalFilename)) {
|
||||
if (!baseFileOriginalFilename.isEmpty()) {
|
||||
if (baseFileOriginalFilename.equals(oldPqReport.getDetailPath().substring(oldPqReport.getDetailPath().lastIndexOf(File.separator) + 1))) {
|
||||
throw new BusinessException(ReportResponseEnum.FILE_NAME_SAME_ERROR);
|
||||
}
|
||||
}
|
||||
if (!"".equals(detailFileOriginalFilename)) {
|
||||
if (!detailFileOriginalFilename.isEmpty()) {
|
||||
if (detailFileOriginalFilename.equals(oldPqReport.getBasePath().substring(oldPqReport.getBasePath().lastIndexOf(File.separator) + 1))) {
|
||||
throw new BusinessException(ReportResponseEnum.FILE_NAME_SAME_ERROR);
|
||||
}
|
||||
@@ -422,13 +398,13 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
}
|
||||
}
|
||||
|
||||
if (!"".equals(baseFileOriginalFilename)) {
|
||||
if (!baseFileOriginalFilename.isEmpty()) {
|
||||
pqReport.setBasePath(newDir + baseFileOriginalFilename);
|
||||
Paths.get(oldPqReport.getBasePath()).toFile().delete();
|
||||
Paths.get(newDir + oldPqReport.getBasePath().substring(oldPqReport.getBasePath().lastIndexOf(File.separator) + 1)).toFile().delete();
|
||||
this.uploadFile(baseFile, pqReport.getBasePath());
|
||||
}
|
||||
if (!"".equals(detailFileOriginalFilename)) {
|
||||
if (!detailFileOriginalFilename.isEmpty()) {
|
||||
pqReport.setDetailPath(newDir + detailFileOriginalFilename);
|
||||
Paths.get(oldPqReport.getDetailPath()).toFile().delete();
|
||||
Paths.get(newDir + oldPqReport.getDetailPath().substring(oldPqReport.getDetailPath().lastIndexOf(File.separator) + 1)).toFile().delete();
|
||||
@@ -560,10 +536,11 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
@Override
|
||||
public void generateReport(DevReportParam devReportParam) {
|
||||
AdPlan plan = adPlanService.getById(devReportParam.getPlanId());
|
||||
// 0 - 模板占位符更新, 1 - 根据配置模版动态组合生产的报告
|
||||
if (plan.getAssociateReport() == 1) {
|
||||
this.generateReportByPlan(plan, devReportParam);
|
||||
} else if (plan.getAssociateReport() == 0) {
|
||||
this.generateReportByDevType(plan, devReportParam);
|
||||
this.generateReportByDevType(devReportParam);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,14 +549,13 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
* 根据设备类型生成报告
|
||||
* 注:该方法目前仅支持楼下出厂检测场景,属于模板占位符替换方式,后期可能会有调整
|
||||
*
|
||||
* @param plan 计划信息
|
||||
* @param devReportParam 被检设备信息
|
||||
*/
|
||||
private void generateReportByDevType(AdPlan plan, DevReportParam devReportParam) {
|
||||
private void generateReportByDevType(DevReportParam devReportParam) {
|
||||
devReportParam.getDevIdList().forEach(devId -> {
|
||||
devReportParam.setDevId(devId);
|
||||
// 根据设备类型找到报告模板
|
||||
PqDevVO pqDevVO = iPqDevService.getPqDevById(devReportParam.getDevId());
|
||||
PqDevVO pqDevVO = iPqDevService.getPqDevById(devId);
|
||||
devReportParam.setDevId(devId);
|
||||
if (Objects.isNull(pqDevVO)) {
|
||||
throw new BusinessException(ReportResponseEnum.DEVICE_NOT_EXIST);
|
||||
}
|
||||
@@ -595,34 +571,30 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
// 读取模板文件
|
||||
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);
|
||||
Map<String, String> baseModelDataMap = dealBaseModelData(pqDevVO, devType);
|
||||
InputStream wordFinishInputStream = wordReportService.replacePlaceholders(inputStream, baseModelDataMap);
|
||||
List<InputStream> wordFileInputStreams = new ArrayList<>();
|
||||
wordFileInputStreams.add(wordFinishInputStream);
|
||||
// 处理数据页中的信息
|
||||
dealDataModel(baseModelDocument, devReportParam, pqDevVO);
|
||||
dealDataModel(wordFileInputStreams, devReportParam, pqDevVO);
|
||||
// 合并文档
|
||||
InputStream finalWordStream = DocxMergeUtil.mergeDocuments(wordFileInputStreams);
|
||||
// 处理需要输出的目录地址 基础路径+设备类型+装置编号.docx
|
||||
// 最终文件输出的路径
|
||||
// String dirPath = reportPath.concat(File.separator).concat(devType.getName());
|
||||
String dirPath = reportPath;
|
||||
// 确保目录存在
|
||||
ensureDirectoryExists(dirPath);
|
||||
String reportFullPath = dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(".docx");
|
||||
FileOutputStream out = new FileOutputStream(reportFullPath);
|
||||
String reportFullPath = dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(ReportConstant.DOCX);
|
||||
// 4. 保存新的Word文档
|
||||
try {
|
||||
baseModelDocument.write(out);
|
||||
} catch (IOException e) {
|
||||
throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR);
|
||||
}
|
||||
out.close();
|
||||
this.updateDevAndPlanState(devReportParam.getDevId(), devReportParam.getPlanId());
|
||||
WordprocessingMLPackage wordPackage = WordprocessingMLPackage.load(finalWordStream);
|
||||
wordPackage.save(new File(reportFullPath));
|
||||
this.updateDevAndPlanState(devId, devReportParam.getPlanId());
|
||||
// 异步将有效的二维码下装到被检设备
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
sendQrToDevice(pqDevVO.getIp(), pqDevVO.getCreateId() + ".docx");
|
||||
sendQrToDevice(pqDevVO.getIp(), pqDevVO.getCreateId() + ReportConstant.DOCX);
|
||||
log.info("二维码下装成功,设备IP: {}", pqDevVO.getIp());
|
||||
} catch (Exception e) {
|
||||
log.error("二维码下装失败,设备IP: {}", pqDevVO.getIp(), e);
|
||||
@@ -643,7 +615,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
log.error(ReportResponseEnum.GENERATE_REPORT_ERROR.getMessage(), e);
|
||||
throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR);
|
||||
}
|
||||
@@ -694,7 +666,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
data.set("file", base64String);
|
||||
sendFileMsg.setData(data.toString());
|
||||
String msg = JSON.toJSONString(sendFileMsg);
|
||||
Channel channel = SocketManager.getChannelByUserId(RequestUtil.getLoginName()+ DetectionCommunicateConstant.DEV);
|
||||
Channel channel = SocketManager.getChannelByUserId(RequestUtil.getLoginName() + DetectionCommunicateConstant.DEV);
|
||||
if (Objects.isNull(channel) || !channel.isActive()) {
|
||||
// 进行源通信连接
|
||||
PreDetectionParam preDetectionParam = new PreDetectionParam();
|
||||
@@ -769,13 +741,14 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
* @param devReportParam 设备信息
|
||||
*/
|
||||
private void generateReportByPlan(AdPlan plan, DevReportParam devReportParam) {
|
||||
// 支持批量生成报告
|
||||
devReportParam.getDevIdList().forEach(devId -> {
|
||||
devReportParam.setDevId(devId);
|
||||
// 准备被检设备的基础信息
|
||||
PqDevVO pqDevVO = iPqDevService.getPqDevById(devReportParam.getDevId());
|
||||
PqDevVO pqDevVO = iPqDevService.getPqDevById(devId);
|
||||
if (Objects.isNull(pqDevVO)) {
|
||||
throw new BusinessException(ReportResponseEnum.DEVICE_NOT_EXIST);
|
||||
}
|
||||
devReportParam.setDevId(devId);
|
||||
// 获取设备型号
|
||||
DevType devType = devTypeService.getById(pqDevVO.getDevType());
|
||||
if (Objects.isNull(devType)) {
|
||||
@@ -785,24 +758,27 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
if (Objects.isNull(report)) {
|
||||
throw new BusinessException(ReportResponseEnum.REPORT_TEMPLATE_NOT_EXIST);
|
||||
}
|
||||
try {
|
||||
WordprocessingMLPackage baseModelDocument = WordprocessingMLPackage.load(new File(report.getBasePath()));
|
||||
WordprocessingMLPackage detailModelDocument = WordprocessingMLPackage.load(new File(report.getDetailPath()));
|
||||
Path basePath = Paths.get(report.getBasePath());
|
||||
Path detailPath = Paths.get(report.getDetailPath());
|
||||
try (InputStream baseInputStream = Files.newInputStream(basePath);
|
||||
InputStream detailInputStream = Files.newInputStream(detailPath)) {
|
||||
WordprocessingMLPackage detailModelDocument = WordprocessingMLPackage.load(detailInputStream);
|
||||
// 获取文档基础部分,并替换占位符
|
||||
Map<String, String> baseModelDataMap = dealBaseModelData(pqDevVO, devType);
|
||||
InputStream wordFinishInputStream = wordReportService.replacePlaceholders(baseInputStream, baseModelDataMap);
|
||||
WordprocessingMLPackage baseModelDocument = WordprocessingMLPackage.load(wordFinishInputStream);
|
||||
MainDocumentPart baseDocumentPart = baseModelDocument.getMainDocumentPart();
|
||||
Map<String, String> baseModelDataMap = dealBaseModelData(pqDevVO, devType, "", "");
|
||||
baseDocumentPart.variableReplace(baseModelDataMap);
|
||||
|
||||
// 获取数据模版页内容,根据脚本动态组装数据页内容
|
||||
MainDocumentPart detailDocumentPart = detailModelDocument.getMainDocumentPart();
|
||||
// dealDataModelScattered(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO);
|
||||
dealDataModelScatteredByBookmark(baseDocumentPart, detailDocumentPart, devReportParam, pqDevVO);
|
||||
|
||||
// 保存新的文档
|
||||
String dirPath = reportPath.concat(File.separator).concat(devType.getName());
|
||||
// 确保目录存在
|
||||
ensureDirectoryExists(dirPath);
|
||||
baseModelDocument.save(new File(dirPath.concat(File.separator).concat(pqDevVO.getCreateId()).concat(ReportConstant.DOCX)));
|
||||
|
||||
this.updateDevAndPlanState(devReportParam.getDevId(), devReportParam.getPlanId());
|
||||
this.updateDevAndPlanState(devId, devReportParam.getPlanId());
|
||||
} catch (Exception e) {
|
||||
log.error(ReportResponseEnum.GENERATE_REPORT_ERROR.getMessage(), e);
|
||||
throw new BusinessException(ReportResponseEnum.GENERATE_REPORT_ERROR);
|
||||
@@ -847,8 +823,8 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
Collections.sort(bookmarkEnums);
|
||||
// 定义个结果,以便存在结果信息的书签
|
||||
Map<String/*指标名称*/, List<Boolean/*以回路的顺序填充结果*/>> resultMap = new HashMap<>();
|
||||
List<Object> todoInsertList = new ArrayList<>();
|
||||
BookmarkUtil.BookmarkInfo bookmarkInfo = null;
|
||||
List<Object> todoInsertList;
|
||||
BookmarkUtil.BookmarkInfo bookmarkInfo;
|
||||
// 书签在文档的位置
|
||||
for (int i = 0; i < bookmarkEnums.size(); i++) {
|
||||
BookmarkEnum bookmarkEnum = bookmarkEnums.get(i);
|
||||
@@ -983,13 +959,13 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
cellValues.add(total);
|
||||
break;
|
||||
case TEST_RESULT_LINE:
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
cellValues.add(value.get(i) ? "合格" : "不合格");
|
||||
for (Boolean aBoolean : value) {
|
||||
cellValues.add(aBoolean ? "合格" : "不合格");
|
||||
}
|
||||
break;
|
||||
case TEST_RESULT_DETAIL:
|
||||
for (int i = 0; i < value.size(); i++) {
|
||||
cellValues.add(value.get(i) ? "合格" : "不合格");
|
||||
for (Boolean aBoolean : value) {
|
||||
cellValues.add(aBoolean ? "合格" : "不合格");
|
||||
}
|
||||
cellValues.add(total);
|
||||
break;
|
||||
@@ -1028,8 +1004,13 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
for (int i = 0; i < devChns; i++) {
|
||||
// 回路标题
|
||||
P titleParagraph = factory.createP();
|
||||
Integer lineNo = i + 1;
|
||||
Docx4jUtil.createTitle(factory, titleParagraph, "测量回路" + lineNo, 28, true);
|
||||
// 如果回路只有一个,则不需要加编号
|
||||
int lineNo = i + 1;
|
||||
if (devChns > 1) {
|
||||
Docx4jUtil.createTitle(factory, titleParagraph, "测量回路" + lineNo, 28, true);
|
||||
} else {
|
||||
Docx4jUtil.createTitle(factory, titleParagraph, "测量回路", 28, true);
|
||||
}
|
||||
todoInsertList.add(titleParagraph);
|
||||
// 依次处理大项文档内容
|
||||
Iterator<Map.Entry<String, List<PqScriptDtlDataVO>>> iterator = scriptMap.entrySet().iterator();
|
||||
@@ -1314,9 +1295,9 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
|
||||
StringBuilder filePath = new StringBuilder(reportPath.concat(File.separator));
|
||||
if (SceneEnum.LEAVE_FACTORY_TEST.getValue().equals(currrentScene)) {
|
||||
filePath.append(pqDevVO.getCreateId()).append(".docx");
|
||||
filePath.append(pqDevVO.getCreateId()).append(ReportConstant.DOCX);
|
||||
} else {
|
||||
filePath.append(devType.getName()).append(File.separator).append(pqDevVO.getCreateId()).append(".docx");
|
||||
filePath.append(devType.getName()).append(File.separator).append(pqDevVO.getCreateId()).append(ReportConstant.DOCX);
|
||||
}
|
||||
File reportFile = new File(filePath.toString());
|
||||
if (!reportFile.exists()) {
|
||||
@@ -1329,7 +1310,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
|
||||
// 设置响应头
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
||||
String fileName = pqDevVO.getCreateId() + ".docx";
|
||||
String fileName = pqDevVO.getCreateId() + ReportConstant.DOCX;
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
|
||||
// 将文件内容写入响应输出流
|
||||
@@ -1349,7 +1330,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean documented(List<String> ids) {
|
||||
if (CollUtil.isNotEmpty(ids)) {
|
||||
List<PqDevVO> pqDevVOList = pqDevMapper.listByDevIds(ids);
|
||||
@@ -1401,66 +1382,66 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
* 处理基础模版中的信息,非数据页报告
|
||||
* 此处为什么要抽出拼接的前缀&后缀,是因为Docx4j工具包替换时会默认增加${},故在使用docx4j时前后缀必须为空
|
||||
*/
|
||||
private Map<String, String> dealBaseModelData(PqDevVO pqDevVO, DevType devType, String prefix, String suffix) {
|
||||
private Map<String, String> dealBaseModelData(PqDevVO pqDevVO, DevType devType) {
|
||||
// 首先获取非数据页中需要的信息
|
||||
Map<String, String> baseModelMap = new HashMap<>(32);
|
||||
// 获取设备型号
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DEV_TYPE.getKey() + suffix, devType.getName());
|
||||
baseModelMap.put(BaseReportKeyEnum.DEV_TYPE.getKey(), devType.getName());
|
||||
// 检测员
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.INSPECTOR.getKey() + suffix, pqDevVO.getCheckBy() + "");
|
||||
baseModelMap.put(BaseReportKeyEnum.INSPECTOR.getKey(), pqDevVO.getCheckBy() + "");
|
||||
// 调试日期
|
||||
if (pqDevVO.getCheckTime() != null) {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.TEST_DATE.getKey() + suffix, DateUtil.format(pqDevVO.getCheckTime(), DatePattern.CHINESE_DATE_PATTERN));
|
||||
baseModelMap.put(BaseReportKeyEnum.TEST_DATE.getKey(), DateUtil.format(pqDevVO.getCheckTime(), DatePattern.CHINESE_DATE_PATTERN));
|
||||
} else {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.TEST_DATE.getKey() + suffix, DateUtil.format(new Date(), DatePattern.CHINESE_DATE_PATTERN));
|
||||
baseModelMap.put(BaseReportKeyEnum.TEST_DATE.getKey(), DateUtil.format(new Date(), DatePattern.CHINESE_DATE_PATTERN));
|
||||
}
|
||||
// 装置编码
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DEV_CODE.getKey() + suffix, pqDevVO.getCreateId());
|
||||
baseModelMap.put(BaseReportKeyEnum.DEV_CODE.getKey(), pqDevVO.getCreateId());
|
||||
// 工作电源
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.POWER.getKey() + suffix, devType.getPower());
|
||||
baseModelMap.put(BaseReportKeyEnum.POWER.getKey(), devType.getPower());
|
||||
// 额定电流
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DEV_CURR.getKey() + suffix, pqDevVO.getDevCurr().toString().concat(PowerConstant.CURRENT_UNIT));
|
||||
baseModelMap.put(BaseReportKeyEnum.DEV_CURR.getKey(), pqDevVO.getDevCurr().toString().concat(PowerConstant.CURRENT_UNIT));
|
||||
// 额定电压
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DEV_VOLT.getKey() + suffix, pqDevVO.getDevVolt().toString().concat(PowerConstant.VOLTAGE_UNIT));
|
||||
baseModelMap.put(BaseReportKeyEnum.DEV_VOLT.getKey(), pqDevVO.getDevVolt().toString().concat(PowerConstant.VOLTAGE_UNIT));
|
||||
// 通道数
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.COUNT.getKey() + suffix, pqDevVO.getDevChns().toString());
|
||||
baseModelMap.put(BaseReportKeyEnum.COUNT.getKey(), pqDevVO.getDevChns().toString());
|
||||
// 制造厂家
|
||||
DictData dictData = dictDataService.getDictDataById(pqDevVO.getManufacturer());
|
||||
if (ObjectUtil.isNotNull(dictData)) {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.MANUFACTURER.getKey() + suffix, dictData.getName());
|
||||
baseModelMap.put(BaseReportKeyEnum.MANUFACTURER.getKey(), dictData.getName());
|
||||
} else {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.MANUFACTURER.getKey() + suffix, StrPool.TAB);
|
||||
baseModelMap.put(BaseReportKeyEnum.MANUFACTURER.getKey(), StrPool.TAB);
|
||||
}
|
||||
// 委托方
|
||||
String delegate = pqDevVO.getDelegate();
|
||||
if (StrUtil.isNotBlank(delegate)) {
|
||||
DictData delegateDictData = dictDataService.getDictDataById(pqDevVO.getManufacturer());
|
||||
if (ObjectUtil.isNotNull(delegateDictData)) {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DELEGATE.getKey() + suffix, dictData.getName());
|
||||
baseModelMap.put(BaseReportKeyEnum.DELEGATE.getKey(), dictData.getName());
|
||||
} else {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DELEGATE.getKey() + suffix, StrPool.TAB);
|
||||
baseModelMap.put(BaseReportKeyEnum.DELEGATE.getKey(), StrPool.TAB);
|
||||
}
|
||||
} else {
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.DELEGATE.getKey() + suffix, StrPool.TAB);
|
||||
baseModelMap.put(BaseReportKeyEnum.DELEGATE.getKey(), StrPool.TAB);
|
||||
}
|
||||
|
||||
// 实验室温度
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.TEMPERATURE.getKey() + suffix, Objects.isNull(pqDevVO.getTemperature()) ? StrPool.TAB : pqDevVO.getTemperature().toString());
|
||||
baseModelMap.put(BaseReportKeyEnum.TEMPERATURE.getKey(), Objects.isNull(pqDevVO.getTemperature()) ? StrPool.TAB : pqDevVO.getTemperature().toString());
|
||||
// 实验室湿度
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.HUMIDITY.getKey() + suffix, Objects.isNull(pqDevVO.getHumidity()) ? StrPool.TAB : pqDevVO.getHumidity().toString());
|
||||
baseModelMap.put(BaseReportKeyEnum.HUMIDITY.getKey(), Objects.isNull(pqDevVO.getHumidity()) ? StrPool.TAB : pqDevVO.getHumidity().toString());
|
||||
|
||||
// 样品编号
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.SAMPLE_ID.getKey() + suffix, StrUtil.isEmpty(pqDevVO.getSampleId()) ? StrPool.TAB : pqDevVO.getSampleId());
|
||||
baseModelMap.put(BaseReportKeyEnum.SAMPLE_ID.getKey(), 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(BaseReportKeyEnum.ARRIVED_DATE.getKey(), 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.TEMPERATURE.getKey() + suffix, Objects.isNull(pqDevVO.getTemperature()) ? StrPool.TAB : pqDevVO.getTemperature().toString());
|
||||
baseModelMap.put(prefix + BaseReportKeyEnum.HUMIDITY.getKey() + suffix, Objects.isNull(pqDevVO.getHumidity()) ? StrPool.TAB : pqDevVO.getHumidity().toString());
|
||||
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));
|
||||
baseModelMap.put(BaseReportKeyEnum.TEST_DATE.getKey(), Objects.isNull(pqDevVO.getCheckTime()) ? StrPool.TAB : String.valueOf(pqDevVO.getCheckTime()).substring(0, 10));
|
||||
baseModelMap.put(BaseReportKeyEnum.TEMPERATURE.getKey(), Objects.isNull(pqDevVO.getTemperature()) ? StrPool.TAB : pqDevVO.getTemperature().toString());
|
||||
baseModelMap.put(BaseReportKeyEnum.HUMIDITY.getKey(), Objects.isNull(pqDevVO.getHumidity()) ? StrPool.TAB : pqDevVO.getHumidity().toString());
|
||||
baseModelMap.put(BaseReportKeyEnum.YEAR.getKey(), DateUtil.format(new Date(), DatePattern.NORM_YEAR_PATTERN));
|
||||
baseModelMap.put(BaseReportKeyEnum.MONTH.getKey(), DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN).substring(4));
|
||||
baseModelMap.put(BaseReportKeyEnum.DAY.getKey(), DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN).substring(6));
|
||||
baseModelMap.put(BaseReportKeyEnum.YEAR_MONTH_DAY.getKey(), DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN));
|
||||
return baseModelMap;
|
||||
}
|
||||
|
||||
@@ -1468,37 +1449,24 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
/**
|
||||
* 获取数据页的信息
|
||||
*
|
||||
* @param baseModelDocument 非数据页的内容
|
||||
* @param devReportParam 查询参数
|
||||
* @param devReportParam 查询参数
|
||||
*/
|
||||
private void dealDataModel(XWPFDocument baseModelDocument, DevReportParam devReportParam, PqDevVO pqDevVO) throws IOException {
|
||||
//AdPlan adPlan = adPlanService.getById(devReportParam.getPlanId());
|
||||
//String scriptId = adPlan.getScriptId();
|
||||
private void dealDataModel(List<InputStream> wordFileInputStreams, DevReportParam devReportParam, PqDevVO pqDevVO) throws Exception {
|
||||
Integer devChns = pqDevVO.getDevChns();
|
||||
for (int i = 1; i <= devChns; i++) {
|
||||
ClassPathResource resource = new ClassPathResource("/model/report_table.docx");
|
||||
XWPFDocument dataModelDocumentTemp = new XWPFDocument(resource.getInputStream());
|
||||
|
||||
SingleNonHarmParam singleNonHarmParam = new SingleNonHarmParam();
|
||||
singleNonHarmParam.setPlanCode(devReportParam.getPlanCode());
|
||||
singleNonHarmParam.setDevId(pqDevVO.getId());
|
||||
singleNonHarmParam.setChannelNo(i);
|
||||
|
||||
// 获取数据
|
||||
Map<String, String> dataModelMap = new HashMap<>();
|
||||
dataModelMap.put("${CreateId}", pqDevVO.getCreateId());
|
||||
dataModelMap.put("${total}", pqDevVO.getDevChns().toString());
|
||||
dataModelMap.put("${count}", i + "");
|
||||
|
||||
Map<String, String> dataModelMap = new HashMap<>(16);
|
||||
// 读取模板文件中的占位符
|
||||
List<String> allMarkList = getAllKeys(dataModelDocumentTemp);
|
||||
Set<String> allMarkList = WordDocumentUtil.extractPlaceholders(resource.getInputStream(), false, Arrays.asList("CreateId", "total", "count"));
|
||||
Map<String, Set<String>> indexKeysMap = allMarkList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
obj -> obj.split("#")[0].replace("${", ""),
|
||||
obj -> obj.split("#")[0],
|
||||
Collectors.mapping(obj -> {
|
||||
int index1 = obj.indexOf("#") + 1;
|
||||
return obj.substring(index1, obj.indexOf("#", index1));
|
||||
}, Collectors.toSet()))); //key为index,value为该index下所有测试项对应的code
|
||||
//key为index,value为该index下所有测试项对应的code
|
||||
}, Collectors.toSet())));
|
||||
|
||||
List<SimAndDigNonHarmonicResult> simAndDigNonHarmonicResultList = adNonHarmonicService.listSimAndDigBaseResult(devReportParam.getScriptId(), devReportParam.getPlanCode(), devReportParam.getDevId() + "_" + i);
|
||||
List<SimAndDigHarmonicResult> adHarmonicResultList = adHarmonicService.listAllResultData(devReportParam.getScriptId(), devReportParam.getPlanCode(), devReportParam.getDevId() + "_" + i);
|
||||
@@ -1518,21 +1486,21 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dataModelMap.put("CreateId", pqDevVO.getCreateId());
|
||||
dataModelMap.put("total", pqDevVO.getDevChns().toString());
|
||||
dataModelMap.put("count", i + "");
|
||||
// 替换文档内容
|
||||
WordUtil.replacePlaceholdersInParagraphs(dataModelDocumentTemp, dataModelMap);
|
||||
WordUtil.replacePlaceholdersInTables(dataModelDocumentTemp, dataModelMap);
|
||||
WordUtil.appendDocument(baseModelDocument, dataModelDocumentTemp);
|
||||
wordFileInputStreams.add(wordReportService.replacePlaceholders(resource.getInputStream(), dataModelMap));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充数据(ABC相)
|
||||
*
|
||||
* @param allNonHarmonicResultList
|
||||
* @param dataModelMap
|
||||
* @param keys
|
||||
* @param index
|
||||
* @param allNonHarmonicResultList 结果数据
|
||||
* @param dataModelMap 替换数据
|
||||
* @param keys keys
|
||||
* @param index index
|
||||
*/
|
||||
private void fillMapValueABC(List<SimAndDigNonHarmonicResult> allNonHarmonicResultList, Map<String, String> dataModelMap, Set<String> keys, String index) {
|
||||
keys.forEach(key -> {
|
||||
@@ -1540,9 +1508,9 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
if (CollectionUtil.isNotEmpty(resultList)) {
|
||||
SimAndDigNonHarmonicResult adNonHarmonicResult = resultList.get(0);
|
||||
if (ObjectUtil.isNotNull(adNonHarmonicResult)) {
|
||||
dataModelMap.put("${" + index + "#" + key + "#A}", devValue(adNonHarmonicResult.getAValue(), 1, 1));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B}", devValue(adNonHarmonicResult.getBValue(), 1, 1));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C}", devValue(adNonHarmonicResult.getCValue(), 1, 1));
|
||||
dataModelMap.put(index + "#" + key + "#A", devValue(adNonHarmonicResult.getAValue(), 1, 1));
|
||||
dataModelMap.put(index + "#" + key + "#B", devValue(adNonHarmonicResult.getBValue(), 1, 1));
|
||||
dataModelMap.put(index + "#" + key + "#C", devValue(adNonHarmonicResult.getCValue(), 1, 1));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1551,10 +1519,10 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
/**
|
||||
* 填充数据(T相)
|
||||
*
|
||||
* @param allNonHarmonicResultList
|
||||
* @param dataModelMap
|
||||
* @param keys
|
||||
* @param index
|
||||
* @param allNonHarmonicResultList 结果数据
|
||||
* @param dataModelMap 替换数据
|
||||
* @param keys key
|
||||
* @param index index
|
||||
*/
|
||||
private void fillMapValueT(List<SimAndDigNonHarmonicResult> allNonHarmonicResultList, Map<String, String> dataModelMap, Set<String> keys, String index) {
|
||||
keys.forEach(key -> {
|
||||
@@ -1562,7 +1530,7 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
if (CollectionUtil.isNotEmpty(resultList)) {
|
||||
SimAndDigNonHarmonicResult adNonHarmonicResult = resultList.get(0);
|
||||
if (ObjectUtil.isNotNull(adNonHarmonicResult)) {
|
||||
dataModelMap.put("${" + index + "#" + key + "#T}", devValue(adNonHarmonicResult.getTValue(), 1, 1));
|
||||
dataModelMap.put(index + "#" + key + "#T", devValue(adNonHarmonicResult.getTValue(), 1, 1));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1571,10 +1539,10 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
/**
|
||||
* 填充数据(谐波类)
|
||||
*
|
||||
* @param allHarmonicResultList
|
||||
* @param dataModelMap
|
||||
* @param keys
|
||||
* @param index
|
||||
* @param allHarmonicResultList 结果数据
|
||||
* @param dataModelMap 替换数据
|
||||
* @param keys key
|
||||
* @param index index
|
||||
*/
|
||||
private void fillMapValueHarm(List<SimAndDigHarmonicResult> allHarmonicResultList, Map<String, String> dataModelMap, Set<String> keys, String index) {
|
||||
keys.forEach(key -> {
|
||||
@@ -1609,9 +1577,9 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
String aBase = devValue(adHarmonicResult.getAValue1(), 1, 1);
|
||||
String bBase = devValue(adHarmonicResult.getBValue1(), 1, 1);
|
||||
String cBase = devValue(adHarmonicResult.getCValue1(), 1, 1);
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#1}", aBase);
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#1}", bBase);
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#1}", cBase);
|
||||
dataModelMap.put(index + "#" + key + "#A#1", aBase);
|
||||
dataModelMap.put(index + "#" + key + "#B#1", bBase);
|
||||
dataModelMap.put(index + "#" + key + "#C#1", cBase);
|
||||
|
||||
// 基波
|
||||
double aBaseValue = baseValue;
|
||||
@@ -1629,71 +1597,39 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
}
|
||||
}
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#2}", devValue(adHarmonicResult.getAValue2(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#2}", devValue(adHarmonicResult.getBValue2(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#2}", devValue(adHarmonicResult.getCValue2(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#2", devValue(adHarmonicResult.getAValue2(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#2", devValue(adHarmonicResult.getBValue2(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#2", devValue(adHarmonicResult.getCValue2(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#5}", devValue(adHarmonicResult.getAValue5(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#5}", devValue(adHarmonicResult.getBValue5(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#5}", devValue(adHarmonicResult.getCValue5(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#5", devValue(adHarmonicResult.getAValue5(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#5", devValue(adHarmonicResult.getBValue5(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#5", devValue(adHarmonicResult.getCValue5(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#7}", devValue(adHarmonicResult.getAValue7(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#7}", devValue(adHarmonicResult.getBValue7(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#7}", devValue(adHarmonicResult.getCValue7(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#7", devValue(adHarmonicResult.getAValue7(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#7", devValue(adHarmonicResult.getBValue7(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#7", devValue(adHarmonicResult.getCValue7(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#11}", devValue(adHarmonicResult.getAValue11(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#11}", devValue(adHarmonicResult.getBValue11(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#11}", devValue(adHarmonicResult.getCValue11(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#11", devValue(adHarmonicResult.getAValue11(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#11", devValue(adHarmonicResult.getBValue11(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#11", devValue(adHarmonicResult.getCValue11(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#23}", devValue(adHarmonicResult.getAValue23(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#23}", devValue(adHarmonicResult.getBValue23(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#23}", devValue(adHarmonicResult.getCValue23(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#23", devValue(adHarmonicResult.getAValue23(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#23", devValue(adHarmonicResult.getBValue23(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#23", devValue(adHarmonicResult.getCValue23(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#35}", devValue(adHarmonicResult.getAValue35(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#35}", devValue(adHarmonicResult.getBValue35(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#35}", devValue(adHarmonicResult.getCValue35(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#35", devValue(adHarmonicResult.getAValue35(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#35", devValue(adHarmonicResult.getBValue35(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#35", devValue(adHarmonicResult.getCValue35(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#43}", devValue(adHarmonicResult.getAValue43(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#43}", devValue(adHarmonicResult.getBValue43(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#43}", devValue(adHarmonicResult.getCValue43(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#43", devValue(adHarmonicResult.getAValue43(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#43", devValue(adHarmonicResult.getBValue43(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#43", devValue(adHarmonicResult.getCValue43(), cBaseValue, percent));
|
||||
|
||||
dataModelMap.put("${" + index + "#" + key + "#A#50}", devValue(adHarmonicResult.getAValue50(), aBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#B#50}", devValue(adHarmonicResult.getBValue50(), bBaseValue, percent));
|
||||
dataModelMap.put("${" + index + "#" + key + "#C#50}", devValue(adHarmonicResult.getCValue50(), cBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#A#50", devValue(adHarmonicResult.getAValue50(), aBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#B#50", devValue(adHarmonicResult.getBValue50(), bBaseValue, percent));
|
||||
dataModelMap.put(index + "#" + key + "#C#50", devValue(adHarmonicResult.getCValue50(), cBaseValue, percent));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件所有表格中的占位符
|
||||
*
|
||||
* @param dataModelDocumentTemp
|
||||
* @return
|
||||
*/
|
||||
private List<String> getAllKeys(XWPFDocument dataModelDocumentTemp) {
|
||||
List<String> allMarkList = new ArrayList<>();
|
||||
List<XWPFTable> tables = dataModelDocumentTemp.getTables();
|
||||
|
||||
for (XWPFTable table : tables) {
|
||||
List<XWPFTableRow> rows = table.getRows();
|
||||
for (XWPFTableRow row : rows) {
|
||||
List<XWPFTableCell> cells = row.getTableCells();
|
||||
for (XWPFTableCell cell : cells) {
|
||||
List<XWPFParagraph> paragraphs = cell.getParagraphs();
|
||||
for (XWPFParagraph paragraph : paragraphs) {
|
||||
List<XWPFRun> runs = paragraph.getRuns();
|
||||
for (XWPFRun run : runs) {
|
||||
String text = run.getText(0);
|
||||
if (StrUtil.isNotBlank(text) && text.startsWith("$")) {
|
||||
allMarkList.add(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return allMarkList.stream().sorted(Comparator.comparing(String::toString)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private String devValue(String dataJson, double baseValue, Integer percent) {
|
||||
DetectionData tempA = JSONUtil.toBean(dataJson, DetectionData.class);
|
||||
if (Objects.nonNull(tempA) && Objects.nonNull(tempA.getData())) {
|
||||
@@ -1752,21 +1688,16 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
@Override
|
||||
public void uploadReportToCloud(List<String> deviceIds) {
|
||||
log.info("开始批量上传检测报告到云端,设备ID列表:{}", deviceIds);
|
||||
|
||||
|
||||
List<PqDevSub> deviceSubs = iPqDevSubService.lambdaQuery()
|
||||
.eq(PqDevSub::getReportState, DevReportStateEnum.GENERATED.getValue())
|
||||
.in(CollUtil.isNotEmpty(deviceIds),PqDevSub::getDevId, deviceIds).list();
|
||||
.in(CollUtil.isNotEmpty(deviceIds), PqDevSub::getDevId, deviceIds).list();
|
||||
List<String> devIds = deviceSubs.stream().map(PqDevSub::getDevId).collect(Collectors.toList());
|
||||
|
||||
List<PqDev> devices = iPqDevService.lambdaQuery()
|
||||
.in(CollUtil.isNotEmpty(devIds), PqDev::getId, devIds).list();
|
||||
|
||||
.in(CollUtil.isNotEmpty(devIds), PqDev::getId, devIds).list();
|
||||
if (CollUtil.isEmpty(devices)) {
|
||||
log.warn("未找到符合条件的设备,无需上传");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("找到{}台设备需要上传报告", devices.size());
|
||||
String dirPath = reportPath;
|
||||
// 确保目录存在
|
||||
@@ -1776,8 +1707,8 @@ public class PqReportServiceImpl extends ServiceImpl<PqReportMapper, PqReport> i
|
||||
for (PqDev device : devices) {
|
||||
try {
|
||||
// 构建报告文件路径
|
||||
String fileName = device.getCreateId() + ".docx";
|
||||
String reportFullPath = dirPath.concat(File.separator).concat(device.getCreateId()).concat(".docx");
|
||||
String fileName = device.getCreateId() + ReportConstant.DOCX;
|
||||
String reportFullPath = dirPath.concat(File.separator).concat(device.getCreateId()).concat(ReportConstant.DOCX);
|
||||
File reportFile = new File(reportFullPath);
|
||||
|
||||
if (!reportFile.exists()) {
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
package com.njcn.gather.report.utils;
|
||||
|
||||
|
||||
import com.njcn.gather.report.pojo.enums.BookmarkEnum;
|
||||
import com.njcn.gather.report.pojo.enums.PowerIndexEnum;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
|
||||
import org.docx4j.wml.*;
|
||||
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* 递归查找所有书签,并在书签处插入内容
|
||||
*/
|
||||
public class BookmarkUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 书签信息
|
||||
*/
|
||||
public static class BookmarkInfo {
|
||||
public CTBookmark bookmark;
|
||||
public P parentParagraph;
|
||||
public ContentAccessor parentContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查找所有书签
|
||||
*/
|
||||
public static List<BookmarkInfo> findAllBookmarks(ContentAccessor contentAccessor) {
|
||||
List<BookmarkInfo> result = new ArrayList<>();
|
||||
for (Object obj : contentAccessor.getContent()) {
|
||||
Object realObj = (obj instanceof JAXBElement) ? ((JAXBElement<?>) obj).getValue() : obj;
|
||||
if (realObj instanceof P) {
|
||||
P p = (P) realObj;
|
||||
for (Object o2 : p.getContent()) {
|
||||
Object realO2 = (o2 instanceof JAXBElement) ? ((JAXBElement<?>) o2).getValue() : o2;
|
||||
if (realO2 instanceof CTBookmark) {
|
||||
BookmarkInfo info = new BookmarkInfo();
|
||||
info.bookmark = (CTBookmark) realO2;
|
||||
info.parentParagraph = p;
|
||||
info.parentContainer = contentAccessor;
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
} else if (realObj instanceof ContentAccessor) {
|
||||
result.addAll(findAllBookmarks((ContentAccessor) realObj));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在书签后插入段落
|
||||
*/
|
||||
public static void insertParagraphsAfter(BookmarkInfo info, P paragraph) {
|
||||
List<Object> parentContent = info.parentContainer.getContent();
|
||||
int idx = parentContent.indexOf(info.parentParagraph);
|
||||
parentContent.add(idx + 1, paragraph);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在书签后插入表格
|
||||
*/
|
||||
public static void insertTableAfter(BookmarkInfo info, Tbl table) {
|
||||
List<Object> parentContent = info.parentContainer.getContent();
|
||||
int idx = parentContent.indexOf(info.parentParagraph);
|
||||
parentContent.add(idx + 1, table);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在书签后插入元素,可能是段落、表格、图片、书签等
|
||||
*/
|
||||
public static void insertElement(BookmarkInfo info, List<Object> elements) {
|
||||
List<Object> parentContent = info.parentContainer.getContent();
|
||||
int idx = parentContent.indexOf(info.parentParagraph);
|
||||
// 遍历元素,如果是通道回路这种大标题需要新起一个空的文档页
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
Object element = elements.get(i);
|
||||
if (element instanceof P) {
|
||||
P p = (P) element;
|
||||
String textFromP = Docx4jUtil.getTextFromP(p);
|
||||
if (textFromP.contains("测量回路")) {
|
||||
if (!textFromP.contains("1")) {
|
||||
// 另起一页
|
||||
P pagePara = Docx4jUtil.getPageBreak();
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, pagePara);
|
||||
}
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, p);
|
||||
}
|
||||
else if (textFromP.startsWith(PowerIndexEnum.IMBV.getDesc())
|
||||
|| textFromP.startsWith(PowerIndexEnum.HV.getDesc())
|
||||
|| textFromP.startsWith(PowerIndexEnum.HI.getDesc())
|
||||
|
||||
) {
|
||||
// 另起一页
|
||||
P pagePara = Docx4jUtil.getPageBreak();
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, pagePara);
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, element);
|
||||
}else if(textFromP.startsWith("注:基波电流幅值5.000A,基波频率50.0Hz,各次间谐波电流含有率均为3.0%。")){
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, element);
|
||||
P pagePara = Docx4jUtil.getPageBreak();
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, pagePara);
|
||||
}
|
||||
else {
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, element);
|
||||
}
|
||||
} else {
|
||||
idx = idx + 1;
|
||||
parentContent.add(idx, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文档中的空白页
|
||||
* @param docx 要处理的Word文档
|
||||
*/
|
||||
public static void removeBlankPages(MainDocumentPart mainDocumentPart) {
|
||||
// 获取文档主体
|
||||
Document document = mainDocumentPart.getJaxbElement();
|
||||
Body body = document.getBody();
|
||||
|
||||
// 获取所有段落
|
||||
List<Object> paragraphs = body.getContent();
|
||||
|
||||
// 用于标记是否在空白页中
|
||||
boolean inBlankPage = false;
|
||||
// 用于存储要删除的段落
|
||||
List<P> paragraphsToRemove = new ArrayList<>();
|
||||
|
||||
for (Object paragraph : paragraphs) {
|
||||
if (paragraph instanceof P){
|
||||
P paragraphtemp = (P) paragraph;
|
||||
// 检查段落是否为空
|
||||
boolean isEmpty = isParagraphEmpty(paragraphtemp);
|
||||
|
||||
if (isEmpty) {
|
||||
if (!inBlankPage) {
|
||||
inBlankPage = true;
|
||||
}
|
||||
paragraphsToRemove.add(paragraphtemp);
|
||||
} else {
|
||||
inBlankPage = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除空白段落
|
||||
for (P paragraph : paragraphsToRemove) {
|
||||
body.getContent().remove(paragraph);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查段落是否为空
|
||||
* @param paragraph 要检查的段落
|
||||
* @return 如果段落为空返回true,否则返回false
|
||||
*/
|
||||
private static boolean isParagraphEmpty(P paragraph) {
|
||||
// 检查段落是否包含分节符
|
||||
if (paragraph.getPPr() != null && paragraph.getPPr().getSectPr() != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查段落中的文本内容
|
||||
for (Object obj : paragraph.getContent()) {
|
||||
if (obj instanceof R) {
|
||||
R run = (R) obj;
|
||||
// 在3.3.4版本中,使用getContent()获取文本内容
|
||||
for (Object runContent : run.getContent()) {
|
||||
if (runContent instanceof Text) {
|
||||
Text text = (Text) runContent;
|
||||
if (text.getValue() != null && !text.getValue().trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在插入前检查目标位置是否有分页符
|
||||
*
|
||||
* @param position 目标位置
|
||||
* @return 是否包含分页符
|
||||
*/
|
||||
private static boolean hasPageBreak(Object position) {
|
||||
if (position instanceof P) {
|
||||
P paragraph = (P) position;
|
||||
for (Object run : paragraph.getContent()) {
|
||||
if (run instanceof R) {
|
||||
R r = (R) run;
|
||||
for (Object element : r.getContent()) {
|
||||
if (element instanceof Br && ((Br) element).getType() != null
|
||||
&& ((Br) element).getType().equals("page")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除书签
|
||||
*
|
||||
* @param bookmarkInfo 书签信息
|
||||
*/
|
||||
public static void removeBookmark(BookmarkUtil.BookmarkInfo bookmarkInfo) {
|
||||
try {
|
||||
// 获取书签所在的段落
|
||||
P paragraph = bookmarkInfo.parentParagraph;
|
||||
|
||||
// 遍历段落内容,找到并删除书签开始和结束标记
|
||||
List<Object> paragraphContent = new ArrayList<>(paragraph.getContent());
|
||||
for (Object obj : paragraphContent) {
|
||||
if (obj instanceof JAXBElement) {
|
||||
JAXBElement<?> element = (JAXBElement<?>) obj;
|
||||
Object value = element.getValue();
|
||||
|
||||
// 删除书签开始标记
|
||||
if (value instanceof CTBookmark) {
|
||||
paragraph.getContent().remove(obj);
|
||||
}
|
||||
// 删除书签结束标记
|
||||
else if (value instanceof CTMarkupRange) {
|
||||
paragraph.getContent().remove(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 ObjectFactory 创建表格
|
||||
*
|
||||
* @param factory ObjectFactory 实例
|
||||
* @param data 二维数组,表格内容
|
||||
* @return Tbl 表格对象
|
||||
*/
|
||||
public static Tbl createTable(ObjectFactory factory, String[][] data) {
|
||||
Tbl table = factory.createTbl();
|
||||
for (String[] rowData : data) {
|
||||
Tr row = factory.createTr();
|
||||
for (String cellData : rowData) {
|
||||
Tc cell = factory.createTc();
|
||||
P para = factory.createP();
|
||||
R run = factory.createR();
|
||||
Text text = factory.createText();
|
||||
text.setValue(cellData);
|
||||
run.getContent().add(text);
|
||||
para.getContent().add(run);
|
||||
cell.getContent().add(para);
|
||||
row.getContent().add(cell);
|
||||
}
|
||||
table.getContent().add(row);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定标签的标签信息
|
||||
*
|
||||
* @param key 标签名
|
||||
* @param bookmarks 所有标签信息
|
||||
*/
|
||||
public static BookmarkInfo getBookmarkInfo(String key, List<BookmarkInfo> bookmarks) {
|
||||
BookmarkUtil.BookmarkInfo bookmarkInfo = null;
|
||||
for (BookmarkUtil.BookmarkInfo info : bookmarks) {
|
||||
String name = info.bookmark.getName();
|
||||
if (key.equalsIgnoreCase(name)) {
|
||||
bookmarkInfo = info;
|
||||
}
|
||||
}
|
||||
return bookmarkInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,633 +0,0 @@
|
||||
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 org.docx4j.XmlUtils;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
|
||||
import org.docx4j.wml.*;
|
||||
|
||||
import javax.xml.bind.JAXBElement;
|
||||
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,PPr ppr) {
|
||||
R run = factory.createR();
|
||||
Text text = factory.createText();
|
||||
text.setValue(content);
|
||||
run.setRPr(rPr);
|
||||
run.getContent().add(text);
|
||||
paragraph.getContent().add(run);
|
||||
paragraph.setPPr(ppr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建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);
|
||||
// 字体
|
||||
// 设置字体
|
||||
RPr rPr = factory.createRPr();
|
||||
RFonts rFonts = factory.createRFonts();
|
||||
if (containsChinese(value)) {
|
||||
rFonts.setEastAsia("宋体");
|
||||
rFonts.setAscii("宋体");
|
||||
rFonts.setHAnsi("宋体");
|
||||
} else {
|
||||
rFonts.setEastAsia("Arial");
|
||||
rFonts.setAscii("Arial");
|
||||
rFonts.setHAnsi("Arial");
|
||||
}
|
||||
rPr.setRFonts(rFonts);
|
||||
// 设置段落居中
|
||||
if (centerFlag) {
|
||||
PPr pPr = factory.createPPr();
|
||||
Jc jc = factory.createJc();
|
||||
jc.setVal(JcEnumeration.CENTER);
|
||||
pPr.setJc(jc);
|
||||
paragraph.setPPr(pPr);
|
||||
}
|
||||
if (value.equals("不合格")) {
|
||||
Color color = factory.createColor();
|
||||
// 红色
|
||||
color.setVal("FF0000");
|
||||
rPr.setColor(color);
|
||||
run.setRPr(rPr);
|
||||
}
|
||||
HpsMeasure sz = factory.createHpsMeasure();
|
||||
// 10号字体 = 20 half-points
|
||||
sz.setVal(new BigInteger("20"));
|
||||
rPr.setSz(sz);
|
||||
|
||||
cell.getContent().add(paragraph);
|
||||
cell.setTcPr(tcPr);
|
||||
row.getContent().add(cell);
|
||||
row.setTrPr(trPr);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断字符串是否包含中文
|
||||
* @param str 需要判断的字符串
|
||||
* @return 是否包含中文
|
||||
*/
|
||||
private static boolean containsChinese(String str) {
|
||||
if (str == null) {
|
||||
return false;
|
||||
}
|
||||
for (char c : str.toCharArray()) {
|
||||
if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据已知信息创建新行
|
||||
*
|
||||
* @param factory 工厂
|
||||
* @param cellValues 数据
|
||||
* @param 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, List<Integer> centerFlag) {
|
||||
Tr row = factory.createTr();
|
||||
for (int i = 0; i < cellValues.size(); i++) {
|
||||
String value = cellValues.get(i);
|
||||
Tc cell = factory.createTc();
|
||||
P paragraph = factory.createP();
|
||||
R run = factory.createR();
|
||||
Text text = factory.createText();
|
||||
text.setValue(value);
|
||||
run.getContent().add(text);
|
||||
paragraph.getContent().add(run);
|
||||
// 设置段落居中
|
||||
if (!centerFlag.contains(i)) {
|
||||
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);
|
||||
// 设置单元格边距
|
||||
TcPr cellProperties = factory.createTcPr();
|
||||
cell.setTcPr(cellProperties);
|
||||
// 设置单元格上下边距(单位:缇)
|
||||
TcMar mar = factory.createTcMar();
|
||||
TblWidth top = factory.createTblWidth();
|
||||
top.setW(BigInteger.valueOf(100));
|
||||
mar.setTop(top);
|
||||
TblWidth bottom = factory.createTblWidth();
|
||||
bottom.setW(BigInteger.valueOf(100));
|
||||
mar.setBottom(bottom);
|
||||
cellProperties.setTcMar(mar);
|
||||
row.getContent().add(cell);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定书签在文档段落中的位置索引
|
||||
*
|
||||
* @param documentPart 主文档部分
|
||||
* @param bookmarkName 书签名称
|
||||
* @return 段落索引,找不到返回 -1
|
||||
*/
|
||||
public static int getParagraphPosition(MainDocumentPart documentPart, String bookmarkName) {
|
||||
List<Object> content = documentPart.getContent();
|
||||
for (int i = 0; i < content.size(); i++) {
|
||||
Object obj = content.get(i);
|
||||
// 只处理段落
|
||||
if (obj instanceof P) {
|
||||
P paragraph = (P) obj;
|
||||
// 提取段落纯文本
|
||||
String text = getTextFromP(paragraph).trim();
|
||||
if (text.startsWith("#{") && text.endsWith("}")) {
|
||||
// 提取书签名
|
||||
String name = text.substring(2, text.length() - 1);
|
||||
if (name.equals(bookmarkName)) {
|
||||
// 返回段落索引
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 找不到返回 -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取段落在文档中的位置
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取分页符
|
||||
*/
|
||||
public static P getPageBreak() {
|
||||
try {
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
// 创建分页符
|
||||
R run = factory.createR();
|
||||
Br br = factory.createBr();
|
||||
br.setType(STBrType.PAGE);
|
||||
// 直接添加 br 对象
|
||||
run.getContent().add(br);
|
||||
// 创建包含分页符的段落
|
||||
P pageBreakParagraph = factory.createP();
|
||||
pageBreakParagraph.getContent().add(run);
|
||||
return pageBreakParagraph;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0
|
||||
* @data 2025/1/9 20:52
|
||||
*/
|
||||
public class WordUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 将源文档的内容(包括段落、表格等)追加到目标文档中
|
||||
*
|
||||
* @param target 目标文档
|
||||
* @param source 源文档
|
||||
*/
|
||||
public static void appendDocument(XWPFDocument target, XWPFDocument source) {
|
||||
// 在追加内容之前,插入分页符
|
||||
// insertPageBreak(target);
|
||||
// 遍历源文档的所有块(段落、表格等)
|
||||
source.getBodyElements().forEach(bodyElement -> {
|
||||
switch (bodyElement.getElementType()) {
|
||||
case PARAGRAPH:
|
||||
// 处理段落
|
||||
XWPFParagraph sourceParagraph = (XWPFParagraph) bodyElement;
|
||||
XWPFParagraph newParagraph = target.createParagraph();
|
||||
newParagraph.getCTP().set(sourceParagraph.getCTP());
|
||||
break;
|
||||
case TABLE:
|
||||
// 处理表格
|
||||
XWPFTable sourceTable = (XWPFTable) bodyElement;
|
||||
XWPFTable newTable = target.createTable();
|
||||
newTable.getCTTbl().set(sourceTable.getCTTbl());
|
||||
break;
|
||||
default:
|
||||
// 针对其他类型(如图片、页眉页脚等)可以扩展处理逻辑
|
||||
System.out.println("未处理的内容类型:" + bodyElement.getElementType());
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 替换表格中的占位符
|
||||
* @param document 文档
|
||||
* @param placeholders 待替换的占位符
|
||||
*/
|
||||
public static void replacePlaceholdersInTables(XWPFDocument document, Map<String, String> placeholders) {
|
||||
for (XWPFTable table : document.getTables()) {
|
||||
for (XWPFTableRow row : table.getRows()) {
|
||||
for (XWPFTableCell cell : row.getTableCells()) {
|
||||
for (XWPFParagraph paragraph : cell.getParagraphs()) {
|
||||
List<XWPFRun> runs = paragraph.getRuns();
|
||||
if (runs != null) {
|
||||
for (XWPFRun run : runs) {
|
||||
String text = run.getText(0);
|
||||
if (text != null) {
|
||||
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
|
||||
text = text.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
run.setText(text, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 替换段落中的占位符
|
||||
* @param document 文档
|
||||
* @param placeholders 待替换的占位符
|
||||
*/
|
||||
public static void replacePlaceholdersInParagraphs(XWPFDocument document, Map<String, String> placeholders) {
|
||||
for (XWPFParagraph paragraph : document.getParagraphs()) {
|
||||
List<XWPFRun> runs = paragraph.getRuns();
|
||||
if (runs != null) {
|
||||
for (XWPFRun run : runs) {
|
||||
String text = run.getText(0);
|
||||
if (text != null) {
|
||||
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
|
||||
text = text.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
run.setText(text, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换文档中的占位符
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user