vue使用a-table设置自定义合并字段实现某字段值相同则合并行
背景:
笔者前端使用ant-design-vue,二次开发了a-table,但a-table组件的属性方法都可以用;
业务需求:物资存放在不同的仓库,显示物资统计表格,以物资分组合并显示物资名称、总数量(物资A在所有库房总数量),同时显示库房名称、地址、数量(物资A在库房1的数量)。
后端返回数据结构:
[
{
"sumQuantity": 100,
"id": "IMilokafkwdIAmWmrlAjLX",
"version": 1,
"materialId": "1",
"quantity": 0,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 13:15:00",
"materialName": "沙袋",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101"
},
{
"sumQuantity": 100,
"id": "D0TpUNP3oF6J8DGFVBDX1v",
"version": 0,
"materialId": "1",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "沙袋",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋"
},
{
"sumQuantity": 100,
"id": "BRmOAec1CbeKTnnnmwefxF",
"version": 0,
"materialId": "3",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "铁锹",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋"
},
{
"sumQuantity": 101,
"id": "JGGKndrPSaVIlvDL8tG3Ea",
"version": 0,
"materialId": "BtjEnxJslGMG3Ns3ZMtcVi",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "C",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋"
},
{
"sumQuantity": 101,
"id": "F7GtvxU2hY8HqPHF90AMpn",
"version": 3,
"materialId": "BtjEnxJslGMG3Ns3ZMtcVi",
"quantity": 1,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 13:15:00",
"materialName": "C",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101"
},
{
"sumQuantity": 104,
"id": "FNgj4RPi1tiGzKebbr4rar",
"version": 2,
"materialId": "E6Sdqv1JjR4HOzExdR2pi1",
"quantity": 4,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 13:15:00",
"materialName": "物资B",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101"
},
{
"sumQuantity": 104,
"id": "KzS27athAsOGPLGviZk4OF",
"version": 0,
"materialId": "E6Sdqv1JjR4HOzExdR2pi1",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "物资B",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋"
},
{
"sumQuantity": 104,
"id": "KQ6z4WBmWmQJPvVQE9Px2G",
"version": 0,
"materialId": "Ki7FlrYpS9UGpQcSyeZYap",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "E",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋"
},
{
"sumQuantity": 104,
"id": "JM3W9JYTNYSItMBLxDOUBf",
"version": 1,
"materialId": "Ki7FlrYpS9UGpQcSyeZYap",
"quantity": 4,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 08:44:18",
"materialName": "E",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101"
}
]
执行this.convertData(xxxData)后的数据结构为
[
{
"sumQuantity": 100,
"id": "IMilokafkwdIAmWmrlAjLX",
"version": 1,
"materialId": "1",
"quantity": 0,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 13:15:00",
"materialName": "沙袋",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 2,
"materialNameRowSpan": 2
},
{
"sumQuantity": 100,
"id": "D0TpUNP3oF6J8DGFVBDX1v",
"version": 0,
"materialId": "1",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "沙袋",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 0,
"materialNameRowSpan": 0
},
{
"sumQuantity": 100,
"id": "BRmOAec1CbeKTnnnmwefxF",
"version": 0,
"materialId": "3",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "铁锹",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 1,
"materialNameRowSpan": 1
},
{
"sumQuantity": 101,
"id": "JGGKndrPSaVIlvDL8tG3Ea",
"version": 0,
"materialId": "BtjEnxJslGMG3Ns3ZMtcVi",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "C",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 2,
"materialNameRowSpan": 2
},
{
"sumQuantity": 101,
"id": "F7GtvxU2hY8HqPHF90AMpn",
"version": 3,
"materialId": "BtjEnxJslGMG3Ns3ZMtcVi",
"quantity": 1,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 13:15:00",
"materialName": "C",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 0,
"materialNameRowSpan": 0
},
{
"sumQuantity": 104,
"id": "FNgj4RPi1tiGzKebbr4rar",
"version": 2,
"materialId": "E6Sdqv1JjR4HOzExdR2pi1",
"quantity": 4,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 13:15:00",
"materialName": "物资B",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 2,
"materialNameRowSpan": 2
},
{
"sumQuantity": 104,
"id": "KzS27athAsOGPLGviZk4OF",
"version": 0,
"materialId": "E6Sdqv1JjR4HOzExdR2pi1",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "物资B",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 0,
"materialNameRowSpan": 0
},
{
"sumQuantity": 104,
"id": "KQ6z4WBmWmQJPvVQE9Px2G",
"version": 0,
"materialId": "Ki7FlrYpS9UGpQcSyeZYap",
"quantity": 100,
"warehouseId": "IBU9sfUgWhcG0RglQB8urC",
"updateTime": "2025-02-28 10:51:51",
"materialName": "E",
"warehouseName": "产业园3号4栋",
"warehouseAddress": "产业园3号4栋",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 2,
"materialNameRowSpan": 2
},
{
"sumQuantity": 104,
"id": "JM3W9JYTNYSItMBLxDOUBf",
"version": 1,
"materialId": "Ki7FlrYpS9UGpQcSyeZYap",
"quantity": 4,
"warehouseId": "IQotvqjOcr3IknflrjDta4",
"updateTime": "2025-02-28 08:44:18",
"materialName": "E",
"warehouseName": "库房1",
"warehouseAddress": "物流运输产业院1栋101",
"warehouseNameRowSpan": 1,
"sumQuantityRowSpan": 0,
"materialNameRowSpan": 0
}
]
前端部分代码
描述:1、计算每个字段(materialName)rowSpan [使用递归计算出的materialNameRowSpan存入行记录]
2、设置组件的columns,使用customRender 参见ant-design-vue文档中Column对象 使用的 API
注意:自定义需要合并字段数组,根据顺序合并字段值相同的行
methods部分函数如下
// 获取需要合并数据的rowSpan
convertData(arr, levelIndex = 0) {
const levelKey = this.sortLevel
const key = levelKey[levelIndex]
// 根据不同维度重新整合数据
let groupObj = this.groupBy(arr, key) || {}
Object.keys(groupObj).forEach((groupKey) => {
if (levelIndex < levelKey.length - 1) {
groupObj[groupKey] = this.convertData(groupObj[groupKey], levelIndex + 1)
}
// 计算rowSpan
groupObj[groupKey].forEach((item, index, arr) => {
item[`${key}RowSpan`] = index === 0 ? arr.length : 0
})
})
return Object.values(groupObj).flat()
},
// 根据属性分组
groupBy(arr = [], key) {
let obj = {}
arr.forEach((item) => {
const val = item[key]
if (!obj[val]) {
obj[val] = []
}
obj[val].push(item)
})
return obj
},
a-table组件columns设置如下
const materialNameRender = (value, row, index) => {
return {
children: value,
attrs: {
rowSpan: row.materialNameRowSpan,
},
}
}
const sumQuantityRender = (value, row, index) => {
return {
children: value,
attrs: {
rowSpan: row.sumQuantityRowSpan,
},
}
}
data(){
const tableColumns = [
{
title: "物资名称",
align: "center",
dataIndex: "materialName",
key: "materialName",
customRender: materialNameRender,
},
{
title: "物资数量",
align: "center",
dataIndex: "sumQuantity",
key: "sumQuantity",
customRender: sumQuantityRender,
},
{
title: "库房库位",
children: [
{
title: "名称",
dataIndex: "warehouseName",
key: "warehouseName",
align: "center",
},
{
title: "地址",
dataIndex: "warehouseAddress",
key: "warehouseAddress",
align: "center",
},
{
title: "数量",
align: "center",
dataIndex: "quantity",
key: "quantity",
},
],
},
{
title: "更新时间",
align: "center",
dataIndex: "updateTime",
key: "updateTime",
},
]
return {
tableColumns,
sortLevel: ["materialName", "sumQuantity", "warehouseName"],
}
}
示例效果
总结
纯前端实现清洗数据+表格合并 ,关键点在于前端数据结构,获取合并列的rowSpan,配合customRender,设置变量存储合并列字段顺序数组(sortLevel),能自定义实现字段值相同的则被合并行