/**
* 仪表盘页面
*/
import { api } from '../lib/tauri-api.js'
import { toast } from '../components/toast.js'
export async function render() {
const page = document.createElement('div')
page.className = 'page'
page.innerHTML = `
`
// 异步加载数据
loadDashboardData(page)
return page
}
async function loadDashboardData(page) {
try {
const [services, version, logs] = await Promise.all([
api.getServicesStatus(),
api.getVersionInfo(),
api.readLogTail('gateway', 20),
])
renderStatCards(page, services, version)
renderLogs(page, logs)
bindActions(page)
} catch (e) {
toast('加载仪表盘数据失败: ' + e, 'error')
}
}
function renderStatCards(page, services, version) {
const cardsEl = page.querySelector('#stat-cards')
const gw = services.find(s => s.label.includes('gateway'))
const guardian = services.find(s => s.label.includes('guardian.watch'))
const watchdog = services.find(s => s.label.includes('watchdog'))
const runningCount = services.filter(s => s.running).length
cardsEl.innerHTML = `
${gw?.running ? '运行中' : '已停止'}
${gw?.pid ? 'PID: ' + gw.pid : ''}
${guardian?.running ? '运行中' : '已停止'}
健康监控
${watchdog?.running ? '运行中' : '已停止'}
看门狗
${version.current || '未知'}
服务 ${runningCount}/${services.length} 运行中
`
}
function renderLogs(page, logs) {
const logsEl = page.querySelector('#recent-logs')
if (!logs) { logsEl.textContent = '暂无日志'; return }
const lines = logs.trim().split('\n')
logsEl.innerHTML = lines.map(l => `${escapeHtml(l)}
`).join('')
logsEl.scrollTop = logsEl.scrollHeight
}
function bindActions(page) {
const btnRestart = page.querySelector('#btn-restart-gw')
const btnUpdate = page.querySelector('#btn-check-update')
btnRestart?.addEventListener('click', async () => {
btnRestart.disabled = true
btnRestart.textContent = '重启中...'
try {
await api.restartService('ai.openclaw.gateway')
toast('Gateway 已重启', 'success')
setTimeout(() => loadDashboardData(page), 500)
} catch (e) {
toast('重启失败: ' + e, 'error')
} finally {
btnRestart.disabled = false
btnRestart.textContent = '重启 Gateway'
}
})
btnUpdate?.addEventListener('click', async () => {
btnUpdate.disabled = true
btnUpdate.textContent = '检查中...'
try {
const info = await api.getVersionInfo()
if (info.update_available) {
toast(`发现新版本: ${info.latest}`, 'info')
} else {
toast('已是最新版本', 'success')
}
} catch (e) {
toast('检查更新失败: ' + e, 'error')
} finally {
btnUpdate.disabled = false
btnUpdate.textContent = '检查更新'
}
})
}
function escapeHtml(str) {
return str.replace(/&/g, '&').replace(//g, '>')
}