“mitao”
2026-05-16 5426881dea603028ca53cf277f2d46bc40176a5d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.estate.expert.admin.stat.report.render;
 
import com.alibaba.fastjson.JSONObject;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
 
import java.math.BigInteger;
import java.util.List;
 
/**
 * 设备分组表格渲染策略:同一设备类型内合并类型和数量,设备类型变更时重新分组。
 */
public class DeviceGroupTablePolicy extends DynamicTableRenderPolicy {
 
    private static final int TYPE_COL = 0;
    private static final int COUNT_COL = 1;
    private static final int NUMBER_COL = 2;
 
    @Override
    public void render(XWPFTable table, Object data) {
        var groups = (List<Object>) data;
        int templateRowIndex = findTemplateRowIndex(table);
        if (templateRowIndex < 0) {
            return;
        }
 
        table.removeRow(templateRowIndex);
        if (CollectionUtils.isEmpty(groups)) {
            return;
        }
 
        int insertIndex = templateRowIndex;
        int groupStart = templateRowIndex;
        int groupSize = 0;
 
        for (Object item : groups) {
            if (!(item instanceof JSONObject group)) {
                continue;
            }
 
            boolean firstRowOfGroup = StringUtils.hasText(group.getString("设备类型"));
            XWPFTableRow row = table.insertNewTableRow(insertIndex++);
            renderRow(row, group, firstRowOfGroup);
 
            if (firstRowOfGroup) {
                mergeGroup(table, groupStart, groupSize);
                groupStart = insertIndex - 1;
                groupSize = 1;
            } else {
                groupSize++;
            }
        }
 
        mergeGroup(table, groupStart, groupSize);
    }
 
    private int findTemplateRowIndex(XWPFTable table) {
        for (int i = 0; i < table.getRows().size(); i++) {
            if (rowText(table.getRow(i)).contains("[设备编号]")) {
                return i;
            }
        }
        return -1;
    }
 
    private String rowText(XWPFTableRow row) {
        if (row == null) {
            return "";
        }
        return row.getTableCells().stream()
                .map(XWPFTableCell::getText)
                .reduce("", String::concat);
    }
 
    private void renderRow(XWPFTableRow row, JSONObject group, boolean firstRowOfGroup) {
        renderCell(row, firstRowOfGroup ? group.getString("设备类型") : "", 2972);
        renderCell(row, firstRowOfGroup ? group.getString("设备数量") : "", 1531);
        renderCell(row, group.getString("设备编号"), 4706);
    }
 
    private void renderCell(XWPFTableRow row, String text, int width) {
        XWPFTableCell cell = row.createCell();
        var tcPr = cell.getCTTc().isSetTcPr() ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
        tcPr.addNewTcW().setW(BigInteger.valueOf(width));
        tcPr.getTcW().setType(STTblWidth.DXA);
        tcPr.addNewGridSpan().setVal(BigInteger.valueOf(2));
        tcPr.addNewVAlign().setVal(STVerticalJc.CENTER);
 
        var borders = tcPr.addNewTcBorders();
        borders.addNewTop().setVal(STBorder.SINGLE);
        borders.addNewBottom().setVal(STBorder.SINGLE);
        borders.addNewLeft().setVal(STBorder.SINGLE);
        borders.addNewRight().setVal(STBorder.SINGLE);
        borders.getTop().setColor("000000");
        borders.getBottom().setColor("000000");
        borders.getLeft().setColor("000000");
        borders.getRight().setColor("000000");
        borders.getTop().setSz(BigInteger.valueOf(4));
        borders.getBottom().setSz(BigInteger.valueOf(4));
        borders.getLeft().setSz(BigInteger.valueOf(4));
        borders.getRight().setSz(BigInteger.valueOf(4));
 
        var paragraph = cell.getParagraphs().get(0);
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        var run = paragraph.createRun();
        run.setFontFamily("黑体");
        run.setFontSize(12);
        run.setText(text == null ? "" : text);
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
    }
 
    private void mergeGroup(XWPFTable table, int groupStart, int groupSize) {
        if (groupSize <= 1) {
            return;
        }
        TableTools.mergeCellsVertically(table, TYPE_COL, groupStart, groupStart + groupSize - 1);
        TableTools.mergeCellsVertically(table, COUNT_COL, groupStart, groupStart + groupSize - 1);
    }
}