import { useEffect, useRef, useState } from "react"; import type { FC } from "react"; import styles from "./Terminal.module.css"; interface LogEntry { timestamp: string; level: string; name: string; message: string; } interface TerminalProps { onClose: () => void; } export const Terminal: FC = ({ onClose }) => { const [logs, setLogs] = useState([]); const [isConnected, setIsConnected] = useState(false); const wsRef = useRef(null); const logsEndRef = useRef(null); const [autoScroll, setAutoScroll] = useState(true); useEffect(() => { // 连接WebSocket const ws = new WebSocket("ws://43.106.118.91:8000/api/logs/watch"); wsRef.current = ws; ws.onopen = () => { setIsConnected(true); console.log("Terminal WebSocket connected"); }; ws.onmessage = (event) => { try { const logEntry: LogEntry = JSON.parse(event.data); setLogs((prev) => [...prev, logEntry]); } catch (error) { console.error("Failed to parse log entry:", error); } }; ws.onerror = (error) => { console.error("Terminal WebSocket error:", error); setIsConnected(false); }; ws.onclose = () => { setIsConnected(false); console.log("Terminal WebSocket disconnected"); }; return () => { ws.close(); }; }, []); useEffect(() => { if (autoScroll && logsEndRef.current) { logsEndRef.current.scrollIntoView({ behavior: "smooth" }); } }, [logs, autoScroll]); const handleClear = () => { setLogs([]); }; const getLevelColor = (level: string) => { switch (level) { case "ERROR": return styles.error; case "WARNING": return styles.warning; case "INFO": return styles.info; case "DEBUG": return styles.debug; default: return ""; } }; return (
控制台输出 {isConnected ? "●" : "○"}
{logs.length === 0 ? (
等待日志输出...
) : ( logs.map((log, index) => (
{new Date(log.timestamp).toLocaleTimeString()} [{log.level}] {log.name}: {log.message}
)) )}
); };