From dd9ec06c656f603a0dd73004a9bccab29d150581 Mon Sep 17 00:00:00 2001 From: hzm <934585316@qq.com> Date: Sat, 28 Feb 2026 23:15:25 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E8=A1=A5=E5=85=85=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/PcTableSettingModal.jsx | 242 +++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 app/components/PcTableSettingModal.jsx diff --git a/app/components/PcTableSettingModal.jsx b/app/components/PcTableSettingModal.jsx new file mode 100644 index 0000000..945a705 --- /dev/null +++ b/app/components/PcTableSettingModal.jsx @@ -0,0 +1,242 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { AnimatePresence, motion, Reorder } from 'framer-motion'; +import { createPortal } from 'react-dom'; +import ConfirmModal from './ConfirmModal'; +import { CloseIcon, DragIcon, ResetIcon, SettingsIcon } from './Icons'; + +/** + * PC 表格个性化设置侧弹框 + * @param {Object} props + * @param {boolean} props.open - 是否打开 + * @param {() => void} props.onClose - 关闭回调 + * @param {Array<{id: string, header: string}>} props.columns - 非冻结列(id + 表头名称) + * @param {Record} [props.columnVisibility] - 列显示状态映射(id => 是否显示) + * @param {(newOrder: string[]) => void} props.onColumnReorder - 列顺序变更回调,参数为新的列 id 顺序 + * @param {(id: string, visible: boolean) => void} props.onToggleColumnVisibility - 列显示/隐藏切换回调 + * @param {() => void} props.onResetColumnOrder - 重置列顺序回调,需二次确认 + * @param {() => void} props.onResetColumnVisibility - 重置列显示/隐藏回调 + * @param {() => void} props.onResetSizing - 点击重置列宽时的回调(通常用于打开确认弹框) + */ +export default function PcTableSettingModal({ + open, + onClose, + columns = [], + columnVisibility, + onColumnReorder, + onToggleColumnVisibility, + onResetColumnOrder, + onResetColumnVisibility, + onResetSizing, +}) { + const [resetOrderConfirmOpen, setResetOrderConfirmOpen] = useState(false); + + useEffect(() => { + if (!open) setResetOrderConfirmOpen(false); + }, [open]); + + useEffect(() => { + if (open) { + const prev = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + return () => { + document.body.style.overflow = prev; + }; + } + }, [open]); + + const handleReorder = (newItems) => { + const newOrder = newItems.map((item) => item.id); + onColumnReorder?.(newOrder); + }; + + const content = ( + + {open && ( + + e.stopPropagation()} + > +
+
+ + 个性化设置 +
+ +
+ +
+

表头设置

+
+

+ 拖拽调整列顺序 +

+ {onResetColumnOrder && ( + + )} +
+ {columns.length === 0 ? ( +
+ 暂无可配置列 +
+ ) : ( + + + {columns.map((item, index) => ( + +
+ +
+ {item.header} + {onToggleColumnVisibility && ( + + )} +
+ ))} +
+
+ )} + {onResetSizing && ( + + )} +
+
+
+ )} + {resetOrderConfirmOpen && ( + { + onResetColumnOrder?.(); + onResetColumnVisibility?.(); + setResetOrderConfirmOpen(false); + }} + onCancel={() => setResetOrderConfirmOpen(false)} + confirmText="重置" + /> + )} +
+ ); + + if (typeof document === 'undefined') return null; + return createPortal(content, document.body); +}