后端数据
说明:monthList: 为动态月份表头标题,data中的valueList 为动态月份对应的动态数据
const res = {
monthList: [
'2023-04',
'2023-04',
'2023-05',
'2023-06',
'2023-07',
'2023-08',
'2023-09',
'2023-10',
'2023-11',
'2023-12',
'2024-01',
'2024-02',
'2024-03',
],
data: [
{
partDept: '部门一',
type: '类型一',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门一',
type: '类型二',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门一',
type: '类型三',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门二',
type: '类型一',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门二',
type: '类型二',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门二',
type: '类型三',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门三',
type: '类型一',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门三',
type: '类型二',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
{
partDept: '部门三',
type: '类型三',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
{ period: '2023-08', value: 100 },
{ period: '2023-09', value: 100 },
{ period: '2023-10', value: 100 },
{ period: '2023-11', value: 100 },
{ period: '2023-12', value: 100 },
{ period: '2024-01', value: 100 },
{ period: '2024-02', value: 100 },
{ period: '2024-03', value: 100 },
],
},
],
};
react代码
import React, { useState, useEffect } from 'react';
import { Col, Row, Table } from 'antd';
import _ from 'lodash';
const Home = () => {
const [dataList, setDataList] = useState([]);
const [periodColumns, setPeriodColumns] = useState([]);
useEffect(() => {
const res = {
monthList: ['2023-04', '2023-05', '2023-06', '2023-07'],
data: [
{
partDept: '部门一',
type: '类型一',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门一',
type: '类型二',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门一',
type: '类型三',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门二',
type: '类型一',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门二',
type: '类型二',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门二',
type: '类型三',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门三',
type: '类型一',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门三',
type: '类型二',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
{
partDept: '部门三',
type: '类型三',
total: 100,
valueList: [
{ period: '2023-04', value: 100 },
{ period: '2023-05', value: 100 },
{ period: '2023-06', value: 100 },
{ period: '2023-07', value: 100 },
],
},
],
};
// 将数据中的动态的valueList打平
const dataCopy = _.cloneDeep(res.data);
const newDataList = dataCopy.map((item) => {
const { valueList } = item;
const newValueList = valueList.map((it) => {
return { [it.period]: it.value };
});
const list = newValueList.reduce((acc, value) => {
return { ...acc, ...value };
});
return {
...item,
...list,
};
});
setPeriodColumns(res.monthList);
setDataList(newDataList);
}, []);
// 表头
const getColumns = () => {
const columns = [
{
title: '部门名称',
dataIndex: 'partDept',
width: 150,
fixed: 'left',
align: 'center',
render: (val, record) => ({
children: <div style={{ fontWeight: 'bold' }}>{val}</div>,
props: {
rowSpan: record.rowSpan,
colSpan: record.colSpan,
},
}),
},
{
title: '类型',
dataIndex: 'type',
fixed: 'left',
align: 'center',
width: 120,
render: (v) => v,
},
{
title: '汇总',
dataIndex: 'total',
align: 'right',
width: 120,
render: (v) => v,
},
];
// 拼接动态表头
const newPeriodColumns = periodColumns.map((item) => {
return {
title: item,
dataIndex: item,
align: 'right',
width: 120,
render: (v) => v,
};
});
return [...columns, ...newPeriodColumns];
};
// 合并单元格处理
const mergeRows = (rows, key) => {
rows[0].rowSpan = 1;
let idx = 0;
return rows.slice(1).reduce(
(mergedRows, item, index) => {
if (item[key] === mergedRows[idx][key]) {
mergedRows[idx].rowSpan++;
item.colSpan = 0;
} else {
item.rowSpan = 1;
idx = index + 1;
}
return [...mergedRows, item];
},
[rows[0]],
);
};
return (
<div>
<Row>
<Col span={24}>
<Table bordered dataSource={dataList.length > 0 && mergeRows(dataList, 'partDept')}>
{getColumns().map((item) => {
return (
<Table.Column
title={item.title}
dataIndex={item.dataIndex}
fixed={item.fixed}
render={item.render}
width={item.width}
onCell={item.onCell}
align={item.align}
/>
);
})}
</Table>
</Col>
</Row>
</div>
);
};
export default Home;
最终效果
说明: 部门、类型、汇总为固定表头,月份为动态数据,由后端提供
长表格首次进来可以确定滚动条位置
接上面代码
// 首次进来时可以确定滚动条的位置 index+1 是因为 汇总, 前提是每列单元格宽度是固定的 本例width为120
const index = res.monthList.length > 0 && res.monthList.map((item) => item).indexOf('2023-07');
const element = document.getElementsByClassName('scrollTable')[0];
const scrollElement = element.getElementsByClassName('ant-table-content')[0];
scrollElement.scrollLeft = index > 0 ? (index + 1) * 120 : 0;