Initial commit: SenSu Alpha 0.2.0

- 13-service async plugin framework
- Textual TUI with CLI fallback
- Plugin hot-reload + permission system
- Web management panel (aiohttp)
- Bridge-based inter-module communication
- 10 regression tests

Fixes applied:
- PBKDF2-SHA256 auth (was plain SHA256)
- Auth bypass removed (was allow-all on fail)
- Bare excepts replaced with logged errors
- CatFramework/DreamSu -> SenSu naming unified
- ServiceManager: health checks + startup_order
- Env var credentials (SENSU_ADMIN_PASSWORD etc)
This commit is contained in:
2026-06-10 12:27:14 +08:00
commit e6875f0b4b
78 changed files with 14843 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
// 初始化检查
window.onload = async () => {
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 {
// 🟢 关键修改:fetch 路径必须包含 /static/
const html = await fetch(`./static/pages/${pageName}.html`).then(r => {
if(!r.ok) throw new Error('404');
return r.text();
});
content.innerHTML = html;
// 动态加载对应 JS 模块
// 🟢 关键修改:script src 路径必须包含 /static/
const script = document.createElement('script');
script.src = `./static/pages/${pageName}.js?t=${Date.now()}`;
script.onload = () => {
// 触发模块初始化
const moduleName = pageName.charAt(0).toUpperCase() + pageName.slice(1) + 'Module';
if(window[moduleName]?.init) {
window[moduleName].init();
}
bar.style.width = '100%';
setTimeout(() => bar.classList.remove('active'), 200);
};
script.onerror = () => {
throw new Error('JS Load Failed');
};
document.head.appendChild(script);
} 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(--accent)'; }, 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(); }
});