/**
* 纵向计算生成合并单元格配置
* @param data 数据
* @return [{ "row": 0, "col": 0, "rowspan": 0, "colspan": 1 }]
*/
public static List<Map<String,Object>> mergeCells(List<Map<String,Object>> data) {
List<Map<String,Object>> mergelist = new ArrayList<>();
List<Map<String,Object>> mergelist2 = new ArrayList<>();
// 多组列计算
Map<Object,List<Map<String,Object>>> glist =data.stream().collect(Collectors.groupingBy(e -> e.get(Constant.RULE_TYPE),
LinkedHashMap::new,Collectors.toList()));
glist.forEach((key, list)->{
// 逻辑梳理,rowspan为向下合并几行,
// row 标记为向下合并从第几行开始,
// 当第一次循环时,默认从0开始,当第n次循环时,n的row= (row(上次合并前起始位置)+ rowspan(上次向下合并了几行的结果))
int row = mergelist.size() == 0 ? 0:
((int)mergelist.get(mergelist.size()-1).get(Constant.ROWS) + (int)mergelist.get(mergelist.size()-1).get(Constant.ROWSPAN));
Map<String,Object> mergeMap = createdMergeCell(row, 0, list.size(), 0);
mergelist.add(mergeMap);
// 第二列合并单元格
Map<Object,List<Map<String,Object>>> child = list.stream().collect(Collectors.groupingBy(e -> e.get(Constant.SEC_NAME1),
LinkedHashMap::new,Collectors.toList()));
child.forEach((childKey, childList)->{
int childRow = mergelist2.size() == 0 ? 0:
((int)mergelist2.get(mergelist2.size()-1).get(Constant.ROWS) + (int)mergelist2.get(mergelist2.size()-1).get(Constant.ROWSPAN));
Map<String,Object> mergeMap2 = createdMergeCell(childRow, 1, childList.size(), 0);
mergelist2.add(mergeMap2);
});
});
mergelist.addAll(mergelist2);
return mergelist;
}
/**
* 生成合并单元格配置参数
* @param row 从第几行开始
* @param col 从第几列开始
* @param rowspan 纵向合并几行
* @param colspan 横向合并几列
* @return
*/
private static Map<String,Object> createdMergeCell(int row, int col, int rowspan, int colspan) {
Map<String,Object> mergeMap = new HashMap<>();
mergeMap.put(Constant.ROWS,row);
mergeMap.put(Constant.COL,col);
mergeMap.put(Constant.ROWSPAN,rowspan);
mergeMap.put(Constant.COLSPAN,colspan);
return mergeMap;
}
/**
* 纵向计算生成合并单元格配置
* @param data 数据
* @return [{ "row": 0, "col": 0, "rowspan": 0, "colspan": 1 }]
*/
public List<Map<String,Object>> mergeCells(List<Map<String,Object>> data) {
int index = sheet.getLastRowNum() + 1; // 定义起始行
List<Map<String,Object>> mergelist = new ArrayList<>();
List<Map<String,Object>> mergelist2 = new ArrayList<>();
List<Map<String,Object>> mergelist3 = new ArrayList<>();
// 多组列计算
Map<Object,List<Map<String,Object>>> glist =data.stream().collect(Collectors.groupingBy(e -> e.get(Constant.RULE_TYPE),
LinkedHashMap::new,Collectors.toList()));
int finalIndex = index;
glist.forEach((key, list)->{
/*
逻辑梳理:
finalIndex: 为excel的最后一行,这里为计算数据合并单元格,所以finalIndex需要+1 从excel最后一行的下一行开始计算
firstCol和lastCol:程序需要excel纵向合并所以firstCol和lastCol 为相同值,代表不横向合并,比如值为0则操作ExcelA列,值为1则代表操作Excel0列
这里用mergelist存A列纵向合并数据,mergelist2存B列纵向合并数据
firstRow:
当mergelist集合中为空时,则说明为第一次循环,firstRow为表格最后一行+1(已经在程序进入前加过了),当第2+n次循环
firstRow的值为mergelist中最后一行的lastRow向下+1, 一次类推
lastRow:
结束行下标,为计算后的firstRow + 当前循环的组内数据的长度-1
*/
int firstRow0 = mergelist.size() == 0 ? finalIndex : (int)mergelist.get(mergelist.size()-1).get(Constant.LAST_ROW)+1;
Map<String,Object> mergeMap = createdMergeCell(firstRow0, 0, firstRow0 + list.size()-1, 0);
mergelist.add(mergeMap);
/*
第二列纵向合并单元格逻辑梳理:
第二列的数据完全由第一列组内的数据,根据某个字段再次分组的来的,所以要在第一列组循环体内,进行再次分组,计算第二列的合并单元格
合并单元格计算方式同上,需要一个新的集合 mergelist2 来存放组2的数据。firstCol和lastCol 置为1,操作Excel中B列。
*/
Map<Object,List<Map<String,Object>>> child = list.stream().collect(Collectors.groupingBy(e -> e.get(Constant.SEC_NAME1),
LinkedHashMap::new,Collectors.toList()));
child.forEach((childKey, childList)->{
int firstRow1 = mergelist2.size() == 0 ? finalIndex : (int)mergelist2.get(mergelist2.size()-1).get(Constant.LAST_ROW) + 1;
Map<String,Object> mergeMap2 = createdMergeCell(firstRow1, 1, firstRow1 + childList.size() -1, 1);
mergelist2.add(mergeMap2);
});
});
mergelist.addAll(mergelist2);
/*
剔除无效数据:
注意:
处理纵向合并数据,由于纵向合并为动态计算的,poi导出Excel比较严谨,结束行必须大于开始行,否则会报错。
以上循环体内无法操作,如只有一行数据,并不需要合并,
但是需要其占位,存入mergelist中,便于下次循环能够准确获取上一行的lastRow 便于计算firstRow的值。
这里将结束行小于等于开始行的数据统一剔除掉。
*/
List<Map<String,Object>> merge = mergelist.stream().filter((item)->(int)item.get(Constant.FIRST_ROW) < (int)item.get(Constant.LAST_ROW)).collect(Collectors.toList());
// 固定添加横向合并数据 Excel C列横向合并到D列
for(int i =0; i<data.size(); i++) {
Map<String,Object> mergeMap3 = createdMergeCell(index, 2, index, 4);
mergelist3.add(mergeMap3);
index++;
}
merge.addAll(mergelist3);
return merge;
}
addMerge(sheet.getLastRowNum() ,sheet.getLastRowNum(),1,4);
// 2 动态设置数据合并单元格
List<Map<String,Object>> mergeData = mergeCells(dataB);
// 2.1 批量创建合并单元格
for(Map merge : mergeData){
addMerge((int)merge.get(Constant.FIRST_ROW),(int)merge.get(Constant.LAST_ROW),(int)merge.get(Constant.FIRST_COL),(int)merge.get(Constant.LAST_COL));
}
/**
* 添加合并单元格数据
* @param firstRow 开始行 从0开始
* @param lastRow 结束行 从0开始数,
* @param firstCol 开始列 从0开始
* @param lastCol 结束列 从0开始数
*/
private void addMerge(int firstRow, int lastRow, int firstCol, int lastCol) {
sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); // 标题
}
https://vxetable.cn/v4/#/table/edit/span
<vxe-table
border
show-overflow
ref="xTable"
height="500"
:span-method="rowspanMethod"
:data="tableData"
:edit-rules="demo1.validRules"
:edit-config="{trigger: 'click', mode: 'cell'}">
// 通用行合并函数(将相同多列数据合并为一行)
const rowspanMethod: VxeTablePropTypes.SpanMethod = ({ row, _rowIndex, column, visibleData }) => {
const fields = ['role']
const cellValue = row[column.field]
if (cellValue && fields.includes(column.field)) {
const prevRow = visibleData[_rowIndex - 1]
let nextRow = visibleData[_rowIndex + 1]
if (prevRow && prevRow[column.field] === cellValue) {
return { rowspan: 0, colspan: 0 }
} else {
let countRowspan = 1
while (nextRow && nextRow[column.field] === cellValue) {
nextRow = visibleData[++countRowspan + _rowIndex]
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 }
}
}
}
}