import { useState, useEffect, useCallback } from 'react'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { RefreshCw, Search, Server, Loader2 } from 'lucide-react'; import { kubernetesApi } from '@/api'; import type { JsonData } from '@/types/common'; export function KubernetesNodes() { const [clusters, setClusters] = useState([]); const [selectedCluster, setSelectedCluster] = useState(''); const [nodes, setNodes] = useState([]); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(''); const [roleFilter, setRoleFilter] = useState('all'); const loadClusters = useCallback(async () => { try { const res: JsonData = await kubernetesApi.getClusters(); const list = res?.list || []; setClusters(list); if (list.length > 0 && !selectedCluster) setSelectedCluster(String(list[0].id)); } catch { setClusters([]); } }, []); useEffect(() => { loadClusters(); }, [loadClusters]); const loadNodes = useCallback(async () => { if (!selectedCluster) return; setLoading(true); try { const res: JsonData = await kubernetesApi.getNodes(selectedCluster); setNodes(Array.isArray(res) ? res : (res?.list || [])); } catch { setNodes([]); } finally { setLoading(false); } }, [selectedCluster]); useEffect(() => { loadNodes(); }, [loadNodes]); const filtered = nodes.filter((n) => (n.name || '').toLowerCase().includes(search.toLowerCase()) && (roleFilter === 'all' || n.role === roleFilter), ); const getRoleBadge = (role: string) => role === 'master' ? Master : Worker; const getStatusBadge = (status: string) => status === 'Ready' ? {status} : {status || 'Unknown'}; return (

节点管理

Kubernetes 集群工作节点状态与资源

setSearch(e.target.value)} className="pl-9 h-9 bg-slate-800/50 border-slate-700 text-slate-200" />
节点名称 IP 角色 状态 配置 使用率 Pods Kubelet {loading ? ( 加载中... ) : filtered.length === 0 ? ( {selectedCluster ? '暂无节点数据' : '请选择集群'} ) : ( filtered.map((n) => ( {n.name} {n.ip || '-'} {getRoleBadge(n.role)} {getStatusBadge(n.status)} {n.cpu ? `${n.cpu}核` : '-'} / {n.memory ? `${Math.round(n.memory / 1024)}GB` : '-'} {(() => { const cpu = n.cpu_usage || 0; const mem = n.memory_usage || 0; const bar = (val: number) => val >= 85 ? 'bg-red-500' : val >= 60 ? 'bg-yellow-500' : 'bg-emerald-500'; const txt = (val: number) => val >= 85 ? 'text-red-400' : val >= 60 ? 'text-yellow-400' : 'text-emerald-400'; return (
CPU
{cpu.toFixed(0)}%
Mem
{mem.toFixed(0)}%
); })()} {n.pod_count || 0} / {n.max_pods || '-'} {n.kubelet_version || '-'} )) )}
); }