zhou zhou
8 小时以前 afc91799ddfa0c9c6934b42295fadb6829765512
#优化StickyDataTable
1个文件已修改
157 ■■■■■ 已修改文件
rsf-admin/src/page/components/StickyDataTable.jsx 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/StickyDataTable.jsx
@@ -1,5 +1,5 @@
import React from 'react';
import React, { useMemo } from 'react';
import { DataTable, useDataTableDataContext, useTranslate } from 'react-admin';
import { TableFooter, TableRow, TableCell } from '@mui/material';
@@ -37,6 +37,50 @@
};
/**
 * 固定列样式常量
 */
const stickyLeftStyle = {
    position: 'sticky',
    left: 0,
    zIndex: 2,
    backgroundColor: '#FFFFFF',
    '.MuiTableRow-root:not(.MuiTableRow-head):hover &': {
        backgroundColor: '#f5f5f5'
    }
};
const stickyRightStyle = {
    position: 'sticky',
    right: 0,
    zIndex: 2,
    backgroundColor: '#FFFFFF',
    '.MuiTableRow-root:not(.MuiTableRow-head):hover &': {
        backgroundColor: '#f5f5f5'
    }
};
/**
 * DataTable 样式常量
 */
const tableStyles = {
    '& .MuiTableCell-head': {
        zIndex: 4,
        borderBottom: 'none'
    },
    '& .MuiTableFooter-root': {
        position: 'sticky',
        bottom: 0,
        zIndex: 3,
        backgroundColor: '#FFFFFF',
    },
    '& .MuiTableFooter-root .MuiTableCell-root': {
        backgroundColor: '#f5f5f5',
        fontWeight: 'bold',
        borderTop: '2px solid #e0e0e0',
    },
};
/**
 * 内部 Footer 组件
 * @param {Object} props
 * @param {Array} props.footerConfig - footer 配置数组
@@ -46,7 +90,8 @@
    const data = useDataTableDataContext();
    const translate = useTranslate();
    const results = footerConfig.map(config => {
    // 缓存计算结果,避免不必要的重复计算
    const results = useMemo(() => footerConfig.map(config => {
        const { field, type = 'sum', label, render } = config;
        const calculator = calculators[type];
        const value = calculator ? calculator(data, field) : 0;
@@ -60,7 +105,7 @@
        // 获取翻译后的标签
        const displayLabel = label ? (label.startsWith('table.') || label.startsWith('common.') ? translate(label) : label) : field;
        return { label: displayLabel, value, typePrefix };
    });
    }), [footerConfig, data, translate]);
    return (
        <TableFooter>
@@ -100,80 +145,56 @@
    ...props
}) => {
    // 递归处理 Children,确保即便是 Fragment 包裹的列也能被处理
    const processChildren = (children) => {
        return React.Children.map(children, (child) => {
            if (!React.isValidElement(child)) return child;
    // 使用 Set 优化查找性能 O(n) -> O(1)
    const stickyLeftSet = useMemo(() => new Set(stickyLeft), [stickyLeft]);
    const stickyRightSet = useMemo(() => new Set(stickyRight), [stickyRight]);
            // 如果是 Fragment,递归处理其 children
            if (child.type === React.Fragment) {
                return <React.Fragment>{processChildren(child.props.children)}</React.Fragment>;
            }
    // 缓存处理后的 children,避免不必要的重新计算
    const processedChildren = useMemo(() => {
        const processChildren = (children) => {
            return React.Children.map(children, (child) => {
                if (!React.isValidElement(child)) return child;
            const source = child.props.source;
            let stickyStyle = {};
                // 如果是 Fragment,递归处理其 children
                if (child.type === React.Fragment) {
                    return <React.Fragment>{processChildren(child.props.children)}</React.Fragment>;
                }
            // 左侧固定
            if (stickyLeft.includes(source)) {
                stickyStyle = {
                    position: 'sticky',
                    left: 0,
                    zIndex: 2, // 比普通内容高
                    backgroundColor: '#FFFFFF',
                    '.MuiTableRow-root:not(.MuiTableRow-head):hover &': {
                        backgroundColor: '#f5f5f5'
                    }
                };
            }
                const source = child.props.source;
                let stickyStyle = null;
            // 右侧固定
            if (stickyRight.includes(source)) {
                stickyStyle = {
                    position: 'sticky',
                    right: 0,
                    zIndex: 2,
                    backgroundColor: '#FFFFFF',
                    '.MuiTableRow-root:not(.MuiTableRow-head):hover &': {
                        backgroundColor: '#f5f5f5'
                    }
                };
            }
                // 左侧固定
                if (stickyLeftSet.has(source)) {
                    stickyStyle = stickyLeftStyle;
                }
            if (Object.keys(stickyStyle).length > 0) {
                // 合并 sx
                return React.cloneElement(child, {
                    sx: { ...child.props.sx, ...stickyStyle }
                });
            }
                // 右侧固定
                if (stickyRightSet.has(source)) {
                    stickyStyle = stickyRightStyle;
                }
            return child;
        });
    };
                if (stickyStyle) {
                    // 合并 sx
                    return React.cloneElement(child, {
                        sx: { ...child.props.sx, ...stickyStyle }
                    });
                }
    // 构建 foot 属性
    const footerComponent = footerConfig && footerConfig.length > 0
        ? () => <StickyTableFooter footerConfig={footerConfig} footerLabel={footerLabel} />
        : undefined;
                return child;
            });
        };
        return processChildren(children);
    }, [children, stickyLeftSet, stickyRightSet]);
    // 缓存 footerComponent,避免每次渲染创建新函数
    const footerComponent = useMemo(() => {
        if (!footerConfig?.length) return undefined;
        return () => <StickyTableFooter footerConfig={footerConfig} footerLabel={footerLabel} />;
    }, [footerConfig, footerLabel]);
    return (
        <DataTable {...props} foot={footerComponent} sx={{
            '& .MuiTableCell-head': {
                zIndex: 4,
                borderBottom: 'none' // 遵循之前的优化,去除表头下边框
            },
            '& .MuiTableFooter-root': {
                position: 'sticky',
                bottom: 0,
                zIndex: 3,
                backgroundColor: '#FFFFFF',
            },
            '& .MuiTableFooter-root .MuiTableCell-root': {
                backgroundColor: '#f5f5f5',
                fontWeight: 'bold',
                borderTop: '2px solid #e0e0e0',
            },
        }}>
            {processChildren(children)}
        <DataTable {...props} foot={footerComponent} sx={tableStyles}>
            {processedChildren}
        </DataTable>
    );
};