mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-13 12:46:36 +08:00
feat: redesign forward card view completely syncing filters and sorting logic
This commit is contained in:
@@ -119,18 +119,7 @@ interface ForwardForm {
|
|||||||
strategy: string;
|
strategy: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加分组接口
|
|
||||||
interface UserGroup {
|
|
||||||
userId: number | null;
|
|
||||||
userName: string;
|
|
||||||
tunnelGroups: TunnelGroup[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TunnelGroup {
|
|
||||||
tunnelId: number;
|
|
||||||
tunnelName: string;
|
|
||||||
forwards: Forward[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ForwardPage() {
|
export default function ForwardPage() {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -233,21 +222,6 @@ export default function ForwardPage() {
|
|||||||
setViewMode(newMode);
|
setViewMode(newMode);
|
||||||
try {
|
try {
|
||||||
localStorage.setItem("forward-view-mode", newMode);
|
localStorage.setItem("forward-view-mode", newMode);
|
||||||
|
|
||||||
// 切换到直接显示模式时,初始化拖拽排序顺序
|
|
||||||
if (newMode === "direct") {
|
|
||||||
const currentUserId = JwtUtil.getUserIdFromToken();
|
|
||||||
const { order, fromDatabase } = buildForwardOrder(
|
|
||||||
forwards,
|
|
||||||
currentUserId,
|
|
||||||
);
|
|
||||||
|
|
||||||
setForwardOrder(order);
|
|
||||||
|
|
||||||
if (fromDatabase) {
|
|
||||||
saveOrder(FORWARD_ORDER_KEY, order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch { }
|
} catch { }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -270,7 +244,6 @@ export default function ForwardPage() {
|
|||||||
setForwards(forwardsData);
|
setForwards(forwardsData);
|
||||||
|
|
||||||
// 初始化拖拽排序顺序
|
// 初始化拖拽排序顺序
|
||||||
if (viewMode === "direct") {
|
|
||||||
const currentUserId = JwtUtil.getUserIdFromToken();
|
const currentUserId = JwtUtil.getUserIdFromToken();
|
||||||
const { order, fromDatabase } = buildForwardOrder(
|
const { order, fromDatabase } = buildForwardOrder(
|
||||||
forwardsData,
|
forwardsData,
|
||||||
@@ -282,7 +255,6 @@ export default function ForwardPage() {
|
|||||||
if (fromDatabase) {
|
if (fromDatabase) {
|
||||||
saveOrder(FORWARD_ORDER_KEY, order);
|
saveOrder(FORWARD_ORDER_KEY, order);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
toast.error(forwardsRes.msg || "获取转发列表失败");
|
toast.error(forwardsRes.msg || "获取转发列表失败");
|
||||||
}
|
}
|
||||||
@@ -298,52 +270,7 @@ export default function ForwardPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 按用户和隧道分组转发数据
|
|
||||||
const groupForwardsByUserAndTunnel = (): UserGroup[] => {
|
|
||||||
const userMap = new Map<string, UserGroup>();
|
|
||||||
|
|
||||||
// 获取排序后的转发列表
|
|
||||||
sortedForwards.forEach((forward) => {
|
|
||||||
const userKey = forward.userId ? forward.userId.toString() : "unknown";
|
|
||||||
const userName = forward.userName || "未知用户";
|
|
||||||
|
|
||||||
if (!userMap.has(userKey)) {
|
|
||||||
userMap.set(userKey, {
|
|
||||||
userId: forward.userId || null,
|
|
||||||
userName,
|
|
||||||
tunnelGroups: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const userGroup = userMap.get(userKey)!;
|
|
||||||
let tunnelGroup = userGroup.tunnelGroups.find(
|
|
||||||
(tg) => tg.tunnelId === forward.tunnelId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!tunnelGroup) {
|
|
||||||
tunnelGroup = {
|
|
||||||
tunnelId: forward.tunnelId,
|
|
||||||
tunnelName: forward.tunnelName,
|
|
||||||
forwards: [],
|
|
||||||
};
|
|
||||||
userGroup.tunnelGroups.push(tunnelGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
tunnelGroup.forwards.push(forward);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 排序:先按用户名,再按隧道名
|
|
||||||
const result = Array.from(userMap.values());
|
|
||||||
|
|
||||||
result.sort((a, b) => a.userName.localeCompare(b.userName));
|
|
||||||
result.forEach((userGroup) => {
|
|
||||||
userGroup.tunnelGroups.sort((a, b) =>
|
|
||||||
a.tunnelName.localeCompare(b.tunnelName),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 表单验证
|
// 表单验证
|
||||||
const validateForm = (): boolean => {
|
const validateForm = (): boolean => {
|
||||||
@@ -720,26 +647,10 @@ export default function ForwardPage() {
|
|||||||
setExportLoading(true);
|
setExportLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 根据当前显示模式获取要导出的转发列表
|
// 获取要导出的转发列表
|
||||||
let forwardsToExport: Forward[] = [];
|
const forwardsToExport = sortedForwards.filter(
|
||||||
|
|
||||||
if (viewMode === "grouped") {
|
|
||||||
// 分组模式下,获取指定隧道的转发
|
|
||||||
const userGroups = groupForwardsByUserAndTunnel();
|
|
||||||
|
|
||||||
forwardsToExport = userGroups.flatMap((userGroup) =>
|
|
||||||
userGroup.tunnelGroups
|
|
||||||
.filter(
|
|
||||||
(tunnelGroup) => tunnelGroup.tunnelId === selectedTunnelForExport,
|
|
||||||
)
|
|
||||||
.flatMap((tunnelGroup) => tunnelGroup.forwards),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// 直接显示模式下,过滤指定隧道的转发
|
|
||||||
forwardsToExport = sortedForwards.filter(
|
|
||||||
(forward) => forward.tunnelId === selectedTunnelForExport,
|
(forward) => forward.tunnelId === selectedTunnelForExport,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (forwardsToExport.length === 0) {
|
if (forwardsToExport.length === 0) {
|
||||||
toast.error("所选隧道没有转发数据");
|
toast.error("所选隧道没有转发数据");
|
||||||
@@ -1181,16 +1092,8 @@ export default function ForwardPage() {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在平铺模式下,只显示当前用户的转发
|
|
||||||
let filteredForwards = forwards;
|
let filteredForwards = forwards;
|
||||||
|
|
||||||
if (viewMode === "direct") {
|
|
||||||
if (tokenUserId !== null) {
|
|
||||||
filteredForwards = forwards.filter(
|
|
||||||
(forward) => forward.userId === tokenUserId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (viewMode === "grouped") {
|
|
||||||
if (filterUserId !== "all") {
|
if (filterUserId !== "all") {
|
||||||
const targetUserId = parseInt(filterUserId);
|
const targetUserId = parseInt(filterUserId);
|
||||||
filteredForwards = filteredForwards.filter(f => f.userId === targetUserId || (targetUserId === 0 && !f.userId));
|
filteredForwards = filteredForwards.filter(f => f.userId === targetUserId || (targetUserId === 0 && !f.userId));
|
||||||
@@ -1199,7 +1102,6 @@ export default function ForwardPage() {
|
|||||||
const targetTunnelId = parseInt(filterTunnelId);
|
const targetTunnelId = parseInt(filterTunnelId);
|
||||||
filteredForwards = filteredForwards.filter(f => f.tunnelId === targetTunnelId);
|
filteredForwards = filteredForwards.filter(f => f.tunnelId === targetTunnelId);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 确保过滤后的转发列表有效
|
// 确保过滤后的转发列表有效
|
||||||
if (!filteredForwards || filteredForwards.length === 0) {
|
if (!filteredForwards || filteredForwards.length === 0) {
|
||||||
@@ -1288,7 +1190,7 @@ export default function ForwardPage() {
|
|||||||
}, [forwards]);
|
}, [forwards]);
|
||||||
|
|
||||||
// 可拖拽的表格行组件
|
// 可拖拽的表格行组件
|
||||||
const SortableTableRow = ({ forward, selectMode, selectedIds, toggleSelect, getStrategyDisplay, formatInAddress, formatRemoteAddress, handleServiceToggle, handleEdit, handleDelete, handleDiagnose, showAddressModal, hasMultipleAddresses }: any) => {
|
const SortableTableRow = ({ forward, selectMode, selectedIds, toggleSelect, getStrategyDisplay, formatInAddress, formatRemoteAddress, handleServiceToggle, handleEdit, handleDelete, handleDiagnose, showAddressModal, hasMultipleAddresses, formatFlow }: any) => {
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
listeners,
|
listeners,
|
||||||
@@ -1386,6 +1288,11 @@ export default function ForwardPage() {
|
|||||||
{strategyDisplay.text}
|
{strategyDisplay.text}
|
||||||
</Chip>
|
</Chip>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">
|
||||||
|
<span className="text-sm font-medium text-default-600 font-mono">
|
||||||
|
{formatFlow((forward.inFlow || 0) + (forward.outFlow || 0))}
|
||||||
|
</span>
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="flex items-center gap-2.5 whitespace-nowrap">
|
<div className="flex items-center gap-2.5 whitespace-nowrap">
|
||||||
<Switch
|
<Switch
|
||||||
@@ -1705,8 +1612,7 @@ export default function ForwardPage() {
|
|||||||
<div className="flex items-center justify-between mb-6 gap-2">
|
<div className="flex items-center justify-between mb-6 gap-2">
|
||||||
<div className="flex-1"></div>
|
<div className="flex-1"></div>
|
||||||
<div className="flex flex-wrap items-center justify-end gap-2 sm:gap-3">
|
<div className="flex flex-wrap items-center justify-end gap-2 sm:gap-3">
|
||||||
{/* 筛选按钮 (仅在分组视图显示) */}
|
{/* 筛选按钮 */}
|
||||||
{viewMode === "grouped" && (
|
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
aria-label="筛选条件"
|
aria-label="筛选条件"
|
||||||
@@ -1735,7 +1641,6 @@ export default function ForwardPage() {
|
|||||||
<span className="absolute top-1.5 right-1.5 flex h-1.5 w-1.5 rounded-full bg-primary" />
|
<span className="absolute top-1.5 right-1.5 flex h-1.5 w-1.5 rounded-full bg-primary" />
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
|
||||||
{/* 显示模式切换按钮 */}
|
{/* 显示模式切换按钮 */}
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
@@ -1905,6 +1810,7 @@ export default function ForwardPage() {
|
|||||||
<TableColumn>入口</TableColumn>
|
<TableColumn>入口</TableColumn>
|
||||||
<TableColumn>目标</TableColumn>
|
<TableColumn>目标</TableColumn>
|
||||||
<TableColumn>策略</TableColumn>
|
<TableColumn>策略</TableColumn>
|
||||||
|
<TableColumn>总流量</TableColumn>
|
||||||
<TableColumn>状态</TableColumn>
|
<TableColumn>状态</TableColumn>
|
||||||
<TableColumn className="text-right">操作</TableColumn>
|
<TableColumn className="text-right">操作</TableColumn>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
@@ -1925,6 +1831,7 @@ export default function ForwardPage() {
|
|||||||
handleDiagnose={handleDiagnose}
|
handleDiagnose={handleDiagnose}
|
||||||
showAddressModal={showAddressModal}
|
showAddressModal={showAddressModal}
|
||||||
hasMultipleAddresses={hasMultipleAddresses}
|
hasMultipleAddresses={hasMultipleAddresses}
|
||||||
|
formatFlow={formatFlow}
|
||||||
/>
|
/>
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user