fix: stabilize console scrolling and protect administrator login

This commit is contained in:
2026-09-30 00:09:01 +08:00
parent 9a15406f76
commit f56f233704
32 changed files with 1308 additions and 86 deletions

View File

@@ -12,6 +12,26 @@
const toast = $('toast'); toast.textContent = message; toast.classList.add('show');
clearTimeout(showToast.timer); showToast.timer = setTimeout(() => toast.classList.remove('show'), 2800);
}
let loginAuditCursor = '', loginAuditPage = 1, loginAuditLoading = false;
async function loadLoginAudit(first = false) {
if (loginAuditLoading) return;
loginAuditLoading = true;
$('login-audit-first').disabled = true; $('login-audit-next').disabled = true;
text('login-audit-status', '正在读取…');
try {
const cursor = first ? '' : loginAuditCursor;
const page = extractData(await request(`/console/auth/audit${cursor ? `?before=${encodeURIComponent(cursor)}` : ''}`));
const labels = { SUCCESS: '登录成功', INVALID: '账号或密码错误', LOCKED: '临时锁定', ACCOUNT_LIMIT: '账号限流', IP_LIMIT: 'IP 限流', PENDING: '校验中', ERROR: '未完成 / 服务异常' };
$('login-audit-rows').innerHTML = (page.items || []).map(row => `<tr><td>${escapeHTML(formatTime(row.created_at))}</td><td>${escapeHTML(row.username)}</td><td>${escapeHTML(row.remote_ip)}</td><td>${escapeHTML(labels[row.outcome] || row.outcome)}</td><td>${escapeHTML(formatTime(row.retry_at))}</td></tr>`).join('');
loginAuditPage = first ? 1 : loginAuditPage + 1; loginAuditCursor = page.next || '';
text('login-audit-page', `第 ${loginAuditPage} 页`); text('login-audit-status', page.items?.length ? '' : '暂无登录记录');
} catch (error) { text('login-audit-status', `读取失败:${error.message}`); }
finally { loginAuditLoading = false; $('login-audit-first').disabled = false; $('login-audit-next').disabled = !loginAuditCursor; }
}
$('login-audit-open').addEventListener('click', () => { $('login-audit-dialog').showModal(); loadLoginAudit(true); });
$('login-audit-close').addEventListener('click', () => $('login-audit-dialog').close());
$('login-audit-first').addEventListener('click', () => loadLoginAudit(true));
$('login-audit-next').addEventListener('click', () => loadLoginAudit());
function formatTime(value) {
if (!value) return '—';
const date = new Date(value); if (Number.isNaN(date.getTime())) return String(value);
@@ -137,6 +157,7 @@
appendScopeOptions($('scope-application'), scopeUI.applications, scope.entry.namespace_id, '', 'application');
appendScopeOptions($('scope-queue'), queues, state.queue, scopeUI.nextQueue, 'queue');
$('scope-application').disabled = !scope.can_switch;
$('login-audit-open').hidden = !scope.can_switch;
$('scope-queue').disabled = !queues.length;
if (scope.can_switch) {
try { await loadScopeApplications(); } catch (error) { text('scope-error', '应用目录读取失败:' + error.message); }