Browse Source

word模板导出demov4

aqm-ops-supervision-platform
gjh 2 weeks ago
parent
commit
e9e5c4780f
  1. 100
      ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/WordReportExporter.java

100
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/WordReportExporter.java

@ -129,33 +129,40 @@ public class WordReportExporter {
}
private static void addScoreTable(XWPFDocument document, ReportData reportData) {
private static void addScoreTable(XWPFDocument document, ReportData reportData) {
List<CheckItem> items = reportData.getCheckItems();
if (items == null || items.isEmpty()) return;
// ✅ 1. 创建表格
XWPFTable table = document.createTable();
// ✅ 2. 设置表格宽度
// ✅ 2. 设置表格宽度 (9000 TWIP ≈ 页面宽度)
CTTblPr tblPr = table.getCTTbl().getTblPr();
CTTblWidth tblWidth = tblPr.addNewTblW();
tblWidth.setW(BigInteger.valueOf(9000));
tblWidth.setType(STTblWidth.DXA);
// ✅ 3. 强制第一行有 5 列(必须!否则 createRow 后 getCell 越界)
// ✅ 3. 强制第一行有 5 列
XWPFTableRow header = table.getRow(0);
for (int i = 1; i < 5; i++) {
header.addNewTableCell();
}
// ✅ 4. 设置表头文本和样式(不要提前操作 TcPr)
// ✅ 4. 设置表头文本和样式
setCellTextAndStyle(header.getCell(0), "检查项目", true);
setCellTextAndStyle(header.getCell(1), "检查要点", true);
setCellTextAndStyle(header.getCell(2), "单项分值", true);
setCellTextAndStyle(header.getCell(3), "得分", true);
setCellTextAndStyle(header.getCell(4), "评分说明", true);
// ✅ 5. 分组数据
// ✅ 5. 设置列宽(关键:20% / 35% / 10% / 10% / 25%)
setCellWidth(header.getCell(0), 1500); // 检查项目
setCellWidth(header.getCell(1), 2800); // 检查要点
setCellWidth(header.getCell(2), 950); // 单项分值(窄)
setCellWidth(header.getCell(3), 950); // 得分(窄)
setCellWidth(header.getCell(4), 2200); // 评分说明
// ✅ 6. 分组数据
Map<String, List<CheckItem>> grouped = items.stream()
.sorted(Comparator.comparing(CheckItem::getCheckProject))
.collect(Collectors.groupingBy(
@ -172,29 +179,28 @@ public class WordReportExporter {
for (int i = 0; i < groupItems.size(); i++) {
CheckItem item = groupItems.get(i);
XWPFTableRow row = table.createRow(); // ✅ 自动 5 列
XWPFTableRow row = table.createRow();
// ✅ 先设置文本和样式
// 设置内容
setCellTextAndStyle(row.getCell(1), item.formatCheckItem(), false);
setCellTextAndStyle(row.getCell(2), String.valueOf(item.getItemScore()), false);
setCellTextAndStyle(row.getCell(3), String.valueOf(item.getObtainedScore()), false);
setCellTextAndStyle(row.getCell(4), item.formatScoringExplanation(), false);
// ✅ 累加
// ✅ 累加
totalScore += item.getObtainedScore();
// ✅ 再设置第0列的合并
// 设置第0列(检查项目)及垂直合并
XWPFTableCell cell = row.getCell(0);
setCellTextAndStyle(cell, i == 0 ? project : "", i == 0); // 只有第一行显示项目名
setCellTextAndStyle(cell, i == 0 ? project : "", i == 0);
// ✅ 最后设置垂直合并
CTTcPr tcPr = cell.getCTTc().addNewTcPr(); // ✅ 这里可以 addNew,因为 setCellTextAndStyle 已完成
CTTcPr tcPr = cell.getCTTc().addNewTcPr();
CTVMerge merge = tcPr.addNewVMerge();
merge.setVal(i == 0 ? STMerge.RESTART : STMerge.CONTINUE);
}
}
// ✅ 6. 总分行
// ✅ 7. 总分行
XWPFTableRow totalRow = table.createRow();
XWPFTableCell labelCell = totalRow.getCell(0);
setCellTextAndStyle(labelCell, "总分", true);
@ -202,11 +208,11 @@ public class WordReportExporter {
XWPFTableCell scoreCell = totalRow.getCell(1);
setCellTextAndStyle(scoreCell, String.valueOf(totalScore), true);
// 合并第1~4列(共4列)
// 合并第1~4列(共4列)
CTTcPr tcPr = scoreCell.getCTTc().addNewTcPr();
tcPr.addNewGridSpan().setVal(BigInteger.valueOf(4));
// ✅ 清空后面单元格(可选
// 清空后面单元格(避免显示多余文本
for (int i = 2; i <= 4; i++) {
XWPFTableCell cell = totalRow.getCell(i);
if (cell != null) {
@ -215,29 +221,57 @@ public class WordReportExporter {
}
}
private static void setCellTextAndStyle(XWPFTableCell cell, String text, boolean isHeader) {
// 1. 先设置文本(✅ 支持 \n 换行)
cell.setText(text);
// 2. 获取或创建单元格属性,设置宽度
// ✅ 辅助方法:设置单元格宽度
private static void setCellWidth(XWPFTableCell cell, int width) {
CTTc ctTc = cell.getCTTc();
CTTcPr tcPr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
CTTblWidth tcW = tcPr.getTcW() != null ? tcPr.getTcW() : tcPr.addNewTcW();
tcW.setW(BigInteger.valueOf(2000));
tcW.setType(STTblWidth.DXA); // 推荐设置单位
// 3. 遍历所有段落和 Run,设置样式
for (XWPFParagraph p : cell.getParagraphs()) {
p.setSpacingAfter(50); // 段后间距
for (XWPFRun r : p.getRuns()) {
r.setFontFamily("宋体");
r.setFontSize(10);
if (isHeader) {
r.setBold(true);
}
CTTblWidth tcW = tcPr.isSetTcW() ? tcPr.getTcW() : tcPr.addNewTcW();
tcW.setW(BigInteger.valueOf(width));
tcW.setType(STTblWidth.DXA);
}
private static void setCellTextAndStyle(XWPFTableCell cell, String text, boolean isHeader) {
cell.removeParagraph(0);
XWPFParagraph p = cell.addParagraph();
p.setAlignment(isHeader ? ParagraphAlignment.CENTER : ParagraphAlignment.LEFT);
p.setSpacingAfter(0);
p.setSpacingBefore(0);
String[] lines = (text == null ? "" : text).split("\n", -1); // 保留末尾空行
for (int i = 0; i < lines.length; i++) {
if (i > 0) {
p.createRun().addCarriageReturn();
}
XWPFRun run = p.createRun();
run.setText(lines[i]);
run.setBold(isHeader);
run.setFontSize(10);
run.setFontFamily("等线");
}
}
// private static void setCellTextAndStyle(XWPFTableCell cell, String text, boolean isHeader) {
// // 1. 先设置文本(✅ 支持 \n 换行)
// cell.setText(text);
//
// // 2. 获取或创建单元格属性,设置宽度
// CTTc ctTc = cell.getCTTc();
// CTTcPr tcPr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();
// CTTblWidth tcW = tcPr.getTcW() != null ? tcPr.getTcW() : tcPr.addNewTcW();
// tcW.setW(BigInteger.valueOf(2000));
// tcW.setType(STTblWidth.DXA); // 推荐设置单位
//
// // 3. 遍历所有段落和 Run,设置样式
// for (XWPFParagraph p : cell.getParagraphs()) {
// p.setSpacingAfter(50); // 段后间距
// for (XWPFRun r : p.getRuns()) {
// r.setFontFamily("宋体");
// r.setFontSize(10);
// if (isHeader) {
// r.setBold(true);
// }
// }
// }
// }
private static void addTotalAndRemarks(XWPFDocument document, ReportData reportData) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

Loading…
Cancel
Save