import { useState, useEffect, useCallback, useMemo } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { RefreshCw, ChevronRight, Bell, AlertTriangle, X } from 'lucide-react'; import { kubernetesApi } from '@/api'; import { EventTable } from './EventTable'; import { normalizeK8sEvent, formatEventRelative } from './k8s-event-utils'; import type { JsonData } from '@/types/common'; interface RankItem { name: string; count: number } // 简洁排名列表,替代花哨柱状图 // Logan.Li function RankPanel({ title, items, selected, onSelect, emptyText, }: { title: string; items: RankItem[]; selected?: string; onSelect?: (name: string) => void; emptyText?: string; }) { const max = Math.max(...items.map((i) => i.count), 1); return (

{title}

{items.length === 0 ? (

{emptyText || '暂无数据'}

) : (
{items.map((item) => { const active = selected === item.name; return ( ); })}
)}
); } function StatCell({ label, value, hint }: { label: string; value: number | string; hint?: string }) { return (

{label}

{value}

{hint &&

{hint}

}
); } export default function EventsPage() { const { clusterCode } = useParams<{ clusterCode: string }>(); const navigate = useNavigate(); const [loading, setLoading] = useState(false); const [events, setEvents] = useState([]); const [clusters, setClusters] = useState([]); const [namespaces, setNamespaces] = useState([]); const [selectedNs, setSelectedNs] = useState('all'); const [filterType, setFilterType] = useState('all'); const [timeWindow, setTimeWindow] = useState('0'); const [activeCluster, setActiveCluster] = useState(clusterCode || ''); const [summary, setSummary] = useState(null); const [selectedReason, setSelectedReason] = useState(''); const [selectedKind, setSelectedKind] = useState(''); useEffect(() => { kubernetesApi.getClusters().then((res: JsonData) => { const list = res?.list || []; setClusters(list); if (!activeCluster && list.length > 0) { const code = list[0].code || String(list[0].id); setActiveCluster(code); navigate(`/kubernetes/${code}/events`, { replace: true }); } }).catch(() => {}); }, []); useEffect(() => { if (!activeCluster) return; kubernetesApi.getNamespaces(activeCluster).then((res: JsonData) => { setNamespaces(Array.isArray(res) ? res : (res?.list || res?.data || [])); }).catch(() => {}); }, [activeCluster]); const loadEvents = useCallback(async () => { if (!activeCluster) return; setLoading(true); try { const ns = selectedNs === 'all' ? undefined : selectedNs; const ft = filterType === 'all' ? undefined : filterType; const res: JsonData = await kubernetesApi.getEvents(activeCluster, ns, ft); setEvents(Array.isArray(res) ? res : (res?.list || [])); } catch { setEvents([]); } finally { setLoading(false); } }, [activeCluster, selectedNs, filterType]); const loadSummary = useCallback(async () => { if (!activeCluster) return; try { const ns = selectedNs === 'all' ? undefined : selectedNs; const hours = parseInt(timeWindow) || undefined; const res: JsonData = await kubernetesApi.getEventsSummary(activeCluster, ns, hours); setSummary(res || null); } catch { setSummary(null); } }, [activeCluster, selectedNs, timeWindow]); useEffect(() => { loadEvents(); }, [loadEvents]); useEffect(() => { loadSummary(); }, [loadSummary]); const displayEvents = useMemo(() => { let filtered = events.map((e) => normalizeK8sEvent(e)); const hours = parseInt(timeWindow, 10); if (hours > 0) { const since = Date.now() - hours * 3600 * 1000; filtered = filtered.filter((e) => !e.lastTime || new Date(e.lastTime).getTime() >= since); } if (selectedReason) filtered = filtered.filter((e) => e.reason === selectedReason); if (selectedKind) { filtered = filtered.filter((e) => e.objectKind === selectedKind || e.object.startsWith(`${selectedKind}/`), ); } return filtered; }, [events, selectedReason, selectedKind, timeWindow]); const warningCount = useMemo(() => events.filter((e) => e.type === 'Warning').length, [events]); const normalCount = useMemo(() => events.filter((e) => e.type === 'Normal').length, [events]); const reasonData = useMemo(() => (summary?.by_reason || []).map((r: JsonData) => ({ name: r.reason || 'Unknown', count: r.count })), [summary]); const nsData = useMemo(() => (summary?.by_namespace || []).map((n: JsonData) => ({ name: n.namespace || '', count: n.count })), [summary]); const kindData = useMemo(() => (summary?.by_kind || []).map((k: JsonData) => ({ name: k.kind || 'Unknown', count: k.count })), [summary]); return (
集群 {activeCluster && ( <> {activeCluster} )} 事件

事件中心

{/* 统计条:统一边框,无彩色卡片 */}
{(selectedReason || selectedKind) && (
筛选: {selectedReason && ( )} {selectedKind && ( )}
)} {reasonData.length > 0 && (
{nsData.length > 0 && } {kindData.length > 0 && ( )}
)} {summary?.recent_warnings?.length > 0 && (

最新告警 ({summary.recent_warnings.length})

{summary.recent_warnings.map((w: JsonData, i: number) => (
{w.reason} {w.object} {w.namespace} {w.source && {w.source}} ×{w.count} {formatEventRelative(w.last_time)}

{w.message}

))}
)}
事件列表 ({displayEvents.length})
); }