'use client'; import { useState, useEffect } from 'react'; import api from '@/lib/api'; import { FileText, Search, RefreshCw, AlertCircle, Download } from 'lucide-react'; interface ServerConfig { host: string; port: number; username: string; password?: string; key_file?: string; project_path: string; } export default function LogViewer({ serverConfig, serverId, projectPath }: { serverConfig: ServerConfig; serverId?: string; projectPath?: string; }) { const [logFiles, setLogFiles] = useState([]); const [selectedLog, setSelectedLog] = useState(''); const [logContent, setLogContent] = useState(''); const [lines, setLines] = useState(100); const [fromHead, setFromHead] = useState(false); const [full, setFull] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchLogList = async () => { setLoading(true); setError(null); try { const url = serverId ? '/api/remote/server/log/list' : '/api/remote/log/list'; const payload = serverId ? { server_id: serverId, project_path: projectPath } : { ...serverConfig, project_path: projectPath }; const response = await api.post(url, payload); if (response.data.code === 0) { setLogFiles(response.data.data.log_files || []); } else { setError(response.data.message || '获取日志列表失败'); } } catch (err: any) { setError(err.response?.data?.message || err.message || '请求失败'); } finally { setLoading(false); } }; const fetchLogContent = async () => { if (!selectedLog) return; setLoading(true); setError(null); try { const url = serverId ? '/api/remote/server/log/read' : '/api/remote/log/read'; const payload = serverId ? { server_id: serverId, log_file: selectedLog, lines: full ? 100 : lines, from_head: fromHead, full: full, project_path: projectPath } : { ...serverConfig, log_file: selectedLog, lines: full ? 100 : lines, from_head: fromHead, full: full, project_path: projectPath, }; const response = await api.post(url, payload); if (response.data.code === 0) { setLogContent(response.data.data.content || ''); } else { setError(response.data.message || '读取日志失败'); } } catch (err: any) { setError(err.response?.data?.message || err.message || '读取日志失败'); } finally { setLoading(false); } }; useEffect(() => { fetchLogList(); }, [serverId, projectPath]); useEffect(() => { if (selectedLog) { fetchLogContent(); } }, [selectedLog, lines, fromHead, full]); const downloadLog = () => { if (!logContent) return; const blob = new Blob([logContent], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = selectedLog || 'log.txt'; a.click(); URL.revokeObjectURL(url); }; return (

日志文件查看

{error && (
{error}
)}
{/* 日志文件列表 */}

日志文件列表

{logFiles.length === 0 ? (

暂无日志文件

) : ( logFiles.map((file) => ( )) )}
{/* 日志内容 */}
{selectedLog ? ( <> {/* 控制栏 */}
{ setLines(parseInt(e.target.value) || 100); setFull(false); }} disabled={full || loading} className="w-16 sm:w-20 px-2 py-1 border border-slate-300 rounded text-xs sm:text-sm disabled:opacity-50" />
{/* 日志内容显示 */}

{selectedLog}

{logContent.split('\n').length} 行
                  {logContent || (loading ? '加载中...' : '暂无内容')}
                
) : (

请选择一个日志文件查看

)}
); }