From abc9f21ab9b34f5f360dc87b6e875b2965cdbda5 Mon Sep 17 00:00:00 2001 From: sagitchu Date: Fri, 20 Feb 2026 19:27:40 +0800 Subject: [PATCH] feat: improve forward page grouped view --- vite-frontend/src/pages/forward.tsx | 435 +++++++++++------- .../src/shadcn-bridge/heroui/table.tsx | 45 +- 2 files changed, 293 insertions(+), 187 deletions(-) diff --git a/vite-frontend/src/pages/forward.tsx b/vite-frontend/src/pages/forward.tsx index 7508435..c437900 100644 --- a/vite-frontend/src/pages/forward.tsx +++ b/vite-frontend/src/pages/forward.tsx @@ -15,6 +15,7 @@ import { SortableContext, sortableKeyboardCoordinates, rectSortingStrategy, + verticalListSortingStrategy, } from "@dnd-kit/sortable"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; @@ -143,11 +144,15 @@ export default function ForwardPage() { const savedMode = localStorage.getItem("forward-view-mode"); return (savedMode as "grouped" | "direct") || "direct"; - } catch { + } catch (e) { return "direct"; } }); + // 筛选状态 + const [filterUserId, setFilterUserId] = useState("all"); + const [filterTunnelId, setFilterTunnelId] = useState("all"); + // 拖拽排序相关状态 const [forwardOrder, setForwardOrder] = useState([]); @@ -1184,6 +1189,15 @@ export default function ForwardPage() { (forward) => forward.userId === tokenUserId, ); } + } else if (viewMode === "grouped") { + if (filterUserId !== "all") { + const targetUserId = parseInt(filterUserId); + filteredForwards = filteredForwards.filter(f => f.userId === targetUserId || (targetUserId === 0 && !f.userId)); + } + if (filterTunnelId !== "all") { + const targetTunnelId = parseInt(filterTunnelId); + filteredForwards = filteredForwards.filter(f => f.tunnelId === targetTunnelId); + } } // 确保过滤后的转发列表有效 @@ -1227,7 +1241,7 @@ export default function ForwardPage() { } return sortedByDb; - }, [forwards, forwardOrder, viewMode, tokenUserId]); + }, [forwards, forwardOrder, viewMode, tokenUserId, filterUserId, filterTunnelId]); const sortableForwardIds = useMemo( () => sortedForwards.map((f) => f.id).filter((id) => id > 0), @@ -1259,6 +1273,170 @@ export default function ForwardPage() { ); }; + // 生成用作筛选项的用户和隧道列表 + const uniqueUsers = useMemo(() => { + const userMap = new Map(); + forwards.forEach((f) => { + const uId = f.userId || 0; + if (!userMap.has(uId)) { + userMap.set(uId, { id: uId, name: f.userName || "未知用户" }); + } + }); + + return Array.from(userMap.values()); + }, [forwards]); + + // 可拖拽的表格行组件 + const SortableTableRow = ({ forward, selectMode, selectedIds, toggleSelect, getStrategyDisplay, formatInAddress, formatRemoteAddress, handleServiceToggle, handleEdit, handleDelete, handleDiagnose, showAddressModal, hasMultipleAddresses }: any) => { + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ id: forward.id }); + + const style = { + transform: transform ? CSS.Transform.toString(transform) : undefined, + transition: isDragging ? undefined : transition || undefined, + opacity: isDragging ? 0.5 : 1, + backgroundColor: isDragging ? "var(--nextui-default-100)" : undefined, + }; + + const strategyDisplay = getStrategyDisplay(forward.strategy); + + return ( + + {selectMode && ( + + toggleSelect(forward.id)} + /> + + )} + +
+ +
+
+ + + {forward.userName || "未知用户"} + + + + + {forward.tunnelName} + + + + {forward.name} + + + + + + + + + + {strategyDisplay.text} + + + +
+ handleServiceToggle(forward)} + /> +
+
+ +
+ + + +
+
+
+ ); + }; + // 渲染转发卡片 const renderForwardCard = (forward: Forward, listeners?: any) => { const statusDisplay = getStatusDisplay(forward.status); @@ -1524,7 +1702,45 @@ export default function ForwardPage() {
{/* 页面头部 */}
-
+
+ {viewMode === "grouped" && ( + <> + + + + + )} +
{/* 显示模式切换按钮 */}