From b3841e08ea938188ed5fe3b8950d1169e0ed7c25 Mon Sep 17 00:00:00 2001 From: kyx236 Date: Fri, 30 Jan 2026 09:58:02 +0800 Subject: [PATCH] feat: Add real-time log streaming component and new Upload page. --- frontend/src/components/upload/LogStream.tsx | 139 ++++++++++++++----- frontend/src/pages/Upload.tsx | 4 +- 2 files changed, 105 insertions(+), 38 deletions(-) diff --git a/frontend/src/components/upload/LogStream.tsx b/frontend/src/components/upload/LogStream.tsx index b3320b5..795aee1 100644 --- a/frontend/src/components/upload/LogStream.tsx +++ b/frontend/src/components/upload/LogStream.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef } from 'react' import { Terminal, Trash2, Play, Pause } from 'lucide-react' -import { Card, CardHeader, CardTitle, CardContent, Button } from '../common' +import { Card, Button } from '../common' interface LogEntry { timestamp: string @@ -33,7 +33,12 @@ const stepLabels: Record = { database: '数据库', } -export default function LogStream() { +interface LogStreamProps { + hideHeader?: boolean + className?: string +} + +export default function LogStream({ hideHeader = false, className = '' }: LogStreamProps) { const [logs, setLogs] = useState([]) const [connected, setConnected] = useState(false) const [paused, setPaused] = useState(false) @@ -53,7 +58,7 @@ export default function LogStream() { eventSource.onmessage = (event) => { try { const log = JSON.parse(event.data) as LogEntry - setLogs((prev) => [...prev.slice(-199), log]) + setLogs((prev) => [...prev.slice(-499), log]) // 增加缓存行数 } catch (e) { console.error('Failed to parse log:', e) } @@ -103,67 +108,129 @@ export default function LogStream() { } } - return ( - - -
- - - 实时日志 + const content = ( +
+ {!hideHeader && ( +
+
+ + 实时日志 - -
+
+
- - -
- {logs.length === 0 ? ( -
等待日志...
- ) : ( - logs.map((log, i) => ( -
- {formatTime(log.timestamp)} + )} + + {/* 紧凑型控制栏 (当 hideHeader=true 时显示) */} + {hideHeader && ( +
+
+ + 系统输出 +
+
+ + +
+
+ )} + +
+ {logs.length === 0 ? ( +
+ +

等待系统日志输出...

+
+ ) : ( +
+ {logs.map((log, i) => ( +
+ + {formatTime(log.timestamp)} + + {log.step && ( {stepLabels[log.step] || log.step} )} - + + {log.level === 'success' ? '✓' : log.level === 'error' ? '✗' : '•'} - {log.message} + + + {log.message} + + {log.email && ( - [{log.email}] + + {log.email} + )}
- )) - )} -
- + ))} +
+ )} +
+ +