gate / static /js /auth.js
harii66's picture
Upload 23 files
b4edbc0 verified
Raw
History Blame Contribute Delete
12.3 kB
(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 = `
<span style="margin-right: 5px;">${badgeInfo.icon}</span>
<span>${badgeInfo.name}</span>
`;
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 = '<div class="loading-spinner-large" style="width: 16px; height: 16px; border-width: 3px; margin-right: 8px; display: inline-block; vertical-align: middle;"></div> 验证中...';
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 += '<br><div style="margin-top: 10px; display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%); color: white; border-radius: 12px; font-weight: 700;">👑 欢迎管理员</div>';
} else if (userBadge && userBadges[userBadge]) {
const badgeInfo = userBadges[userBadge];
welcomeMsg += `<br><div style="margin-top: 10px; display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: ${badgeInfo.gradient}; color: ${badgeInfo.color}; border: 2px solid ${badgeInfo.border}; box-shadow: 0 2px 8px ${badgeInfo.glow}; border-radius: 12px; font-weight: 700;"><span>${badgeInfo.icon}</span><span>欢迎 ${badgeInfo.name}</span></div>`;
} else {
welcomeMsg += '<br><div style="margin-top: 10px; color: #065f46; font-weight: 600;">👤 欢迎普通用户</div>';
}
showSuccess(welcomeMsg);
saveLogin(username, isAdminUser, userBadge);
await loadBadges();
setTimeout(() => {
showMainPage();
}, 1500);
} else {
showError('用户名或密码错误');
btn.disabled = false;
btn.textContent = '🚀 立即登录';
pass.value = '';
}
} catch (err) {
showError('登录失败: ' + err.message);
btn.disabled = false;
btn.textContent = '🚀 立即登录';
}
}
function togglePassword() {
const input = document.getElementById('passwordInput');
const btn = document.getElementById('togglePasswordBtn');
if (!input || !btn) return;
if (input.type === 'password') {
input.type = 'text';
btn.textContent = '🙈';
} else {
input.type = 'password';
btn.textContent = '👁️';
}
}
function handleLogout() {
if (confirm('确定要退出吗?')) {
clearLogin();
location.reload();
}
}
async function init() {
await loadBadges();
if (isLoggedIn()) {
setTimeout(() => showMainPage(), 100);
} else {
showLoginPage();
setTimeout(() => {
const user = document.getElementById('usernameInput');
if (user) user.focus();
}, 100);
}
const form = document.getElementById('loginForm');
const toggleBtn = document.getElementById('togglePasswordBtn');
const logoutBtn = document.getElementById('logoutBtn');
if (form) {
form.addEventListener('submit', handleLogin);
}
if (toggleBtn) {
toggleBtn.addEventListener('click', togglePassword);
}
if (logoutBtn) {
logoutBtn.addEventListener('click', handleLogout);
}
}
window.isAdmin = isAdmin;
window.updateAdminUI = updateAdminUI;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();