import { useState, useEffect, useCallback } from 'react'; import { useParams, Link } from 'react-router-dom'; import { ChevronRight, Cloud, Boxes, Container, Network, FileText, Shield, Activity, Clock, } from 'lucide-react'; import { kubernetesApi } from '@/api'; import type { JsonData } from '@/types/common'; const RESOURCE_LINKS = [ { type: 'deployments', label: 'Deployments', icon: Boxes, desc: '工作负载副本管理' }, { type: 'pods', label: 'Pods', icon: Container, desc: '容器实例运行状态' }, { type: 'cronjobs', label: 'CronJobs', icon: Clock, desc: '定时任务管理' }, { type: 'services', label: 'Services', icon: Network, desc: '服务发现与负载均衡' }, { type: 'ingresses', label: 'Ingresses', icon: Network, desc: '外部流量路由规则' }, { type: 'configmaps', label: 'ConfigMaps', icon: FileText, desc: '配置字典' }, { type: 'secrets', label: 'Secrets', icon: Shield, desc: '密钥与凭证' }, { type: 'hpas', label: 'HPAs', icon: Activity, desc: '水平自动伸缩策略' }, ]; export default function NamespaceOverviewPage() { const { clusterCode, namespace } = useParams<{ clusterCode: string; namespace: string }>(); const [counts, setCounts] = useState>({}); const [loading, setLoading] = useState(false); const loadCounts = useCallback(async () => { if (!clusterCode || !namespace) return; setLoading(true); try { const results = await Promise.allSettled([ kubernetesApi.getNamespaceDeployments(clusterCode, namespace!), kubernetesApi.getNamespacePods(clusterCode, namespace!), kubernetesApi.getNamespaceServices(clusterCode, namespace!), kubernetesApi.getNamespaceIngresses(clusterCode, namespace!), kubernetesApi.getNamespaceConfigMaps(clusterCode, namespace!), kubernetesApi.getNamespaceSecrets(clusterCode, namespace!), kubernetesApi.getHPAs(clusterCode, namespace!), kubernetesApi.getCronJobs(clusterCode, namespace!), ]); const toArr = (v: JsonData) => Array.isArray(v) ? v : (v?.list || v?.data || []); setCounts({ deployments: toArr(results[0].status === 'fulfilled' ? results[0].value : []).length, pods: toArr(results[1].status === 'fulfilled' ? results[1].value : []).length, services: toArr(results[2].status === 'fulfilled' ? results[2].value : []).length, ingresses: toArr(results[3].status === 'fulfilled' ? results[3].value : []).length, configmaps: toArr(results[4].status === 'fulfilled' ? results[4].value : []).length, secrets: toArr(results[5].status === 'fulfilled' ? results[5].value : []).length, hpas: toArr(results[6].status === 'fulfilled' ? results[6].value : []).length, cronjobs: toArr(results[7].status === 'fulfilled' ? results[7].value : []).length, }); } catch { setCounts({}); } finally { setLoading(false); } }, [clusterCode, namespace]); useEffect(() => { loadCounts(); }, [loadCounts]); return (
{/* Breadcrumb */}
集群 {clusterCode} {namespace}
{/* Header */}

{namespace}

命名空间概览

{/* Resource grid */}
{RESOURCE_LINKS.map((r) => (
{loading ? '-' : (counts[r.type] ?? 0)}
{r.label}
{r.desc}
))}
); }