https://www.npmjs.com/package/react-perfect-scrollbar :用到滚动组件去作友好的滚动处理(没发觉有什么具体效果感觉)
https://v4.mui.com/zh/components/tables/:用material-UI 的table组件 + 自定义CSS 实现冻结效果;
import React, { useEffect, useState } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import PropTypes from 'prop-types';
import {
Card,
CardContent,
Link,
// TableContainer,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/styles';
import PerfectScrollbar from 'react-perfect-scrollbar';
import clsx from 'clsx';
import accounting from 'accounting';
const useStyles = makeStyles((theme) => ({
root: {},
content: {
padding: 0,
},
inner: {
minWidth: 1920,
maxHeight: 800,
},
headerRowCell1: { // 自定义CSS
width: theme.spacing(15),
zIndex: 4,
},
headerRowCell2: {
left: theme.spacing(15),
zIndex: 4,
},
headerRowCell: {
top: 57,
},
bodyRowCell1: {
width: theme.spacing(15),
backgroundColor: 'white',
left: 0,
position: 'sticky',
zIndex: 3,
},
bodyRowCell2: {
backgroundColor: 'white',
left: theme.spacing(15),
position: 'sticky',
zIndex: 3,
},
bodyRowCell3: { // 自定义CSS
zIndex: 1,
},
}));
const Result = (props) => {
const {
data, className, search, begin, end, projectId,
} = props;
const classes = useStyles();
const formatMoney = (number) => accounting.formatMoney(number, '');
const [maxCol, setMaxCol] = useState({
approvedBudgets: 0,
frozenNumber: 0,
availableNumber: 0,
actualExpenditure: 0,
balanceNumber: 0,
});
const getMaxCol = (field) => {
data.forEach((current) => {
if (current[field].length > maxCol[field]) {
setMaxCol((prevState) => ({
...prevState,
[field]: current[field].length,
}));
}
});
};
const getFirst = (field) => {
if (data && data.length > 0 && data[0] && data[0][field] && data[0][field].length > 0) {
return data[0][field];
}
return null;
};
useEffect(() => {
getMaxCol('approvedBudgets');
getMaxCol('frozenNumber');
getMaxCol('availableNumber');
getMaxCol('actualExpenditure');
getMaxCol('balanceNumber');
}, [data]);
return (
<Card className={clsx(classes.root, className)}>
<CardContent className={classes.content}>
<PerfectScrollbar>
<div className={classes.inner}>
<Table stickyHeader>
<TableHead>
<TableRow>
<TableCell rowSpan={2} align="center" className={classes.headerRowCell1}>支出分类编码</TableCell>
<TableCell rowSpan={2} align="center" className={classes.headerRowCell2}>支出分类名称</TableCell>
<TableCell colSpan={maxCol.approvedBudgets} align="center">预算批复数</TableCell>
<TableCell colSpan={maxCol.frozenNumber} align="center">冻结数</TableCell>
<TableCell colSpan={maxCol.availableNumber} align="center">可用数</TableCell>
<TableCell colSpan={maxCol.actualExpenditure} align="center">实际支出数</TableCell>
<TableCell colSpan={maxCol.balanceNumber} align="center">结余数</TableCell>
<TableCell rowSpan={2} align="center">支出预算比</TableCell>
</TableRow>
<TableRow>
{
getFirst('approvedBudgets')?.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.headerRowCell}>{value.fundSourceName}</TableCell>
))
}
{
getFirst('frozenNumber')?.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.headerRowCell}>{value.fundSourceName}</TableCell>
))
}
{
getFirst('availableNumber')?.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.headerRowCell}>{value.fundSourceName}</TableCell>
))
}
{
getFirst('actualExpenditure')?.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.headerRowCell}>{value.fundSourceName}</TableCell>
))
}
{
getFirst('balanceNumber')?.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.headerRowCell}>{value.fundSourceName}</TableCell>
))
}
</TableRow>
</TableHead>
<TableBody>
{data.map((item) => (
<TableRow key={item.id}>
<TableCell align="center" className={classes.bodyRowCell1}>{item.expenditureTypeCode}</TableCell>
<TableCell align="center" className={classes.bodyRowCell2}>{item.expenditureTypeName}</TableCell>
{
item.approvedBudgets.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>{formatMoney(value.amount)}</TableCell>
))
}
{
item.frozenNumber.map((value) => (
value.fundSourceName === '合计'
? (
<TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>
<Link
color="primary"
component={RouterLink}
noWrap
underline="always"
to={`/frozenquery/${item.expenditureTypeId}/${search.begin}/${search.end}/${search.projectId}`}
variant="body1"
>
{formatMoney(value.amount)}
</Link>
</TableCell>
)
: <TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>{formatMoney(value.amount)}</TableCell>
))
}
{
item.availableNumber.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>{formatMoney(value.amount)}</TableCell>
))
}
{
item.actualExpenditure.map((value) => (
value.fundSourceName === '合计'
? ( // expenditureTypeId
<TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>
<Link
component={RouterLink}
underline="always"
variant="body1"
to={`/expenditure-details/${item.expenditureTypeId}/${begin}/${end}/${projectId}`}
>
{formatMoney(value.amount)}
</Link>
</TableCell>
) : (
<TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>{formatMoney(value.amount)}</TableCell>
)
))
}
{
item.balanceNumber.map((value) => (
<TableCell key={value.fundSourceName} align="center" className={classes.bodyRowCell3}>{formatMoney(value.amount)}</TableCell>
))
}
<TableCell align="center" className={classes.bodyRowCell3}>{item.budgetRatio}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</PerfectScrollbar>
</CardContent>
</Card>
);
};
Result.propTypes = {
className: PropTypes.string,
begin: PropTypes.string,
end: PropTypes.string,
projectId: PropTypes.string,
data: PropTypes.arrayOf({
id: PropTypes.string,
// 支出类型编码
expenditureTypeCode: PropTypes.string,
// 支出类型名称
expenditureTypeName: PropTypes.string,
// 预算批复数
approvedBudgets: PropTypes.shape({
fundSourceName: PropTypes.string,
amount: PropTypes.number,
}),
// 冻结数
frozenNumber: PropTypes.shape({
fundSourceName: PropTypes.string,
amount: PropTypes.number,
}),
// 可用数
availableNumber: PropTypes.shape({
fundSourceName: PropTypes.string,
amount: PropTypes.number,
}),
// 实际支出数
actualExpenditure: PropTypes.shape({
fundSourceName: PropTypes.string,
amount: PropTypes.number,
}),
// 结余数
balanceNumber: PropTypes.shape({
fundSourceName: PropTypes.string,
amount: PropTypes.number,
}),
// 支出预算比
budgetRatio: PropTypes.number,
}),
search: PropTypes.arrayOf({
begin: PropTypes.string,
end: PropTypes.string,
projectId: PropTypes.string,
}),
};
Result.defaultProps = {
className: '',
data: [],
search: [],
};
export default Result;