From 7dc5cdb7f22e680f7d72af33da7d9cf84d310f33 Mon Sep 17 00:00:00 2001 From: attacker Date: Wed, 17 Jun 2026 01:06:38 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8B=86=E5=88=86ServerManager.tsx?= =?UTF-8?q?(645=E2=86=92462=E8=A1=8C)=E6=8F=90=E5=8F=96ServerTableRow+serv?= =?UTF-8?q?erHelpers=E5=AD=90=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/server/ServerManager.tsx | 209 ++---------------- .../src/components/server/ServerTableRow.tsx | 166 ++++++++++++++ .../src/components/server/serverHelpers.tsx | 63 ++++++ 3 files changed, 242 insertions(+), 196 deletions(-) create mode 100644 frontend/src/components/server/ServerTableRow.tsx create mode 100644 frontend/src/components/server/serverHelpers.tsx diff --git a/frontend/src/components/server/ServerManager.tsx b/frontend/src/components/server/ServerManager.tsx index d24d55f..b124e11 100644 --- a/frontend/src/components/server/ServerManager.tsx +++ b/frontend/src/components/server/ServerManager.tsx @@ -31,13 +31,9 @@ import { import { Search, Plus, - MoreHorizontal, - Terminal, Trash2, - Edit, Download, Upload, - Server as ServerIcon, Cloud, FileSpreadsheet, RefreshCw, @@ -46,11 +42,12 @@ import { serverApi } from '@/services/api'; import { ServerStatsCards } from './ServerStatsCards'; import { useConfirm } from '@/components/ui/confirm-dialog'; import { toast } from 'sonner'; -import type { Server as ServerType } from '@/types'; import { CloudServerImport } from './CloudServerImport'; import { TerminalDialog } from './TerminalDialog'; import { ExcelServerImport } from './ExcelServerImport'; import { ServerForm, EMPTY_FORM, type ServerFormData } from './ServerForm'; +import { getTags } from './serverHelpers'; +import { ServerTableRow } from './ServerTableRow'; export function ServerManager() { const confirm = useConfirm(); @@ -95,27 +92,6 @@ export function ServerManager() { loadData(); }, []); - // 解析标签:后端 tags 可能是 JSON 字符串(JSON数组/对象)、逗号分隔字符串或数组 // Logan.Li - const getTags = (server: any): string[] => { - const tags = server.tags; - if (!tags) return []; - if (Array.isArray(tags)) return tags; - try { - const parsed = JSON.parse(tags); - if (Array.isArray(parsed)) return parsed; - // JSON 对象 → key:value 格式展示(如 project:prod) // Logan.Li - if (typeof parsed === 'object' && parsed !== null) { - return Object.entries(parsed).map(([k, v]) => `${k}:${String(v)}`); - } - return [String(parsed)]; - } catch { - return String(tags) - .split(',') - .map((t: string) => t.trim()) - .filter(Boolean); - } - }; - const filteredServers = servers.filter((server) => { const matchesSearch = (server.hostname || '').toLowerCase().includes(searchQuery.toLowerCase()) || @@ -276,39 +252,6 @@ export function ServerManager() { toast.success(`已导出 ${filteredServers.length} 台服务器`); }; - const getStatusBadge = (status: ServerType['status']) => { - switch (status) { - case 'running': - return ( - -
- 运行中 - - ); - case 'stopped': - return ( - - 已停止 - - ); - case 'maintenance': - return ( - -
- 维护中 - - ); - case 'offline': - return ( - - 离线 - - ); - default: - return null; - } - }; - const colSpanCount = 8; return ( @@ -459,143 +402,17 @@ export function ServerManager() { ) : ( - filteredServers.map((server) => { - const cpuUsage = Number(server.cpu_usage || 0); - const memoryUsage = Number(server.memory_usage || 0); - const tags = getTags(server); - const memGB = server.memory ? Math.round(server.memory / 1024) : 0; - return ( - - - toggleSelect(server.id)} - className="border-[var(--dg-border)]" - /> - - -
- -
-

{server.hostname}

-

{server.os}

-
-
-
- - - {server.ip} - - - - {server.public_ip ? ( - - {server.public_ip} - - ) : ( - - - )} - - {getStatusBadge(server.status)} - -
- {server.cpu}核 - / - {memGB}GB - / - {server.disk}GB -
-
- -
-
- CPU -
-
80 ? 'bg-red-400' : cpuUsage > 60 ? 'bg-amber-400' : 'bg-emerald-400' - )} - style={{ width: `${cpuUsage}%` }} - /> -
- {cpuUsage.toFixed(1)}% -
-
- 内存 -
-
80 ? 'bg-red-400' : memoryUsage > 60 ? 'bg-amber-400' : 'bg-emerald-400' - )} - style={{ width: `${memoryUsage}%` }} - /> -
- {memoryUsage.toFixed(1)}% -
-
- - -
- {tags.slice(0, 3).map((tag) => ( - - {tag} - - ))} - {tags.length > 3 && ( - - +{tags.length - 3} - - )} -
-
- -
- - - - - - - 操作 - - openEditForm(server)} - > - - 编辑 - - openTerminal(server)} - > - - 终端 - - - handleDelete(server.id)} - > - - 删除 - - - -
-
- - ); - }) + filteredServers.map((server) => ( + + )) )} diff --git a/frontend/src/components/server/ServerTableRow.tsx b/frontend/src/components/server/ServerTableRow.tsx new file mode 100644 index 0000000..7542e86 --- /dev/null +++ b/frontend/src/components/server/ServerTableRow.tsx @@ -0,0 +1,166 @@ +// 服务器表格行 — 纯展示子组件(接收 props,不直接调 API) // Logan.Li +import { cn } from '@/lib/utils'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { Checkbox } from '@/components/ui/checkbox'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { TableCell, TableRow } from '@/components/ui/table'; +import { Edit, MoreHorizontal, Server as ServerIcon, Terminal, Trash2 } from 'lucide-react'; +import { getStatusBadge, getTags, getUsageColor } from './serverHelpers'; + +interface ServerTableRowProps { + server: any; + selected: boolean; + onToggleSelect: (id: string) => void; + onOpenTerminal: (server: any) => void; + onOpenEdit: (server: any) => void; + onDelete: (id: string) => void; +} + +export function ServerTableRow({ + server, + selected, + onToggleSelect, + onOpenTerminal, + onOpenEdit, + onDelete, +}: ServerTableRowProps) { + const cpuUsage = Number(server.cpu_usage || 0); + const memoryUsage = Number(server.memory_usage || 0); + const tags = getTags(server); + const memGB = server.memory ? Math.round(server.memory / 1024) : 0; + + return ( + + + onToggleSelect(server.id)} + className="border-[var(--dg-border)]" + /> + + +
+ +
+

{server.hostname}

+

{server.os}

+
+
+
+ + + {server.ip} + + + + {server.public_ip ? ( + + {server.public_ip} + + ) : ( + - + )} + + {getStatusBadge(server.status)} + +
+ {server.cpu}核 + / + {memGB}GB + / + {server.disk}GB +
+
+ +
+
+ CPU +
+
+
+ {cpuUsage.toFixed(1)}% +
+
+ 内存 +
+
+
+ {memoryUsage.toFixed(1)}% +
+
+ + +
+ {tags.slice(0, 3).map((tag) => ( + + {tag} + + ))} + {tags.length > 3 && ( + + +{tags.length - 3} + + )} +
+
+ +
+ + + + + + + 操作 + + onOpenEdit(server)} + > + + 编辑 + + onOpenTerminal(server)} + > + + 终端 + + + onDelete(server.id)} + > + + 删除 + + + +
+
+ + ); +} diff --git a/frontend/src/components/server/serverHelpers.tsx b/frontend/src/components/server/serverHelpers.tsx new file mode 100644 index 0000000..ac899b9 --- /dev/null +++ b/frontend/src/components/server/serverHelpers.tsx @@ -0,0 +1,63 @@ +// 服务器管理共享纯函数/常量 // Logan.Li +import { Badge } from '@/components/ui/badge'; +import type { Server as ServerType } from '@/types'; + +// 解析标签:后端 tags 可能是 JSON 字符串(JSON数组/对象)、逗号分隔字符串或数组 // Logan.Li +export function getTags(server: any): string[] { + const tags = server.tags; + if (!tags) return []; + if (Array.isArray(tags)) return tags; + try { + const parsed = JSON.parse(tags); + if (Array.isArray(parsed)) return parsed; + // JSON 对象 → key:value 格式展示(如 project:prod) // Logan.Li + if (typeof parsed === 'object' && parsed !== null) { + return Object.entries(parsed).map(([k, v]) => `${k}:${String(v)}`); + } + return [String(parsed)]; + } catch { + return String(tags) + .split(',') + .map((t: string) => t.trim()) + .filter(Boolean); + } +} + +// 服务器状态徽章 // Logan.Li +export function getStatusBadge(status: ServerType['status']) { + switch (status) { + case 'running': + return ( + +
+ 运行中 + + ); + case 'stopped': + return ( + + 已停止 + + ); + case 'maintenance': + return ( + +
+ 维护中 + + ); + case 'offline': + return ( + + 离线 + + ); + default: + return null; + } +} + +// 使用率进度条颜色(CPU/内存通用)— 绿色<60% 黄色60-80% 红色>80% // Logan.Li +export function getUsageColor(usage: number): string { + return usage > 80 ? 'bg-red-400' : usage > 60 ? 'bg-amber-400' : 'bg-emerald-400'; +}