1.新增稳态区域报告功能
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package com.njcn.harmonic.pojo.dto.report;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: cdf
|
||||
* @CreateTime: 2026-01-06
|
||||
* @Description: 公共台账
|
||||
*/
|
||||
@Data
|
||||
public class CommReportLedgerDto {
|
||||
|
||||
private String deptName;
|
||||
|
||||
private String monitorName;
|
||||
|
||||
private List<MonitorLedgerInfo> monitorNameList;
|
||||
|
||||
|
||||
|
||||
@Data
|
||||
static class MonitorLedgerInfo {
|
||||
|
||||
private String monitorName;
|
||||
|
||||
private String gdName;
|
||||
|
||||
private String bdName;
|
||||
|
||||
private String busBarName;
|
||||
|
||||
private String voltageLevel;
|
||||
|
||||
private String shortCapacity;
|
||||
|
||||
private String devCapacity;
|
||||
|
||||
private String dealCapacity;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.harmonic.pojo.dto.report;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: cdf
|
||||
* @CreateTime: 2026-01-07
|
||||
* @Description:
|
||||
*/
|
||||
@Data
|
||||
public class TableMergeRule {
|
||||
|
||||
/** 文档中表格的索引(从0开始) */
|
||||
private Integer tableIndex;
|
||||
/** 要合并的列索引(比如0=第0列) */
|
||||
private Integer mergeColIndex;
|
||||
/** 从第几行开始合并(从0开始计数,比如从第2行开始填2) */
|
||||
private Integer startRow = 0;
|
||||
/** 每多少行合并一次(比如5=每5行合并一组) */
|
||||
private Integer mergeRowsPerGroup;
|
||||
/** 是否启用该规则 */
|
||||
private boolean enable = true;
|
||||
|
||||
// 快捷构造方法(包含起始行)
|
||||
public static TableMergeRule build(int tableIndex, int mergeColIndex, int startRow, int mergeRowsPerGroup) {
|
||||
TableMergeRule rule = new TableMergeRule();
|
||||
rule.setTableIndex(tableIndex);
|
||||
rule.setMergeColIndex(mergeColIndex);
|
||||
rule.setStartRow(startRow);
|
||||
rule.setMergeRowsPerGroup(mergeRowsPerGroup);
|
||||
rule.setEnable(true);
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.njcn.harmonic.pojo.param.report;
|
||||
|
||||
import com.njcn.harmonic.pojo.dto.report.CommReportLedgerDto;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: cdf
|
||||
* @CreateTime: 2026-01-06
|
||||
* @Description: 谐波区域报告
|
||||
*/
|
||||
@Data
|
||||
public class AreaHarmReportParam {
|
||||
|
||||
private String startTime;
|
||||
|
||||
private String endTime;
|
||||
|
||||
private String deptId;
|
||||
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package com.njcn.harmonic.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 类的介绍:
|
||||
*
|
||||
@@ -37,24 +40,44 @@ public class OverAreaLimitVO {
|
||||
* 个数
|
||||
*/
|
||||
private Integer frequencyMonitorNumber = 0;
|
||||
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> freqMonitorList = new ArrayList<>();;
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double frequencyBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double frequencyDayAvgBiLi = -1.0;
|
||||
|
||||
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
private Double frequencyOverDayBiLi = -1.0;
|
||||
|
||||
|
||||
//电压偏差超标情况
|
||||
/**
|
||||
* 个数
|
||||
*/
|
||||
private Integer voltageMonitorNumber = 0;
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> voltageMonitorList = new ArrayList<>();;
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double voltageBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double voltageDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
@@ -65,10 +88,19 @@ public class OverAreaLimitVO {
|
||||
* 个数
|
||||
*/
|
||||
private Integer harmonicVoltageMonitorNumber = 0;
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> harmonicVoltageMonitorList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double harmonicVoltageBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double harmonicVoltageDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
@@ -79,10 +111,18 @@ public class OverAreaLimitVO {
|
||||
* 个数
|
||||
*/
|
||||
private Integer harmonicCurrentMonitorNumber = 0;
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> harmonicCurrentMonitorList = new ArrayList<>();;
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double harmonicCurrentBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double harmonicCurrentDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
@@ -93,10 +133,18 @@ public class OverAreaLimitVO {
|
||||
* 个数
|
||||
*/
|
||||
private Integer threePhaseVoltageMonitorNumber = 0;
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> threePhaseVoltageMonitorList = new ArrayList<>();;
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double threePhaseVoltageBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double threePhaseVoltageDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
@@ -107,10 +155,18 @@ public class OverAreaLimitVO {
|
||||
* 个数
|
||||
*/
|
||||
private Integer flickerMonitorNumber = 0;
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> flickerMonitorList = new ArrayList<>();;
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double flickerBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double flickerDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
@@ -125,6 +181,10 @@ public class OverAreaLimitVO {
|
||||
* 占比
|
||||
*/
|
||||
private Double negativeBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double negativeDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
@@ -139,8 +199,48 @@ public class OverAreaLimitVO {
|
||||
* 占比
|
||||
*/
|
||||
private Double interHarmonicBiLi = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double interHarmonicDayAvgBiLi = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
private Double interHarmonicOverDayBiLi = -1.0;
|
||||
|
||||
|
||||
|
||||
private List<InnerHarmV> innerHarmVList;
|
||||
|
||||
|
||||
private List<InnerHarmV> innerHarmIList;
|
||||
|
||||
|
||||
@Data
|
||||
public static class InnerHarmV{
|
||||
|
||||
private String name;
|
||||
//谐波电压超标情况
|
||||
/**
|
||||
* 个数
|
||||
*/
|
||||
private Integer limitCount = 0;
|
||||
/**
|
||||
* 超标监测点集合,区域报告使用
|
||||
*/
|
||||
private List<String> limitIdList;
|
||||
|
||||
/**
|
||||
* 占比
|
||||
*/
|
||||
private Double limitRate = -1.0;
|
||||
/**
|
||||
* 日均超标占比
|
||||
*/
|
||||
private Double dayAvg = -1.0;
|
||||
/**
|
||||
* 平均超标天数
|
||||
*/
|
||||
private Double dayLimit = -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,4 +31,7 @@ public class OverAreaVO extends DeviceInfoParam.BusinessParam{
|
||||
@Range(min = 1,message = "条数必须大于0")
|
||||
private Integer pageSize;
|
||||
|
||||
@ApiModelProperty("1.报告标志")
|
||||
private Integer areaReportFlag;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
package com.njcn.harmonic.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.njcn.harmonic.pojo.dto.report.TableMergeRule;
|
||||
import com.njcn.oss.constant.OssPath;
|
||||
import com.njcn.oss.utils.FileStorageUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.xwpf.usermodel.*;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -26,7 +29,13 @@ public class WordUtil2 {
|
||||
private final FileStorageUtil fileStorageUtil;
|
||||
|
||||
|
||||
public void getWord(String path, Map<String, Object> params, String fileName,List<List<String[]>> tableList, HttpServletResponse response)
|
||||
// 保留原有getWord方法(兼容旧调用,无合并规则时直接执行)
|
||||
public void getWord(String path, Map<String, Object> params, String fileName,
|
||||
List<List<String[]>> tableList, HttpServletResponse response) throws Exception {
|
||||
this.getWord(path, params, fileName, tableList, null, response);
|
||||
}
|
||||
|
||||
public void getWord(String path, Map<String, Object> params, String fileName,List<List<String[]>> tableList,List<TableMergeRule> mergeRules, HttpServletResponse response)
|
||||
throws Exception {
|
||||
path = ClearPathUtil.cleanString(path);
|
||||
InputStream inStream = null;
|
||||
@@ -35,20 +44,29 @@ public class WordUtil2 {
|
||||
try {
|
||||
inStream = new ClassPathResource(path).getInputStream();;
|
||||
doc = new CustomXWPFDocument(inStream);
|
||||
// 替换表格里面的变量
|
||||
if(CollUtil.isNotEmpty(tableList)){
|
||||
this.replaceInTable(doc, params,tableList);
|
||||
}else{
|
||||
this.replaceInTable(doc, params);
|
||||
}
|
||||
// 替换表格里面的变量
|
||||
this.replaceInPara(doc, params); // 替换文本里面的变量
|
||||
// 替换文本里面的变量
|
||||
this.replaceInPara(doc, params);
|
||||
|
||||
//新增:执行动态合并规则
|
||||
if(CollUtil.isNotEmpty(mergeRules)) {
|
||||
this.dynamicMergeTables(doc, mergeRules);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
getError("获取报告模板异常,原因为:" + e);
|
||||
} finally {
|
||||
if (null != inStream) {
|
||||
inStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
@@ -223,6 +241,74 @@ public class WordUtil2 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* public static void processParagraphs(List<XWPFParagraph> paragraphList, Map<String, Object> param,
|
||||
CustomXWPFDocument doc) {
|
||||
if (paragraphList != null && !paragraphList.isEmpty()) {
|
||||
for (XWPFParagraph paragraph : paragraphList) {
|
||||
// 先获取整个段落的完整文本
|
||||
String fullText = paragraph.getText();
|
||||
|
||||
// 检查是否包含变量
|
||||
boolean hasVariable = false;
|
||||
for (String key : param.keySet()) {
|
||||
if (fullText.contains(key)) {
|
||||
hasVariable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasVariable) {
|
||||
// 进行变量替换
|
||||
String replacedText = fullText;
|
||||
boolean hasImage = false;
|
||||
|
||||
for (Entry<String, Object> entry : param.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (replacedText.contains(key)) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof String) {
|
||||
replacedText = replacedText.replace(key, value.toString());
|
||||
} else if (value instanceof Map) {
|
||||
// 处理图片:需要特殊处理
|
||||
hasImage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasImage) {
|
||||
// 如果没有图片,直接替换整个段落文本
|
||||
// 清空原有 Runs
|
||||
List<XWPFRun> runs = paragraph.getRuns();
|
||||
for (int i = runs.size() - 1; i >= 0; i--) {
|
||||
paragraph.removeRun(i);
|
||||
}
|
||||
|
||||
// 创建新的 Run
|
||||
XWPFRun newRun = paragraph.createRun();
|
||||
newRun.setText(replacedText);
|
||||
} else {
|
||||
// 有图片的情况:逐个 Run 处理(保留原逻辑)
|
||||
List<XWPFRun> runs = paragraph.getRuns();
|
||||
for (XWPFRun run : runs) {
|
||||
String text = run.getText(0);
|
||||
if (text != null) {
|
||||
for (Entry<String, Object> entry : param.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (text.contains(key)) {
|
||||
// ... 原图片处理逻辑
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* 替换段落里面的变量
|
||||
*
|
||||
@@ -292,33 +378,6 @@ public class WordUtil2 {
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 为表格插入数据,行数不够添加新行
|
||||
*
|
||||
* @param table 需要插入数据的表格
|
||||
* @param tableList 插入数据集合
|
||||
*/
|
||||
private static void insertTable(XWPFTable table, List<String[]> tableList) {
|
||||
//删除占位符行数
|
||||
table.removeRow(1);
|
||||
if (CollUtil.isNotEmpty(tableList)) {
|
||||
// 创建行,根据需要插入的数据添加新行,不处理表头
|
||||
for (int i = 0; i < tableList.size(); i++) {
|
||||
XWPFTableRow row = table.createRow();
|
||||
List<XWPFTableCell> cells = row.getTableCells();
|
||||
for (int j = 0; j < cells.size(); j++) {
|
||||
String s = tableList.get(i)[j];
|
||||
XWPFTableCell cell = cells.get(j);
|
||||
cell.removeParagraph(0);
|
||||
XWPFParagraph paragraph = cell.addParagraph();
|
||||
paragraph.setAlignment(ParagraphAlignment.CENTER);
|
||||
// 在段落中添加文本
|
||||
XWPFRun run = paragraph.createRun();
|
||||
run.setText(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换表格里面的变量
|
||||
@@ -350,6 +409,7 @@ public class WordUtil2 {
|
||||
}else {
|
||||
if (CollUtil.isNotEmpty(tableList.get(num))){
|
||||
insertTable(table, tableList.get(num)); // 插入数据
|
||||
|
||||
}
|
||||
num++;
|
||||
}
|
||||
@@ -357,6 +417,53 @@ public class WordUtil2 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为表格插入数据,行数不够添加新行
|
||||
*
|
||||
* @param table 需要插入数据的表格
|
||||
* @param tableList 插入数据集合
|
||||
*/
|
||||
private static void insertTable(XWPFTable table, List<String[]> tableList) {
|
||||
//删除占位符行数
|
||||
table.removeRow(1);
|
||||
if (CollUtil.isNotEmpty(tableList)) {
|
||||
// 创建行,根据需要插入的数据添加新行,不处理表头
|
||||
for (int i = 0; i < tableList.size(); i++) {
|
||||
XWPFTableRow row = table.createRow();
|
||||
List<XWPFTableCell> cells = row.getTableCells();
|
||||
String[] rowData = tableList.get(i);
|
||||
|
||||
for (int j = 0; j < cells.size(); j++) {
|
||||
String s = tableList.get(i)[j];
|
||||
XWPFTableCell cell = cells.get(j);
|
||||
cell.removeParagraph(0);
|
||||
XWPFParagraph paragraph = cell.addParagraph();
|
||||
paragraph.setAlignment(ParagraphAlignment.CENTER);
|
||||
// 在段落中添加文本
|
||||
XWPFRun run = paragraph.createRun();
|
||||
// 处理普通数据
|
||||
if (j < rowData.length && !rowData[j].startsWith("merge:")) {
|
||||
run.setText(rowData[j] == null ? "" : rowData[j]);
|
||||
}
|
||||
// 处理合并配置
|
||||
else if (j < rowData.length && rowData[j].startsWith("merge:")) {
|
||||
String[] mergeParams = rowData[j].replace("merge:", "").split(",");
|
||||
int rowMerge = Integer.parseInt(mergeParams[0]);
|
||||
int colMerge = Integer.parseInt(mergeParams[1]);
|
||||
// 调用合并方法
|
||||
setCellMerge(cell, rowMerge, colMerge);
|
||||
// 清空跨列后续单元格
|
||||
for (int k = j + 1; k < j + colMerge && k < cells.size(); k++) {
|
||||
cells.get(k).removeParagraph(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 正则匹配字符串
|
||||
*
|
||||
@@ -398,4 +505,144 @@ public class WordUtil2 {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 适配 POI 4.1.1 的单元格合并核心方法
|
||||
* @param cell 要合并的单元格
|
||||
* @param rowMerge 纵向合并行数(1=不合并,>1=合并行数)
|
||||
* @param colMerge 横向合并列数(1=不合并,>1=合并列数)
|
||||
*/
|
||||
private static void setCellMerge(XWPFTableCell cell, int rowMerge, int colMerge) {
|
||||
CTTc ctTc = cell.getCTTc();
|
||||
CTTcPr tcPr = ctTc.getTcPr() == null ? ctTc.addNewTcPr() : ctTc.getTcPr();
|
||||
tcPr.addNewVAlign().setVal(STVerticalJc.CENTER);
|
||||
|
||||
// 1. 横向合并(跨列)- POI 4.1.1 写法
|
||||
if (colMerge > 1) {
|
||||
// 直接创建 gridSpan 并设置值
|
||||
tcPr.addNewGridSpan().setVal(BigInteger.valueOf(colMerge));
|
||||
}
|
||||
|
||||
// 2. 纵向合并(跨行)- POI 4.1.1 写法
|
||||
if (rowMerge > 1) {
|
||||
// 起始单元格标记为 RESTART
|
||||
tcPr.addNewVMerge().setVal(STMerge.RESTART);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 适配 POI 4.1.1 的表格单元格合并工具方法
|
||||
* @param table Word表格对象
|
||||
* @param rowIndex 行索引(从0开始)
|
||||
* @param colIndex 列索引(从0开始)
|
||||
* @param mergeRows 跨行数(如2表示合并当前行和下一行)
|
||||
* @param mergeCols 跨列数(如2表示合并当前列和下一列)
|
||||
*/
|
||||
public static void mergeTableCell(XWPFTable table, int rowIndex, int colIndex, int mergeRows, int mergeCols) {
|
||||
// 参数校验
|
||||
if (table == null || rowIndex < 0 || colIndex < 0 || mergeRows < 1 || mergeCols < 1) {
|
||||
log.error("表格合并参数无效:行{} 列{} 跨行{} 跨列{}", rowIndex, colIndex, mergeRows, mergeCols);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取目标行和单元格
|
||||
XWPFTableRow targetRow = table.getRow(rowIndex);
|
||||
if (targetRow == null) {
|
||||
log.error("指定行不存在:{}", rowIndex);
|
||||
return;
|
||||
}
|
||||
XWPFTableCell targetCell = targetRow.getCell(colIndex);
|
||||
if (targetCell == null) {
|
||||
log.error("指定列不存在:{}", colIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置起始单元格的合并属性
|
||||
setCellMerge(targetCell, mergeRows, mergeCols);
|
||||
|
||||
// 处理跨行合并的后续单元格(标记为 CONTINUE)
|
||||
for (int i = rowIndex + 1; i < rowIndex + mergeRows; i++) {
|
||||
XWPFTableRow row = table.getRow(i);
|
||||
if (row == null) break;
|
||||
|
||||
XWPFTableCell cell = row.getCell(colIndex);
|
||||
if (cell == null) continue;
|
||||
|
||||
CTTc ctTc = cell.getCTTc();
|
||||
CTTcPr tcPr = ctTc.getTcPr() == null ? ctTc.addNewTcPr() : ctTc.getTcPr();
|
||||
// 后续单元格标记为 CONTINUE
|
||||
tcPr.addNewVMerge().setVal(STMerge.CONTINUE);
|
||||
}
|
||||
|
||||
// 处理跨列合并的后续单元格(清空并标记为 CONTINUE)
|
||||
for (int j = colIndex + 1; j < colIndex + mergeCols; j++) {
|
||||
XWPFTableCell cell = targetRow.getCell(j);
|
||||
if (cell == null) break;
|
||||
|
||||
CTTc ctTc = cell.getCTTc();
|
||||
CTTcPr tcPr = ctTc.getTcPr() == null ? ctTc.addNewTcPr() : ctTc.getTcPr();
|
||||
tcPr.addNewVMerge().setVal(STMerge.CONTINUE);
|
||||
// 清空跨列后续单元格的内容
|
||||
cell.removeParagraph(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ========== 新增:动态合并核心方法 ==========
|
||||
/**
|
||||
* 动态执行多个表格的合并规则
|
||||
* @param doc Word文档对象
|
||||
* @param mergeRules 合并规则列表
|
||||
*/
|
||||
public void dynamicMergeTables(CustomXWPFDocument doc, List<TableMergeRule> mergeRules) {
|
||||
// 遍历文档中的所有表格,按规则合并
|
||||
Iterator<XWPFTable> tableIterator = doc.getTablesIterator();
|
||||
int currentTableIndex = 0; // 当前遍历到的表格索引(从0开始)
|
||||
while (tableIterator.hasNext()) {
|
||||
XWPFTable table = tableIterator.next();
|
||||
// 查找当前表格是否有匹配的合并规则
|
||||
for (TableMergeRule rule : mergeRules) {
|
||||
if (rule.isEnable() && rule.getTableIndex().equals(currentTableIndex)) {
|
||||
// 执行该表格的合并规则
|
||||
mergeTableByRule(table, rule);
|
||||
break; // 一个表格只执行一条规则,避免重复处理
|
||||
}
|
||||
}
|
||||
currentTableIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据单条规则合并指定表格(支持指定起始行)
|
||||
* @param table 要合并的表格
|
||||
* @param rule 合并规则
|
||||
*/
|
||||
private void mergeTableByRule(XWPFTable table, TableMergeRule rule) {
|
||||
if (table == null || rule == null || !rule.isEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int totalRows = table.getRows().size();
|
||||
int mergeCol = rule.getMergeColIndex();
|
||||
int startRow = rule.getStartRow(); // 新增:获取指定的起始行
|
||||
int mergeRowsPerGroup = rule.getMergeRowsPerGroup();
|
||||
|
||||
// 参数校验:起始行不能大于总行数、行数不足、列索引非法、合并行数小于2
|
||||
if (startRow >= totalRows || totalRows < 2 || mergeCol < 0 || mergeRowsPerGroup < 2) {
|
||||
log.warn("表格{}合并规则无效:总行数{} 起始行{} 合并列{} 每组行数{}",
|
||||
rule.getTableIndex(), totalRows, startRow, mergeCol, mergeRowsPerGroup);
|
||||
return;
|
||||
}
|
||||
|
||||
// 核心改动:从startRow开始,每mergeRowsPerGroup行合并一组
|
||||
for (int currentStart = startRow; currentStart < totalRows; currentStart += mergeRowsPerGroup) {
|
||||
// 最后一组可能不足N行,取实际行数
|
||||
int actualMergeRows = Math.min(mergeRowsPerGroup, totalRows - currentStart);
|
||||
// 复用原有mergeTableCell方法执行合并
|
||||
mergeTableCell(table, currentStart, mergeCol, actualMergeRows, 1);
|
||||
}
|
||||
log.info("表格{}合并完成:第{}列 从第{}行开始 每{}行合并一次",
|
||||
rule.getTableIndex(), mergeCol, startRow, mergeRowsPerGroup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user