滚动组件 react-perfect-scrollbar 和冻结行、列

公冶同
2023-12-01

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;
 类似资料: