// PodLogsModal.tsx — Pod 日志弹窗(带容器切换 + 行数 + 实时流) // 作者: Logan.Li import { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { FileText, RefreshCw, Loader2, X } from 'lucide-react'; import { kubernetesApi } from '@/api'; import { useToast } from '@/hooks/use-toast'; import { useUserStore } from '@/store'; export interface PodLogsModalProps { clusterCode: string; namespace: string; podName: string; containers: string[]; onClose: () => void; } export function PodLogsModal({ clusterCode, namespace, podName, containers, onClose }: PodLogsModalProps) { const { toast } = useToast(); const [logs, setLogs] = useState(''); const [tail, setTail] = useState(200); const [container, setContainer] = useState(containers[0] || ''); const [loading, setLoading] = useState(false); const [streaming, setStreaming] = useState(false); const loadLogs = async () => { setLoading(true); try { const res: Record = await kubernetesApi.getPodLogs(clusterCode, namespace, podName, tail, container || undefined); setLogs(res?.data?.logs || res?.logs || res || '无日志'); } catch { setLogs('获取日志失败'); } finally { setLoading(false); } }; useEffect(() => { loadLogs(); }, [container, tail]); const startStream = async () => { setStreaming(true); const token = useUserStore.getState().token || ''; const baseUrl = import.meta.env.VITE_API_BASE_URL || ''; const cParam = container ? `&container=${encodeURIComponent(container)}` : ''; const url = `${baseUrl}/api/v1/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/logs?tail=${tail}&stream=true${cParam}`; try { const resp = await fetch(url, { headers: { Authorization: `Bearer ${token}` } }); const reader = resp.body?.getReader(); if (!reader) return; const decoder = new TextDecoder(); let buf = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); setLogs(buf); } } catch { toast({ title: '流式日志连接中断', variant: 'destructive' }); } finally { setStreaming(false); } }; return (
e.stopPropagation()}>
{podName} {container && {container}}
{containers.length > 0 && ( )} 最近 setTail(Number(e.target.value) || 200)} className="w-16 h-7 bg-slate-800 border-slate-700 text-slate-200 text-xs" /> 行
            {logs || '无日志内容'}
          
); }