class RunLog extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.logFiles = []; this.expandedLogs = new Set(); this.logDir = '/log'; // 直接设置日志目录路径 // 添加分页相关的状态变量 this.currentPage = 1; this.pageSize = 10; // 每页显示10个日志文件 this.totalPages = 1; this.currentLogContent = []; // 存储当前日志文件的所有内容 } connectedCallback() { this.render(); this.setupEventListeners(); this.loadLogFileList(); } render() { this.shadowRoot.innerHTML = `
暂无日志记录
`; } setupEventListeners() { // 移除顶部刷新按钮的事件监听,因为按钮已经被移除 } loadLogFileList() { this.fetchLogFiles().then(logFiles => { this.logFiles = logFiles; this.renderLogList(); }).catch(error => { console.error('获取日志文件列表失败:', error); }); } async fetchLogFiles() { try { // 直接使用固定的日志目录路径 const logDirPath = this.logDir; // 读取目录下的所有文件 const files = await this.readLogDirectory(logDirPath); // 过滤出.log文件并获取文件信息 const logFiles = []; for (const fileName of files) { if (fileName.endsWith('.log')) { const filePath = `${logDirPath}/${fileName}`; const fileStats = await this.getFileStats(filePath); // 格式化修改时间 const modTime = new Date(fileStats.mtime); const formattedTime = this.formatDateTime(modTime); logFiles.push({ name: fileName, time: formattedTime, path: filePath }); } } // 按修改时间排序,最新的在前面 return logFiles.sort((a, b) => { return new Date(b.time) - new Date(a.time); }); } catch (error) { console.error('获取日志文件列表失败:', error); return []; } } // 读取目录内容 async readLogDirectory(dirPath) { return new Promise((resolve, reject) => { fetch(`/api/filesystem/readdir?path=${encodeURIComponent(dirPath)}`) .then(response => { if (!response.ok) { throw new Error(`读取目录失败: ${response.status}`); } return response.json(); }) .then(data => { resolve(data.files || []); }) .catch(error => { console.error('读取目录请求失败:', error); reject(error); }); }); } // 获取文件状态信息 async getFileStats(filePath) { return new Promise((resolve, reject) => { fetch(`/api/filesystem/stat?path=${encodeURIComponent(filePath)}`) .then(response => { if (!response.ok) { throw new Error(`获取文件信息失败: ${response.status}`); } return response.json(); }) .then(data => resolve(data)) .catch(error => reject(error)); }); } // 格式化日期时间 formatDateTime(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } renderLogList() { const logListElement = this.shadowRoot.getElementById('logList'); if (this.logFiles.length === 0) { logListElement.innerHTML = '
暂无日志记录
'; return; } // 计算总页数 this.totalPages = Math.ceil(this.logFiles.length / this.pageSize); // 获取当前页的日志文件 const start = (this.currentPage - 1) * this.pageSize; const end = start + this.pageSize; const currentPageFiles = this.logFiles.slice(start, end); // 清空列表 logListElement.innerHTML = ''; // 渲染当前页的日志文件 currentPageFiles.forEach(logFile => { const logItemElement = document.createElement('div'); logItemElement.className = 'log-item'; logItemElement.dataset.path = logFile.path; const isExpanded = this.expandedLogs.has(logFile.path); if (isExpanded) { logItemElement.classList.add('expanded'); } const iconSrc = isExpanded ? 'assets/icons/png/chevron-up_b.png' : 'assets/icons/png/chevron-down_b.png'; const iconAlt = isExpanded ? '收起' : '展开'; logItemElement.innerHTML = `
${logFile.name}
${logFile.time}
`; const toggleBtn = logItemElement.querySelector('.log-item-toggle'); const toggleImg = toggleBtn.querySelector('img'); const content = logItemElement.querySelector('.log-item-content'); toggleBtn.addEventListener('click', () => { const isExpanded = logItemElement.classList.contains('expanded'); if (isExpanded) { logItemElement.classList.remove('expanded'); this.expandedLogs.delete(logFile.path); content.innerHTML = ''; toggleImg.src = 'assets/icons/png/chevron-down_b.png'; toggleImg.alt = '展开'; } else { logItemElement.classList.add('expanded'); this.expandedLogs.add(logFile.path); this.loadLogContent(logFile.path, content); toggleImg.src = 'assets/icons/png/chevron-up_b.png'; toggleImg.alt = '收起'; } }); if (isExpanded) { this.loadLogContent(logFile.path, content); } logListElement.appendChild(logItemElement); }); // 添加分页控制器和刷新按钮 const paginationHtml = ` `; logListElement.insertAdjacentHTML('beforeend', paginationHtml); // 添加分页按钮事件监听 const prevButton = logListElement.querySelector('#prevPage'); const nextButton = logListElement.querySelector('#nextPage'); const refreshButton = logListElement.querySelector('#refreshLog'); prevButton.addEventListener('click', () => { if (this.currentPage > 1) { this.currentPage--; this.renderLogList(); } }); nextButton.addEventListener('click', () => { if (this.currentPage < this.totalPages) { this.currentPage++; this.renderLogList(); } }); refreshButton.addEventListener('click', () => { this.loadLogFileList(); }); } loadLogContent(logPath, contentElement) { contentElement.innerHTML = '
加载中...
'; this.fetchLogContent(logPath).then(content => { let html = '
'; html += '
全部
'; html += '
信息
'; html += '
警告
'; html += '
错误
'; html += '
'; if (!content || content.length === 0) { html += '
日志为空
'; } else { content.forEach(line => { let className = 'log-message'; if (line.includes('[INFO]')) { className += ' info'; } else if (line.includes('[WARNING]')) { className += ' warning'; } else if (line.includes('[ERROR]')) { className += ' error'; } html += `
${line}
`; }); } html += '
'; contentElement.innerHTML = html; // 设置过滤器事件 const filterElements = contentElement.querySelectorAll('.log-filter'); filterElements.forEach(filter => { filter.addEventListener('click', () => { filterElements.forEach(f => f.classList.remove('active')); filter.classList.add('active'); const level = filter.getAttribute('data-level'); const messagesContainer = contentElement.querySelector('.log-content-messages'); this.filterLogContent(messagesContainer, level); }); }); }).catch(error => { contentElement.innerHTML = `
加载日志内容失败: ${error.message}
`; }); } async fetchLogContent(logPath) { try { const response = await fetch(`/api/filesystem/readFile?path=${encodeURIComponent(logPath)}`); if (!response.ok) { throw new Error(`读取文件失败: ${response.status}`); } const fileContent = await response.text(); // 解析日志内容,按行分割 const lines = fileContent.split('\n') .filter(line => line.trim() !== '') // 过滤空行 .slice(-500); // 只显示最后500行,避免日志过大 return lines; } catch (error) { console.error('获取日志内容失败:', error); return []; } } filterLogContent(contentElement, level) { const logMessages = contentElement.querySelectorAll('.log-message'); logMessages.forEach(message => { if (level === 'all') { message.style.display = 'block'; } else { message.style.display = message.classList.contains(level) ? 'block' : 'none'; } }); } } customElements.define('run-log', RunLog);