From afc91799ddfa0c9c6934b42295fadb6829765512 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期三, 04 二月 2026 14:18:59 +0800
Subject: [PATCH] #优化StickyDataTable

---
 rsf-admin/src/page/components/StickyDataTable.jsx |  157 +++++++++++++++++++++++++++++----------------------
 1 files changed, 89 insertions(+), 68 deletions(-)

diff --git a/rsf-admin/src/page/components/StickyDataTable.jsx b/rsf-admin/src/page/components/StickyDataTable.jsx
index f2cbada..4fbae7a 100644
--- a/rsf-admin/src/page/components/StickyDataTable.jsx
+++ b/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 鍖呰9鐨勫垪涔熻兘琚鐞�
-    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>
     );
 };

--
Gitblit v1.9.1