From f2ee9390065a2016e7f684e3cdc8cc1492476cd8 Mon Sep 17 00:00:00 2001 From: sagitchu Date: Sun, 15 Mar 2026 22:12:33 +0800 Subject: [PATCH] Restore BatchActionResultModal usage in tunnel.tsx --- plans/039-restore-removed-features-pr322.md | 4 +- vite-frontend/src/pages/tunnel.tsx | 125 +++++++++++++++++--- 2 files changed, 114 insertions(+), 15 deletions(-) diff --git a/plans/039-restore-removed-features-pr322.md b/plans/039-restore-removed-features-pr322.md index ebd1ee2..6a56669 100644 --- a/plans/039-restore-removed-features-pr322.md +++ b/plans/039-restore-removed-features-pr322.md @@ -23,7 +23,8 @@ PR #322 (https://github.com/Sagit-chu/flvx/pull/322) 原本移除了三个功能 - [x] 恢复 `use-dashboard-data.ts` 中的 `expiryReminderDismissed` 过滤逻辑 - [x] 恢复 `batch-actions.ts` 中的 `BatchOperationFailure` 相关处理 - [x] 恢复 `forward.tsx` 中的 `BatchActionResultModal` 使用 -- [x] 提交并推送修改 +- [x] 恢复 `tunnel.tsx` 中的 `BatchActionResultModal` 使用 +- [ ] 提交并推送修改 ## 修改的文件 @@ -34,6 +35,7 @@ PR #322 (https://github.com/Sagit-chu/flvx/pull/322) 原本移除了三个功能 - `vite-frontend/src/pages/dashboard/use-dashboard-data.ts` - 恢复 `expiryReminderDismissed` 过滤逻辑 - `vite-frontend/src/pages/forward/batch-actions.ts` - 恢复批量操作失败处理 - `vite-frontend/src/pages/forward.tsx` - 恢复 `BatchActionResultModal` 组件使用 +- `vite-frontend/src/pages/tunnel.tsx` - 恢复 `BatchActionResultModal` 组件使用 ## 注意事项 diff --git a/vite-frontend/src/pages/tunnel.tsx b/vite-frontend/src/pages/tunnel.tsx index bbf43fb..9d24970 100644 --- a/vite-frontend/src/pages/tunnel.tsx +++ b/vite-frontend/src/pages/tunnel.tsx @@ -1,3 +1,5 @@ +import type { BatchOperationFailure } from "@/api/types"; + import { useState, useEffect, useMemo, useRef, useCallback } from "react"; import toast from "react-hot-toast"; import { @@ -20,6 +22,7 @@ import { CSS } from "@dnd-kit/utilities"; import { SearchBar } from "@/components/search-bar"; import { AnimatedPage } from "@/components/animated-page"; +import { BatchActionResultModal } from "@/components/batch-action-result-modal"; import { Card, CardBody, CardHeader } from "@/shadcn-bridge/heroui/card"; import { Button } from "@/shadcn-bridge/heroui/button"; import { Input, Textarea } from "@/shadcn-bridge/heroui/input"; @@ -63,7 +66,11 @@ import { } from "@/pages/tunnel/form"; import { useLocalStorageState } from "@/hooks/use-local-storage-state"; import { loadStoredOrder, saveOrder } from "@/utils/order-storage"; -import { extractApiErrorMessage } from "@/api/error-message"; +import { + buildBatchFailureMessage, + extractBatchFailures, + extractApiErrorMessage, +} from "@/api/error-message"; interface ChainTunnel { nodeId: number; @@ -122,6 +129,20 @@ interface BatchProgressState { percent: number; } +interface BatchResultModalState { + failures: BatchOperationFailure[]; + open: boolean; + summary: string; + title: string; +} + +const EMPTY_BATCH_RESULT_MODAL_STATE: BatchResultModalState = { + failures: [], + open: false, + summary: "", + title: "", +}; + const TUNNEL_ORDER_KEY = "tunnel-order"; const mapTunnelApiItems = (items: any[]): Tunnel[] => { @@ -232,6 +253,8 @@ export default function TunnelPage() { label: "", percent: 0, }); + const [batchResultModal, setBatchResultModal] = + useState(EMPTY_BATCH_RESULT_MODAL_STATE); useEffect(() => { return () => { @@ -358,7 +381,7 @@ export default function TunnelPage() { }); setErrors({}); setModalOpen(true); - }; + }; // 删除隧道 const handleDelete = (tunnel: Tunnel) => { @@ -842,6 +865,18 @@ export default function TunnelPage() { setSelectedIds(new Set()); }; + const openBatchResultModal = useCallback( + (title: string, summary: string, failures: BatchOperationFailure[]) => { + setBatchResultModal({ + failures, + open: true, + summary, + title, + }); + }, + [], + ); + const handleBatchDelete = async () => { if (selectedIds.size === 0) return; setBatchLoading(true); @@ -874,9 +909,19 @@ export default function TunnelPage() { return next; }); } else { - toast.error( - `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, - ); + const failures = extractBatchFailures(result); + + if (failures.length > 0) { + openBatchResultModal( + "批量删除结果", + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + failures, + ); + } else { + toast.error( + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + ); + } setBatchProgress({ active: true, label: `部分完成:成功 ${result.successCount} 项,正在刷新列表...`, @@ -915,9 +960,22 @@ export default function TunnelPage() { if (result.failCount === 0) { toast.success(`成功重新下发 ${result.successCount} 项`); } else { - toast.error( - `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, - ); + const failures = extractBatchFailures(result); + + if (failures.length > 0) { + openBatchResultModal( + "批量下发结果", + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + failures, + ); + } else { + toast.error( + buildBatchFailureMessage( + result, + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + ), + ); + } } setSelectedIds(new Set()); setSelectMode(false); @@ -1204,7 +1262,21 @@ export default function TunnelPage() { -
+
+ +
@@ -1343,7 +1415,6 @@ export default function TunnelPage() { )} -
@@ -1442,8 +1513,11 @@ export default function TunnelPage() { )} {/* 新增/编辑模态框 */} - {/* 删除确认模态框 */} - - @@ -3030,6 +3113,20 @@ export default function TunnelPage() { )} + + { + if (open) { + setBatchResultModal((prev) => ({ ...prev, open: true })); + return; + } + setBatchResultModal(EMPTY_BATCH_RESULT_MODAL_STATE); + }} + /> ); }