本次学习到使用antd里table组件实现三级表格嵌套;
父级点击+号出现子表;
子级点击+号出现孙表;
table表格录制
import React, { useEffect, useState, useMemo } from "react";
import { Table, Divider } from "antd";
const MultiLevelTable = () => {
const [expandedRowKeys, setExpandedRowKeys] = useState([]);
// 父表列配置
const parentColumns = [
{ title: "會員編號", dataIndex: "memberTeamNum", key: "memberTeamNum" },
{ title: "會員姓名", dataIndex: "memberName", key: "memberName" },
{ title: "總收費", dataIndex: "totalAmount", key: "totalAmount" },
];
// 子表列配置(可共用)
const subTableColumns = [
{ title: "繳費收款類型", dataIndex: "feeType", key: "type" },
{ title: "數量", dataIndex: "number", key: "number" },
{ title: "單價", dataIndex: "price", key: "price" },
{ title: "小計", dataIndex: "total", key: "total" },
];
// 孙表列配置(可自定义)
const grandChildTableColumns1 = [
{ title: "簽署的服務類別", dataIndex: "type", key: "type1" },
{ title: "開始日期", dataIndex: "startDate", key: "startDate1" },
{ title: "開始時間", dataIndex: "startTime", key: "startTime1" },
{ title: "結束日期", dataIndex: "endDate", key: "endDate1" },
{ title: "結束時間", dataIndex: "endTime", key: "endTime1" },
{ title: "服務狀況", dataIndex: "status", key: "status1" },
];
// 孙表列配置(可自定义)
const grandChildTableColumns2 = [
{ title: "收款服務名稱", dataIndex: "itemName", key: "itemName22" },
{ title: "日期", dataIndex: "date", key: "date22" },
{ title: "數量", dataIndex: "number", key: "number22" },
{ title: "單價", dataIndex: "price", key: "price22" },
{ title: "小計", dataIndex: "total", key: "total22" },
{ title: "備註", dataIndex: "remark", key: "remark22" },
];
// 孙表列配置(可自定义)
const grandChildTableColumns3 = [
{ title: "使用的服務物料", dataIndex: "itemName", key: "itemName33" },
{ title: "日期", dataIndex: "date", key: "date33" },
{ title: "數量", dataIndex: "number", key: "number33" },
{ title: "物料費", dataIndex: "price", key: "price33" },
{ title: "小計", dataIndex: "total", key: "total33" },
{ title: "備註", dataIndex: "remark", key: "remark33" },
];
// 孙表列配置(可自定义)
const grandChildTableColumns4 = [
{ title: "活動編號", dataIndex: "activityId", key: "activityId44" },
{ title: "活動名稱", dataIndex: "activityName", key: "activityName44" },
{ title: "開始日期", dataIndex: "startDate", key: "startDate44" },
{ title: "開始時間", dataIndex: "startTime", key: "startTime44" },
{ title: "結束日期", dataIndex: "endDate", key: "endDate44" },
{ title: "結束時間", dataIndex: "endTime", key: "endTime44" },
{ title: "活動類別", dataIndex: "activityType", key: "activityType44" },
{ title: "數量", dataIndex: "number", key: "number44" },
{ title: "單價", dataIndex: "price", key: "price44" },
{ title: "小計", dataIndex: "total", key: "total44" },
{ title: "備註", dataIndex: "remark", key: "remark44" },
];
const getGrandChildTableColumns = (data) => {
switch (data.type) {
case '1':
return grandChildTableColumns1;
case '2':
return grandChildTableColumns2;
case '3':
return grandChildTableColumns3;
case '4':
return grandChildTableColumns4;
default:
return null;
}
}
const getGrandChildTableData = (type) => {
switch (type) {
case '1':
return [
{ type: "膳食費用", startDate: "02-05-2025", startTime: "12:15", endDate: "N/A", endTime: "", status: "已完成" }
]
case '2':
return [
{
itemName: "大件",
date: "2023-01-01",
number: 1,
price: 100,
remark: "1"
},
{
itemName: "小件",
date: "2023-01-01",
number: 1,
price: 120,
remark: "32",
}
];
case '3':
return [
{
itemName: "驗血糖物料",
date: "2023-01-01",
number: 1,
price: 140,
remark: "臨時展示"
}
];
case '4':
return [
{
activityId: "UUU/25/05/01",
activityName: "中秋展覽",
startDate: "2023-01-01",
startTime: "9:00",
endDate: "2023-01-01",
endTime: "17:00",
place: "臨時展示",
remark: "",
}
];
default:
return null
}
}
// 模拟数据(包含父表、子表1、子表2、孙表)
const source = useMemo(() => {
const parentSourceData = [
{
key: "1",
memberTeamNum: "EEE12/0332/23/04",
memberName: "蔡名杰",
totalAmount: "269.5",
},
{
key: "2",
memberTeamNum: "EEE12/03322/23/05",
memberName: "張小喬",
totalAmount: "280.8",
}
]
const childrenSourceData = [
{
feeType: "1.膳食費用",
price: "10.4",
number: "5",
type: "1"
},
{
feeType: "2.各類服務收費-膳食送遞費",
number: "5",
price: "2.6",
type: "1"
},
{
feeType: "3.各類服務收費-家居照顧/護理服務費",
number: "11",
price: "5.5",
type: "1"
},
{
feeType: "4.物料費",
number: "1",
price: "10.4",
type: "3"
},
{
feeType: "5.護送交通費",
number: "5",
price: "2.6",
type: "3"
},
{
feeType: "6.其他費用",
number: "11",
price: "5.5",
type: "2"
},
{
feeType: "7.活動收費",
number: "10",
price: "300.4",
type: "4"
},
]
const combineData = parentSourceData.map((parentItem) => {
const combineChildrenSourceData = (childrenItem, childrenKey) => {
const list = getGrandChildTableData(childrenItem?.type)?.map((item, index) => {
return {
...item,
key: `${childrenKey}-GrandChild${index}`,
// total: 123330,
}
})
console.log("得到的數據是=childrenSourceData=》", list)
return list ?? []
}
return {
...parentItem,
subTable1: childrenSourceData.map((childrenItem, index) => {
const childrenKey = `${parentItem.key}-children${index}`
return {
...childrenItem,
total: childrenItem.number * childrenItem.price,
key: childrenKey,
childrenList: combineChildrenSourceData(childrenItem, childrenKey),
// children: [{}]
// children: [{
// key: `${childrenKey}-GrandChild1`,
// price: "測試價格"
// }]
}
})
}
})
return combineData
})
// 渲染子表(可展开孙表)
const renderSubTable = (data, tableName) => {
if (!data || data.length === 0) {
return <p>{tableName} 无数据</p>;
}
const expandedRowRender = (record) => {
return (
<div style={{ background: "#fafafa", padding: "16px" }}>
{/* <h4>孫表</h4> */}
<Table
columns={getGrandChildTableColumns(record)}
dataSource={record.childrenList}
// expandable={null}
pagination={false}
size="small"
/>
</div>
);
};
return (
<Table
columns={subTableColumns}
dataSource={data}
pagination={false}
size="small"
expandable={{
expandedRowRender,
rowExpandable: (record) => record.childrenList?.length > 0
}}
/>
);
};
// 父表展开时渲染多个子表
const expandedRowRender = (record) => {
return (
<div style={{ background: "#fafafa", padding: "16px" }}>
{/* <h4>子表</h4> */}
{renderSubTable(record.subTable1, "子表1")}
</div>
);
};
return (
<Table
columns={parentColumns}
dataSource={source}
expandable={{
expandedRowRender,
expandedRowKeys,
onExpand: (expanded, record) => {
const keys = expanded
? [...expandedRowKeys, record.key]
: expandedRowKeys.filter((key) => key !== record.key);
setExpandedRowKeys(keys);
},
rowExpandable: (record) =>
record.subTable1.length > 0 || record.subTable2.length > 0,
}}
/>
);
};
export default MultiLevelTable;
在模拟数据中,不要使用的children字段传入子(孙)表数据;
如果使用了,会出现以下画面:
代码:
// 省去了部分代码...
return {
...parentItem,
subTable1: childrenSourceData.map((childrenItem, index) => {
const childrenKey = `${parentItem.key}-children${index}`
return {
...childrenItem,
total: childrenItem.number * childrenItem.price,
key: childrenKey,
childrenList: combineChildrenSourceData(childrenItem, childrenKey),
// children: [{}]
// 會有不合理的數據展示
children: [{
key: `${childrenKey}-GrandChild1`,
price: "測試價格"
}]
}
})
}
antd 的官网上没有具体提到dataSource里children的使用;但是我们可以根据事件可以猜出来。当父表有存在子表的时候(有配置expandable属性)且dataSource有存在children数据,那么children会和上一层级一同展示;