(function() { 'use strict'; const API = window.location.origin; let userBadges = {}; function isLoggedIn() { return sessionStorage.getItem('logged_in') === 'true'; } function isAdmin() { return sessionStorage.getItem('is_admin') === 'true'; } function saveLogin(username, isAdminUser, badge = null) { sessionStorage.setItem('logged_in', 'true'); sessionStorage.setItem('username', username); sessionStorage.setItem('is_admin', isAdminUser ? 'true' : 'false'); sessionStorage.setItem('user_badge', badge || ''); sessionStorage.setItem('login_time', Date.now().toString()); } function clearLogin() { sessionStorage.clear(); } async function sha256(text) { try { const buf = new TextEncoder().encode(text); const hash = await crypto.subtle.digest('SHA-256', buf); const arr = Array.from(new Uint8Array(hash)); return arr.map(b => b.toString(16).padStart(2, '0')).join(''); } catch (error) { throw error; } } function showError(msg) { const el = document.getElementById('loginError'); if (el) { el.textContent = '❌ ' + msg; el.classList.add('show'); setTimeout(() => el.classList.remove('show'), 5000); } } function showSuccess(msg) { const el = document.getElementById('loginError'); if (el) { el.innerHTML = msg; // ✅ 使用 innerHTML 支持 HTML el.style.background = 'linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%)'; el.style.color = '#065f46'; el.style.borderColor = '#6ee7b7'; el.classList.add('show'); setTimeout(() => { el.classList.remove('show'); el.style.background = ''; el.style.color = ''; el.style.borderColor = ''; }, 2000); } } async function loadBadges() { try { const res = await fetch(`${API}/api/badges`); const data = await res.json(); if (data.success) { userBadges = data.badges; } } catch (e) { } } function updateAdminUI() { const isAdminUser = isAdmin(); const adminElements = document.querySelectorAll('.admin-only'); adminElements.forEach(el => { if (isAdminUser) { el.style.display = ''; el.style.visibility = 'visible'; el.style.opacity = '1'; el.classList.remove('hidden'); if (el.classList.contains('tab-button')) { el.style.display = 'block'; } } else { el.style.display = 'none'; el.style.visibility = 'hidden'; el.style.opacity = '0'; el.classList.add('hidden'); } }); } function showMainPage() { const login = document.getElementById('loginOverlay'); const main = document.getElementById('mainContainer'); if (!login || !main) { return; } login.classList.add('hide'); main.style.display = 'flex'; const username = sessionStorage.getItem('username') || '未知'; const isAdminUser = isAdmin(); const userBadge = sessionStorage.getItem('user_badge') || ''; const userEl = document.getElementById('currentUser'); if (userEl) { userEl.textContent = username; } const badge = document.getElementById('userTypeBadge'); if (badge) { badge.innerHTML = ''; badge.className = 'user-type-badge'; if (isAdminUser) { badge.innerHTML = '👑 管理员'; badge.className = 'user-type-badge admin'; } else if (userBadge && userBadges[userBadge]) { const badgeInfo = userBadges[userBadge]; badge.innerHTML = ` ${badgeInfo.icon} ${badgeInfo.name} `; badge.style.background = badgeInfo.gradient; badge.style.color = badgeInfo.color; badge.style.border = `2px solid ${badgeInfo.border}`; badge.style.boxShadow = `0 2px 8px ${badgeInfo.glow}`; badge.style.padding = '6px 14px'; badge.style.borderRadius = '20px'; badge.style.fontSize = '0.85em'; badge.style.fontWeight = '700'; badge.style.display = 'inline-flex'; badge.style.alignItems = 'center'; } else { badge.innerHTML = '👤 普通用户'; badge.className = 'user-type-badge user'; } } updateAdminUI(); setTimeout(() => checkAPI(), 100); setTimeout(() => { window.dispatchEvent(new Event('user-logged-in')); }, 200); } function showLoginPage() { const login = document.getElementById('loginOverlay'); const main = document.getElementById('mainContainer'); if (login) login.classList.remove('hide'); if (main) main.style.display = 'none'; } async function checkAPI() { try { const start = Date.now(); const res = await fetch('/health'); const time = Date.now() - start; const data = await res.json(); const status = document.getElementById('apiStatus'); const timeEl = document.getElementById('responseTime'); if (status) { if (data.status === 'running') { status.textContent = '在线'; status.className = 'status-value online'; } else { status.textContent = '异常'; status.className = 'status-value loading'; } } if (timeEl) timeEl.textContent = time + 'ms'; } catch (e) { const status = document.getElementById('apiStatus'); if (status) { status.textContent = '离线'; status.className = 'status-value offline'; } } } async function handleLogin(e) { e.preventDefault(); const user = document.getElementById('usernameInput'); const pass = document.getElementById('passwordInput'); const btn = document.getElementById('loginBtn'); if (!user || !pass || !btn) { showError('页面元素错误'); return; } const username = user.value.trim(); const password = pass.value; if (!username || !password) { showError('请输入用户名和密码'); return; } btn.disabled = true; btn.innerHTML = '
验证中...'; try { const hash = await sha256(password); const res = await fetch('/api/verify-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password_hash: hash }) }); const data = await res.json(); if (data.success) { const isAdminUser = data.user?.is_admin || false; const userBadge = data.user?.badge || null; // ✅ 保存用户数据到 sessionStorage if (data.user_data) { const userDataKey = `user_data_${username}`; sessionStorage.setItem(userDataKey, JSON.stringify(data.user_data)); console.log('✅ 用户数据已保存到 sessionStorage'); } // 生成欢迎语 let welcomeMsg = '✅ 登录成功!'; if (isAdminUser) { welcomeMsg += '