feat: 飞书单点登录和通知功能

This commit is contained in:
2026-02-03 11:38:16 +08:00
parent c657fbe01a
commit 78ebc67e2a
18 changed files with 2136 additions and 105 deletions

View File

@@ -24,14 +24,39 @@ function switchTab(tab) {
//如果切换到日志页,开始实时加载
if (tab === 'logs') {
startLogStreaming();
checkAdminStatus().then(allowed => {
if (allowed) {
startLogStreaming();
} else {
const container = document.getElementById('content-logs');
container.innerHTML = `
<div class="w-full h-[calc(100vh-100px)] rounded-lg overflow-hidden bg-white shadow-sm border border-slate-200">
<iframe src="/error.html" class="w-full h-full border-0"></iframe>
</div>
`;
}
});
return;
} else {
stopLogStreaming();
}
//如果切换到设置页,加载 .env 文件
if (tab === 'settings') {
loadEnvFile();
checkAdminStatus().then(allowed => {
if (allowed) {
loadEnvFile();
} else {
const container = document.getElementById('content-settings');
// 使用 iframe 嵌入错误页,保持侧边栏导航
container.innerHTML = `
<div class="w-full h-[calc(100vh-100px)] rounded-lg overflow-hidden bg-white shadow-sm border border-slate-200">
<iframe src="/error.html" class="w-full h-full border-0"></iframe>
</div>
`;
}
});
return; // 等待检查结果,暂不加载内容
}
//如果切换到使用指南页,加载 README
@@ -40,6 +65,17 @@ function switchTab(tab) {
}
}
async function checkAdminStatus() {
try {
const res = await fetch('/api/me');
const data = await res.json();
return data.loggedIn && data.isAdmin;
} catch (e) {
console.error('Check admin status failed:', e);
return false;
}
}
//日志流控制
let logInterval = null;
let lastLogSize = 0;
@@ -101,6 +137,17 @@ function escapeHtml(text) {
async function loadDashboardData() {
try {
const res = await fetch('/api/status');
if (res.status === 403) {
document.getElementById('today-syncs').textContent = '无权限';
document.getElementById('repo-count').textContent = '无权限';
document.getElementById('error-count').textContent = '无权限';
document.getElementById('uptime').textContent = '系统运行时间: 无权限';
updateServiceStatus('unknown');
loadHistory(); // 也会处理 403
return;
}
const data = await res.json();
if (data.success) {
@@ -124,6 +171,13 @@ async function loadDashboardData() {
async function loadHistory() {
try {
const res = await fetch('/api/history');
if (res.status === 403) {
const tbody = document.getElementById('history-table');
tbody.innerHTML = '<tr><td colspan="4" class="px-4 py-8 text-center text-sm text-slate-500">无权限查看历史记录</td></tr>';
return;
}
const data = await res.json();
if (data.success && data.history) {
@@ -163,6 +217,15 @@ function updateServiceStatus(status) {
运行中
`;
statusText.textContent = '运行中';
} else if (status === 'unknown') {
badge.className = 'px-3 py-1 rounded-full text-xs font-medium flex items-center border bg-slate-100 text-slate-600 border-slate-200';
badge.innerHTML = `
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
状态未知
`;
statusText.textContent = '状态未知';
} else {
badge.className = 'px-3 py-1 rounded-full text-xs font-medium flex items-center border bg-slate-100 text-slate-600 border-slate-200';
badge.innerHTML = `