// Filename: frontend/js/pages/logs/systemLog.js export default class SystemLogTerminal { constructor(container, controlsContainer) { this.container = container; this.controlsContainer = controlsContainer; this.ws = null; this.isPaused = false; this.shouldAutoScroll = true; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.isConnected = false; this.elements = { output: this.container.querySelector('#log-terminal-output'), statusIndicator: this.controlsContainer.querySelector('#terminal-status-indicator'), clearBtn: this.controlsContainer.querySelector('[data-action="clear-terminal"]'), pauseBtn: this.controlsContainer.querySelector('[data-action="toggle-pause-terminal"]'), scrollBtn: this.controlsContainer.querySelector('[data-action="toggle-scroll-terminal"]'), connectBtn: this.controlsContainer.querySelector('[data-action="toggle-connect-terminal"]'), settingsBtn: this.controlsContainer.querySelector('[data-action="terminal-settings"]'), }; this._initEventListeners(); } _initEventListeners() { this.elements.clearBtn.addEventListener('click', () => this.clear()); this.elements.pauseBtn.addEventListener('click', () => this.togglePause()); this.elements.scrollBtn.addEventListener('click', () => this.toggleAutoScroll()); this.elements.connectBtn.addEventListener('click', () => this.toggleConnect()); this.elements.settingsBtn.addEventListener('click', () => this.openSettings()); } toggleConnect() { if (this.isConnected) { this.disconnect(); } else { this.connect(); } } connect() { this.clear(); this._appendMessage('info', '正在连接到实时日志流...'); this._updateStatus('connecting', '连接中...'); const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.host}/ws/system-logs`; this.ws = new WebSocket(wsUrl); this.ws.onopen = () => { this._appendMessage('info', '✓ 已连接到系统日志流'); this._updateStatus('connected', '已连接'); this.reconnectAttempts = 0; this.isConnected = true; this.elements.connectBtn.title = '断开'; this.elements.connectBtn.querySelector('i').classList.replace('fa-plug', 'fa-minus-circle'); }; this.ws.onmessage = (event) => { if (this.isPaused) return; try { const data = JSON.parse(event.data); const levelColors = { 'error': 'text-red-500', 'warning': 'text-yellow-400', 'info': 'text-green-400', 'debug': 'text-zinc-400' }; const color = levelColors[data.level] || 'text-zinc-200'; const timestamp = new Date(data.timestamp).toLocaleTimeString(); const msg = `[${timestamp}] [${data.level.toUpperCase()}] ${data.message}`; this._appendMessage(color, msg); } catch (e) { this._appendMessage('text-zinc-200', event.data); } }; this.ws.onerror = (error) => { this._appendMessage('error', `✗ WebSocket 错误`); this._updateStatus('error', '连接错误'); }; this.ws.onclose = () => { this._appendMessage('error', '✗ 连接已断开'); this._updateStatus('disconnected', '未连接'); this.isConnected = false; this.elements.connectBtn.title = '连接'; this.elements.connectBtn.querySelector('i').classList.replace('fa-minus-circle', 'fa-plug'); if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; setTimeout(() => { this._appendMessage('info', `尝试重新连接 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`); this.connect(); }, 3000); } }; } disconnect() { if (this.ws) { this.ws.close(); this.ws = null; } this.reconnectAttempts = this.maxReconnectAttempts; this.isConnected = false; this._updateStatus('disconnected', '未连接'); this.elements.connectBtn.title = '连接'; this.elements.connectBtn.querySelector('i').classList.replace('fa-minus-circle', 'fa-plug'); } clear() { if(this.elements.output) { this.elements.output.innerHTML = ''; } } togglePause() { this.isPaused = !this.isPaused; const icon = this.elements.pauseBtn.querySelector('i'); if (this.isPaused) { this.elements.pauseBtn.title = '继续'; icon.classList.replace('fa-pause', 'fa-play'); } else { this.elements.pauseBtn.title = '暂停'; icon.classList.replace('fa-play', 'fa-pause'); } } toggleAutoScroll() { this.shouldAutoScroll = !this.shouldAutoScroll; this.elements.scrollBtn.title = this.shouldAutoScroll ? '自动滚动' : '手动滚动'; } openSettings() { // 实现设置功能 console.log('打开设置'); } _appendMessage(colorClass, text) { if (!this.elements.output) return; const p = document.createElement('p'); p.className = colorClass; p.textContent = text; this.elements.output.appendChild(p); if (this.shouldAutoScroll) { this.elements.output.scrollTop = this.elements.output.scrollHeight; } } _updateStatus(status, text) { const indicator = this.elements.statusIndicator.querySelector('span.relative'); const statusText = this.elements.statusIndicator.childNodes[2]; const colors = { 'connecting': 'bg-yellow-500', 'connected': 'bg-green-500', 'disconnected': 'bg-zinc-500', 'error': 'bg-red-500' }; indicator.querySelectorAll('span').forEach(span => { span.className = span.className.replace(/bg-\w+-\d+/g, colors[status] || colors.disconnected); }); if (statusText) { statusText.textContent = ` ${text}`; } } }