-
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';
+}