el-table树形表格合并相同的值
<style lang="scss" scoped>
.tableBox {
/deep/ &.el-table th:first-child,
/deep/ &.el-table td:first-child {
padding-left: 0;
}
}
</style>
<template>
<div>
<el-table
class="tableBox"
row-key="uniID"
ref="refTable"
:data="tableData"
style="width: 100%"
border
:span-method="arraySpanMethod"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column prop="dateTime" label="时间" key="dateTime" min-width="140">
<template slot-scope="{ row }">
{{ row.groupNo ? findValue(row.groupNo, groupNoList) : row.dateTime }}
</template>
</el-table-column>
<el-table-column prop="yieldConsume" label="产量(t)" key="yieldConsume" min-width="110" />
</el-table>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
interface TableRow {
uniID: number;
dateTime: string;
groupNo: number | null;
yieldConsume: number;
children?: TableRow[];
parent?: TableRow | null;
// 新增预处理字段
spanInfo?: {
rowspan: number;
hidden: boolean;
};
}
@Component({})
export default class EnergyAnalysis extends Vue {
private tableData: TableRow[] = [];
private groupNoList: any = [
{
value: '甲',
key: 1,
},
{
value: '乙',
key: 2,
},
{
value: '丙',
key: 3,
},
{
value: '丁',
key: 4,
},
];
private testData = {
data: {
everyDetail: [
{
dateTime: '2025-03-01',
groupNo: null,
yieldConsume: -30176.691,
children: [
{
dateTime: '2025-03-01',
groupNo: 1,
yieldConsume: 100,
children: null,
},
{
dateTime: '2025-03-01',
groupNo: 1,
yieldConsume: -18885.714,
children: null,
},
{
dateTime: '2025-03-01',
groupNo: 2,
yieldConsume: 100,
children: null,
},
{
dateTime: '2025-03-01',
groupNo: 2,
yieldConsume: 101,
children: null,
},
{
dateTime: '2025-03-01',
groupNo: 2,
yieldConsume: 102,
children: null,
},
],
},
{
dateTime: '2025-03-02',
groupNo: null,
yieldConsume: -30176.691,
children: [
{
dateTime: '2025-03-02',
groupNo: 1,
yieldConsume: 111,
children: null,
},
],
},
],
},
};
created() {
this.statisticsQuery();
}
private findValue(data: any, list: any) {
const a = list.find((el: any) => el.key === data);
return a ? a.value : '-';
}
private async statisticsQuery() {
let index = 1;
const recursionList = (list: any[], parent: TableRow | null = null): TableRow[] => {
return list?.map((v: any) => {
const newRow: TableRow = {
...v,
uniID: index++,
parent: parent,
spanInfo: { rowspan: 1, hidden: false }, // 初始化合并信息
};
// 预处理子节点的合并信息
if (newRow.children) {
newRow.children = recursionList(newRow.children, newRow);
this.preCalculateSpan(newRow.children); // 关键优化点
}
return newRow;
});
};
const data = this.testData;
this.tableData = recursionList(data.data?.everyDetail);
this.$nextTick(() => {
(this.$refs as any).refTable.doLayout();
});
}
/**
* 预处理合并信息 (核心优化逻辑)
* @param children - 子节点列表,包含需要进行合并处理的行数据。
*/
preCalculateSpan(children: TableRow[]) {
let pos = 0; // 当前处理的位置指针
while (pos < children.length) {
// 遍历所有子节点
const current = children[pos]; // 当前处理的行
if (current.groupNo == null) {
// 如果当前行没有组编号,则跳过
pos++;
continue;
}
// 向后查找相同 groupNo 的数量
let sameCount = 1; // 初始化相同组编号的数量为1(包括当前行)
for (let i = pos + 1; i < children.length; i++) {
// 从下一个元素开始查找
if (children[i].groupNo === current.groupNo) {
// 如果发现相同组编号
sameCount++; // 增加计数
} else {
break; // 一旦遇到不同的组编号,停止查找
}
}
// 更新合并信息
current.spanInfo = { rowspan: sameCount, hidden: false }; // 设置当前行为合并起始行
for (let j = pos + 1; j < pos + sameCount; j++) {
// 对于后续的相同组编号的行
children[j].spanInfo = { rowspan: 0, hidden: true }; // 标记这些行为隐藏状态,不需要显示
}
pos += sameCount; // 移动位置指针,跳过已处理的行
}
}
/**
* 合并方法直接使用预处理结果
* @param param - 包含 row(当前行数据)、column(当前列配置)、columnIndex(当前列索引)的对象。
* @returns 返回一个对象,指定当前单元格的 rowspan 和 colspan。
*/
arraySpanMethod({ row, column, columnIndex }: any) {
// 只对第一列应用合并规则
if (columnIndex === 0 && row.spanInfo) {
return {
rowspan: row.spanInfo.rowspan, // 根据预处理结果设置行跨度
colspan: row.spanInfo.hidden ? 0 : 1, // 如果该行被标记为隐藏,则设置 colspan 为 0
};
}
// 默认情况下,每个单元格的 rowspan 和 colspan 都为 1
return { rowspan: 1, colspan: 1 };
}
}
</script>