diff --git a/src/components/sidebar.js b/src/components/sidebar.js index dce259e..d3cf25c 100644 --- a/src/components/sidebar.js +++ b/src/components/sidebar.js @@ -43,6 +43,8 @@ const ICONS = { deploy: '', } +let _delegated = false + export function renderSidebar(el) { const current = getCurrentRoute() @@ -86,14 +88,22 @@ export function renderSidebar(el) { el.innerHTML = html - // 绑定导航点击事件 - el.querySelectorAll('.nav-item[data-route]').forEach(item => { - item.onclick = () => navigate(item.dataset.route) - }) - - // 主题切换 - el.querySelector('#btn-theme-toggle')?.addEventListener('click', () => { - toggleTheme() - renderSidebar(el) - }) + // 事件委托:只绑定一次,避免重复绑定 + if (!_delegated) { + _delegated = true + el.addEventListener('click', (e) => { + // 导航点击 + const navItem = e.target.closest('.nav-item[data-route]') + if (navItem) { + navigate(navItem.dataset.route) + return + } + // 主题切换 + const themeBtn = e.target.closest('#btn-theme-toggle') + if (themeBtn) { + toggleTheme() + renderSidebar(el) + } + }) + } } diff --git a/src/pages/agents.js b/src/pages/agents.js index b3dd8ed..2397dcd 100644 --- a/src/pages/agents.js +++ b/src/pages/agents.js @@ -22,7 +22,17 @@ export async function render() { const state = { config: null } await loadConfig(page, state) - page.querySelector('#btn-save-agent').onclick = () => saveConfig(page, state) + page.querySelector('#btn-save-agent').onclick = async () => { + const btn = page.querySelector('#btn-save-agent') + btn.disabled = true + btn.textContent = '保存中...' + try { + await saveConfig(page, state) + } finally { + btn.disabled = false + btn.textContent = '保存配置' + } + } return page } diff --git a/src/pages/gateway.js b/src/pages/gateway.js index b477abe..33fae78 100644 --- a/src/pages/gateway.js +++ b/src/pages/gateway.js @@ -21,7 +21,17 @@ export async function render() { const state = { config: null } await loadConfig(page, state) - page.querySelector('#btn-save-gw').onclick = () => saveConfig(page, state) + page.querySelector('#btn-save-gw').onclick = async () => { + const btn = page.querySelector('#btn-save-gw') + btn.disabled = true + btn.textContent = '保存中...' + try { + await saveConfig(page, state) + } finally { + btn.disabled = false + btn.textContent = '保存配置' + } + } return page } diff --git a/src/pages/logs.js b/src/pages/logs.js index 5105ee4..a77af40 100644 --- a/src/pages/logs.js +++ b/src/pages/logs.js @@ -12,6 +12,8 @@ const LOG_TABS = [ { key: 'config-audit', label: '审计日志' }, ] +let _searchTimer = null + export async function render() { const page = document.createElement('div') page.className = 'page' @@ -48,10 +50,9 @@ export async function render() { }) // 搜索 - let searchTimer = null page.querySelector('#log-search').addEventListener('input', (e) => { - clearTimeout(searchTimer) - searchTimer = setTimeout(() => { + clearTimeout(_searchTimer) + _searchTimer = setTimeout(() => { if (e.target.value.trim()) { searchLog(page, currentTab, e.target.value.trim()) } else { @@ -67,6 +68,11 @@ export async function render() { return page } +export function cleanup() { + clearTimeout(_searchTimer) + _searchTimer = null +} + async function loadLog(page, logName) { const el = page.querySelector('#log-content') el.innerHTML = '