Files
SenSu/static/web_panel/js/app.js
T
qinglong c07cea4ff7 Fix page loader: execute inline scripts, JS module loading optional
- innerHTML strips script tags, now extract and eval them
- External .js module: 404 = skip gracefully (no error)
- Progress bar: completes regardless of JS module
- Proxy/projects pages now render with CSS + inline JS executes
2026-06-11 14:43:24 +08:00

100 lines
3.9 KiB
JavaScript

// 主题初始化 (必须在渲染前执行, 防止闪白)
(function(){
var s = localStorage.getItem("sensu-theme") || "dark";
document.documentElement.setAttribute("data-theme", s);
})();
window.toggleTheme = function(){
var t = document.documentElement.getAttribute("data-theme") === "light" ? "dark" : "light";
document.documentElement.setAttribute("data-theme", t);
localStorage.setItem("sensu-theme", t);
var btn = document.querySelector(".theme-toggle");
if(btn) btn.textContent = t === "light" ? "☀️" : "🌙";
};
// 初始化检查
window.onload = async () => {
// 设置按钮初始图标
var btn = document.querySelector(".theme-toggle");
if(btn) btn.textContent = document.documentElement.getAttribute("data-theme") === "light" ? "☀️" : "🌙";
try {
const res = await fetch('./api/auth/status', { credentials: 'include' });
if(res.status === 401) { window.location.href = './index.html'; return; }
const data = await res.json();
if(!data.authenticated) { window.location.href = './index.html'; return; }
document.getElementById('uname').textContent = data.username || 'Admin';
loadPage('dashboard'); // 默认加载
} catch(e) { window.location.href = './index.html'; }
};
// 路由加载器
async function loadPage(pageName) {
const content = document.getElementById('page-content');
const bar = document.getElementById('progress');
// 侧边栏高亮
document.querySelectorAll('.nav-item').forEach(el => el.classList.remove('active'));
document.querySelector(`.nav-item[data-page="${pageName}"]`)?.classList.add('active');
// 进度条动画
bar.classList.add('active'); bar.style.width = '0%';
await new Promise(r => requestAnimationFrame(() => { bar.style.width = '80%'; setTimeout(r, 100); }));
try {
const resp = await fetch(`./static/pages/${pageName}.html`);
if(!resp.ok) throw new Error('404');
const html = await resp.text();
// Extract inline scripts before innerHTML (browsers skip them)
const scripts = [];
const cleanHtml = html.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, (m, code) => {
scripts.push(code.trim()); return '';
});
content.innerHTML = cleanHtml;
// Execute inline scripts
for(const code of scripts) {
try { (new Function(code)).call(window); } catch(e) { console.error('Inline script error:', e); }
}
// Load external JS module (optional — skip if 404)
try {
const jsResp = await fetch(`./static/pages/${pageName}.js?t=${Date.now()}`);
if(jsResp.ok) {
const jsCode = await jsResp.text();
(new Function(jsCode)).call(window);
const moduleName = pageName.charAt(0).toUpperCase() + pageName.slice(1) + 'Module';
if(window[moduleName]?.init) window[moduleName].init();
}
} catch(e) { /* JS module optional */ }
bar.style.width = '100%';
setTimeout(() => bar.classList.remove('active'), 200);
} catch(e) {
content.innerHTML = `<div style="color:var(--error); text-align:center; margin-top:20vh;">页面加载失败: ${e.message}</div>`;
bar.style.background = 'var(--error)';
setTimeout(() => { bar.style.width = '100%'; setTimeout(() => { bar.classList.remove('active'); bar.style.background = 'var(--primary)'; }, 200); }, 100);
}
}
// 侧边栏切换
function toggleSidebar() {
document.getElementById('app').classList.toggle('collapsed');
}
// 退出登录
async function doLogout() {
await fetch('./api/logout', { method: 'POST', credentials: 'include' });
window.location.href = './index.html';
}
// 点击侧边栏事件委托
document.addEventListener('click', (e) => {
const nav = e.target.closest('.nav-item');
if(nav) { loadPage(nav.dataset.page); e.preventDefault(); }
});