/** * 日志查看页面 */ import { api } from '../lib/tauri-api.js' import { toast } from '../components/toast.js' const LOG_TABS = [ { key: 'gateway', label: 'Gateway 日志' }, { key: 'gateway-err', label: 'Gateway 错误' }, { key: 'guardian', label: '守护进程' }, { key: 'guardian-backup', label: '备份日志' }, { key: 'config-audit', label: '审计日志' }, ] let _searchTimer = null export async function render() { const page = document.createElement('div') page.className = 'page' page.innerHTML = `
${LOG_TABS.map((t, i) => `
${t.label}
`).join('')}
` let currentTab = 'gateway' // Tab 切换 page.querySelectorAll('.tab').forEach(tab => { tab.onclick = () => { page.querySelectorAll('.tab').forEach(t => t.classList.remove('active')) tab.classList.add('active') currentTab = tab.dataset.tab page.querySelector('#log-search').value = '' loadLog(page, currentTab) } }) // 搜索 page.querySelector('#log-search').addEventListener('input', (e) => { clearTimeout(_searchTimer) _searchTimer = setTimeout(() => { if (e.target.value.trim()) { searchLog(page, currentTab, e.target.value.trim()) } else { loadLog(page, currentTab) } }, 300) }) // 刷新 page.querySelector('#btn-refresh').onclick = () => loadLog(page, currentTab) loadLog(page, currentTab) return page } export function cleanup() { clearTimeout(_searchTimer) _searchTimer = null } async function loadLog(page, logName) { const el = page.querySelector('#log-content') try { const content = await api.readLogTail(logName, 200) if (!content || !content.trim()) { el.innerHTML = '
暂无日志
' return } const lines = content.trim().split('\n') el.innerHTML = lines.map(l => `
${escapeHtml(l)}
`).join('') if (page.querySelector('#log-autoscroll')?.checked) { el.scrollTop = el.scrollHeight } } catch (e) { el.innerHTML = '
加载日志失败: ' + e + '
' toast('加载日志失败: ' + e, 'error') } } async function searchLog(page, logName, query) { const el = page.querySelector('#log-content') try { const results = await api.searchLog(logName, query) if (!results || !results.length) { el.innerHTML = '
未找到匹配结果
' return } el.innerHTML = results.map(l => `
${highlightMatch(escapeHtml(l), query)}
`).join('') } catch (e) { el.innerHTML = '
搜索失败: ' + e + '
' toast('搜索失败: ' + e, 'error') } } function escapeHtml(str) { return str.replace(/&/g, '&').replace(//g, '>') } function highlightMatch(html, query) { const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') return html.replace(new RegExp(escaped, 'gi'), m => `${m}`) }