From 001e82c7cff123d378eadf02c92acc5a3cbad318 Mon Sep 17 00:00:00 2001 From: LiuJiaNan <15703339975@163.com> Date: Sat, 27 Dec 2025 09:53:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Table/index.js | 179 +++++++++++++++++++++++++++++--- src/components/Table/index.less | 6 -- 2 files changed, 163 insertions(+), 22 deletions(-) diff --git a/src/components/Table/index.js b/src/components/Table/index.js index c8531e0..82ce1cf 100644 --- a/src/components/Table/index.js +++ b/src/components/Table/index.js @@ -1,10 +1,14 @@ -import TablePro from "@cqsjjb/jjb-react-admin-component/Table"; -import { getIndexColumn } from "../../utils/index"; -import dayjs from 'dayjs'; +import { ProTable } from "@ant-design/pro-components"; +import dayjs from "dayjs"; +import { useEffect, useMemo, useState } from "react"; +import { throttle } from "throttle-debounce"; +import { useAntdResizableHeader } from "use-antd-resizable-header"; +import { getDataType, getIndexColumn } from "../../utils"; +import "use-antd-resizable-header/dist/style.css"; import "./index.less"; const CLEANUP_INTERVAL_DAYS = 10; // 清理间隔天数 -const LAST_CLEANUP_KEY = 'tableLocalStorageLastCleanup'; // 最后清理时间存储key +const LAST_CLEANUP_KEY = "tableLocalStorageLastCleanup"; // 最后清理时间存储key // 清理本地存储中特定后缀的key function cleanupTableLocalStorage() { @@ -13,20 +17,20 @@ function cleanupTableLocalStorage() { const lastCleanup = lastCleanupStr ? dayjs(lastCleanupStr) : null; // 如果没有上次清理时间或距离上次清理已超过10天 - if (!lastCleanup || now.diff(lastCleanup, 'day') >= CLEANUP_INTERVAL_DAYS) { + if (!lastCleanup || now.diff(lastCleanup, "day") >= CLEANUP_INTERVAL_DAYS) { // 查找并清理符合条件的key const keysToRemove = []; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); - if (key && (key.endsWith('#columnState') || - key.endsWith('#size') || - key.endsWith('#resizable'))) { + if (key && (key.endsWith("#columnState") + || key.endsWith("#size") + || key.endsWith("#resizable"))) { keysToRemove.push(key); } } // 删除匹配的key - keysToRemove.forEach(key => { + keysToRemove.forEach((key) => { localStorage.removeItem(key); }); @@ -35,6 +39,26 @@ function cleanupTableLocalStorage() { } } +function getPersistenceKey(index) { + const basename = process.env?.app?.basename; + const pathname = decodeURIComponent(window.location.pathname); + const insertIndex = getDataType(index) === "Undefined" ? "" : `#{${index}}`; + + return { + size: `${basename}#${pathname}${insertIndex}#size`, + resizable: `${basename}#${pathname}${insertIndex}#resizable`, + columnState: `${basename}#${pathname}${insertIndex}#columnState`, + }; +} + +function getTableSize(index) { + return window.localStorage.getItem(getPersistenceKey(index).size); +} + +function setTableSize(value, index) { + return window.localStorage.setItem(getPersistenceKey(index).size, value); +} + function Table(props) { const { columns = [], @@ -43,14 +67,101 @@ function Table(props) { align = "center", indexColumnFixed = "left", rowKey = "id", + storeIndex, + disabledResizer = false, ...restProps } = props; - // 组件初始化时执行清理 - cleanupTableLocalStorage(); + const antPrefix = process.env.app.antd["ant-prefix"]; + const prefix = antPrefix || "ant"; + const baseCls = `.${prefix}-table`; + const tableCls = `${baseCls}-wrapper`; + const tableBodyCls = `${baseCls}-body`; - function settingColumns() { - showIndexColumn && columns.unshift({ ...getIndexColumn(props.pagination), fixed: indexColumnFixed }); + const [size, setSize] = useState(getTableSize(storeIndex) || "default"); + const [tableHeight, setTableHeight] = useState(0); + + const persistenceKey = getPersistenceKey(storeIndex); + const enabledResizer = !disabledResizer; + + const { + components, + resizableColumns, + tableWidth, + resetColumns, + } = useAntdResizableHeader({ + columns, + columnsState: { + persistenceKey: persistenceKey.resizable, + persistenceType: "localStorage", + }, + }); + + // 计算高度 + const calcTableHeight = throttle(50, () => { + try { + // table元素 + const tableEl = document.querySelector(tableCls); + // table-body元素 + const tableBodyEl = document.querySelector(tableBodyCls); + + // 获取页脚元素高度 + const footerEl = document.querySelector(".page-layout-footer"); + const footerHeight = footerEl ? footerEl.offsetHeight : 0; + + if (tableBodyEl && tableEl) { + // 获取table元素的矩形数据 + const tableRect = tableEl.getBoundingClientRect(); + // 获取table-body元素的矩形数据 + const tableBodyRect = tableBodyEl.getBoundingClientRect(); + // 获取底部的高度差 + const bottomHeight = tableRect.bottom - tableBodyRect.bottom; + // 计算最终值,减去页脚高度 + setTableHeight(innerHeight - tableBodyRect.top - bottomHeight - (window.__IN_BASE__ ? 38 : 22) - footerHeight); + } + } + catch (e) { + window.console.error(e); + } + }); + + useEffect(() => { + let mutationObserver, resizeObserver; + if (enabledResizer) { + // 监听-DOM树 + mutationObserver = new MutationObserver(mutations => mutations.forEach(() => calcTableHeight())); + // 监听-缩放 + resizeObserver = new ResizeObserver(entries => entries.forEach(() => calcTableHeight())); + + // 初始化首次计算 + setTimeout(() => calcTableHeight(), 500); + + // 执行-监听-缩放 + resizeObserver.observe(document.body); + // 执行-监听-DOM树是否发生变化 + mutationObserver.observe(document.body, { + subtree: true, + childList: true, + }); + } + + cleanupTableLocalStorage(); + + return () => { + if (mutationObserver && resizeObserver && enabledResizer) { + resizeObserver.unobserve(document.body); + mutationObserver.disconnect(document.body); + } + }; + }, []); + + useEffect(() => { + setTableSize(size, storeIndex); + }, [size]); + + const settingColumns = () => { + const columnsCopy = [...resizableColumns]; + showIndexColumn && columnsCopy.unshift({ ...getIndexColumn(props.pagination), fixed: indexColumnFixed }); const setAlign = column => ({ align, @@ -59,11 +170,47 @@ function Table(props) { ...(column.children ? { children: column.children.map(setAlign) } : {}), }); - return columns.map(setAlign); - } + return columnsCopy.map(setAlign); + }; + + const processedColumns = useMemo(() => settingColumns(), [resizableColumns, showIndexColumn, align, ellipsis, indexColumnFixed, props.pagination]); + return (
- + + 重置列宽 + + ), + }, + }} + components={components} + columnsState={{ + persistenceKey: persistenceKey.columnState, + persistenceType: "localStorage", + }} + onSizeChange={setSize} + columns={processedColumns} + bordered + size="small" + rowKey={rowKey} + {...restProps} + />
); } diff --git a/src/components/Table/index.less b/src/components/Table/index.less index 0f73dd2..c979530 100644 --- a/src/components/Table/index.less +++ b/src/components/Table/index.less @@ -12,9 +12,3 @@ padding-top: 0 !important; padding-bottom: 16px; } - -.search-layout { - + .table-layout .@{ant-prefix}-pro-table-list-toolbar-container { - padding-top: 26px !important; - } -}