报表引出 Excel 所见即所得(支持内容单元格融合)原创
金蝶云社区-周立思
周立思
5人赞赏了该文章 688次浏览 未经作者许可,禁止转载编辑于2024年02月02日 16:43:25

需求

报表引出 Excel 支持列头单元格融合,不支持内容单元格融合。

思路方案

  1. 引出 Excel 操作执行 ReportView.exportExcel() -> ReportList.exportExcel()

  2. 找到处理 Excel 类 ReportList.getExcelExporter() ,内容单元格融合在这个类就可以解决,但是源码是写死的 kd.bos.mvc.export.GridExcelExporter。

  3. 参考 GridExcelExporter 源码修改实现内容单元格融合

  4. 参考 ReportView 和 ReportList 实现引出操作功能

实现步骤

1.参考GridExcelExporter 源码编写内容单元融合功能

GridExcelExporter.createBodyColumn() 处理内容区域生成,同时单元格合并使用 SXSSFSheet.addMergedRegion(CellRangeAddress region) 。基于这两部分,在 GridExcelExporter.setCellValueAndStyle() 判断需要合并的单元格添加到待合并单元格集合中,最后在GridExcelExporter.createBodyColumn() 统一处理合并。

image.pngimage.pngimage.png


需要注意:苍穹报表单元格融合是列纵向融合,没有多列横向融合,这块简单写了一个类用于计算合并单元开始和结束索引。noMergeFieldKey 是实现按条件判断单元格融合,之前我写的一篇文章 https://developer.kingdee.com/article/416977219471536640?productLineId=29   



public class MyMergeCell {
    private final String columnName;
    private final int columnIndex;
    private final LinkedList<MergeRegion> mergeRegions = new LinkedList<>();

    public MyMergeCell(String columnName, int columnIndex) {
        this.columnName = columnName;
        this.columnIndex = columnIndex;
    }

    public void compare(int rowIndex, Object value, String noMergeFields) {
        MergeRegion lastRegion = mergeRegions.isEmpty() ? null : mergeRegions.getLast();
        if (lastRegion == null) {
            lastRegion = new MergeRegion(this.columnName);
            mergeRegions.addLast(lastRegion);
        }
        if (!lastRegion.compare(rowIndex, value, noMergeFields)) {
            mergeRegions.addLast(new MergeRegion(this.columnName, rowIndex, value, noMergeFields));
        }
    }

    public List<CellRangeAddress> createCellRanges() {
        List<CellRangeAddress> cellRanges = new ArrayList<>();
        for (MergeRegion item : mergeRegions) {
            if (item.check()) {
                cellRanges.add(new CellRangeAddress(item.beginRow, item.endRow, columnIndex, columnIndex));
            }
        }
        return cellRanges;
    }

    public static class MergeRegion {
        private String columnName;
        private String preValue;
        private int beginRow = -1;
        private int endRow = -1;

        public MergeRegion(String columnName) {
            this.columnName = columnName;
        }

        public MergeRegion(String columnName, int rowIndex, Object value, String noMergeFields) {
            this(columnName);
            compare(rowIndex, value, noMergeFields);
        }

        public boolean check() {
            if (beginRow > 0 && endRow > 0) {
                return endRow > beginRow;
            }
            return false;
        }

        public boolean compare(int rowIndex, Object value, String noMergeFields) {
            String stringValue = convertStringValue(value);
            if (this.beginRow >= 0) {
                if (StringUtils.isNotBlank(stringValue) && StringUtils.equals(this.preValue, stringValue)) {
                    if (checkNoMerge(noMergeFields)) {
                        return false;
                    }
                    this.endRow = rowIndex;
                    return true;
                } else {
                    if (this.endRow > 0) {
                        return false;
                    }
                }
            }
            this.preValue = stringValue;
            this.beginRow = rowIndex;
            this.endRow = -1;
            return true;
        }

        private boolean checkNoMerge(String noMergeFields) {
            if (StringUtils.isNotBlank(noMergeFields)) {
                if (!noMergeFields.startsWith(",")) {
                    noMergeFields = "," + noMergeFields;
                }
                if (!noMergeFields.endsWith(",")) {
                    noMergeFields = noMergeFields + ",";
                }
                return noMergeFields.indexOf("," + this.columnName + ",") >= 0;
            }
            return false;
        }

        private String convertStringValue(Object value) {
            String stringValue = value == null ? "" : String.valueOf(value);
            return stringValue;
        }
    }
}

2.参考 ReportView 和 ReportList 实现引出操作功能

这块代码比较多,大量是ReportView 和 ReportList 代码合并起来。只是增加了获取报表列表有哪些列启用了合并。下图红框中,基于报表设置列合并,需要重写报表表单插件 setMergeColums() 。


ReportList.getColumnList()
MyCustomExportExcel.getColumnList()
image.png
image.png

3.报表自定义引出操作


image.png

实现效果

Excel 内容单元格融合 Excel 按条件内容单元格融合 (noMergeFieldKey
image.pngimage.png

开发环境版本

v5.0.011

注意事项

文章内示例代码仅供参考,因为有一些对源码处理,如有需要私信我发你。

赞 5