/** * 认证模块管理器 * 处理登录、注册、注销及权限检查 */ class AuthManager { constructor() { this.apiBase = '/api'; this.init(); } init() { this.createNotificationContainer(); this.initEventListeners(); this.checkAuthStatus(); } /** * 创建通知容器 */ createNotificationContainer() { if (!document.getElementById('notification-container')) { const container = document.createElement('div'); container.id = 'notification-container'; container.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; `; document.body.appendChild(container); } } /** * 检查用户认证状态 */ async checkAuthStatus() { // 如果当前是公共页面,可以选择不检查,或者检查后更新UI const currentPath = window.location.pathname; const isAuthPage = currentPath.includes('/login') || currentPath.includes('/register'); try { const response = await fetch(`${this.apiBase}/auth/me`); const data = await response.json(); if (data.success && data.user) { // 用户已登录 const redirectUrl = this.getDashboardUrl(data.user.role); // 如果在登录/注册页,跳转到仪表板 if (isAuthPage || currentPath === '/') { window.location.href = redirectUrl; } } else { // 用户未登录,如果在受保护页面,跳转到登录页 // 注意:后端通常已经处理了重定向,这里是前端的额外保障 if (!isAuthPage && currentPath !== '/') { // 可以在这里添加逻辑,但通常交给后端控制 } } } catch (error) { console.error('Auth check failed:', error); } } getDashboardUrl(role) { switch(role) { case 'student': return '/student/dashboard'; case 'teacher': return '/teacher/dashboard'; case 'admin': return '/admin/dashboard'; default: return '/dashboard'; } } initEventListeners() { // 登录表单 const loginForm = document.getElementById('loginForm'); if (loginForm) { loginForm.addEventListener('submit', (e) => this.handleLogin(e)); } // 注册表单 const registerForm = document.getElementById('registerForm'); if (registerForm) { registerForm.addEventListener('submit', (e) => this.handleRegister(e)); // 角色选择联动 const roleSelect = document.getElementById('role'); if (roleSelect) { roleSelect.addEventListener('change', (e) => this.handleRoleChange(e)); } } // 注销按钮 (可能有多个,例如在导航栏) document.querySelectorAll('.btn-logout, #logoutBtn').forEach(btn => { btn.addEventListener('click', (e) => this.handleLogout(e)); }); } handleRoleChange(e) { const role = e.target.value; const classField = document.getElementById('classField'); const classInput = document.getElementById('class'); if (classField && classInput) { if (role === 'student' || role === 'teacher') { classField.style.display = 'block'; classInput.required = true; } else { classField.style.display = 'none'; classInput.required = false; classInput.value = ''; // 清空值 } } } async handleLogin(e) { e.preventDefault(); const form = e.target; const submitBtn = form.querySelector('button[type="submit"]'); if (this.setLoading(submitBtn, true, '登录中...')) { try { const formData = new FormData(form); const data = Object.fromEntries(formData.entries()); const response = await fetch(`${this.apiBase}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { this.showNotification('登录成功,正在跳转...', 'success'); setTimeout(() => { window.location.href = this.getDashboardUrl(result.user.role); }, 1000); } else { this.showNotification(result.message || '登录失败', 'error'); this.setLoading(submitBtn, false); } } catch (error) { console.error('Login error:', error); this.showNotification('网络错误,请稍后重试', 'error'); this.setLoading(submitBtn, false); } } } async handleRegister(e) { e.preventDefault(); const form = e.target; const submitBtn = form.querySelector('button[type="submit"]'); // 获取数据 const formData = new FormData(form); const data = Object.fromEntries(formData.entries()); // 简单验证 if (data.password !== data.confirmPassword) { this.showNotification('两次输入的密码不一致', 'error'); return; } if (this.setLoading(submitBtn, true, '注册中...')) { try { const response = await fetch(`${this.apiBase}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { this.showNotification('注册成功,请登录', 'success'); setTimeout(() => { window.location.href = '/login'; }, 1500); } else { this.showNotification(result.message || '注册失败', 'error'); this.setLoading(submitBtn, false); } } catch (error) { console.error('Register error:', error); this.showNotification('网络错误,请稍后重试', 'error'); this.setLoading(submitBtn, false); } } } async handleLogout(e) { e.preventDefault(); if (confirm('确定要退出登录吗?')) { try { const response = await fetch(`${this.apiBase}/auth/logout`, { method: 'POST' }); const result = await response.json(); if (result.success) { this.showNotification('已退出登录', 'success'); setTimeout(() => { window.location.href = '/login'; }, 1000); } } catch (error) { console.error('Logout error:', error); // 即使出错也强制跳转到登录页 window.location.href = '/login'; } } } /** * 设置按钮加载状态 * @param {HTMLElement} btn 按钮元素 * @param {boolean} isLoading 是否正在加载 * @param {string} text 加载时的文本 * @returns {boolean} true表示状态设置成功 */ setLoading(btn, isLoading, text = '') { if (!btn) return false; if (isLoading) { if (btn.dataset.loading) return false; // 防止重复提交 btn.dataset.loading = 'true'; btn.dataset.originalText = btn.innerHTML; btn.innerHTML = ` ${text}`; btn.disabled = true; } else { btn.innerHTML = btn.dataset.originalText || btn.innerHTML; delete btn.dataset.loading; btn.disabled = false; } return true; } /** * 显示通知 * @param {string} message 消息内容 * @param {string} type 消息类型 'success' | 'error' | 'info' */ showNotification(message, type = 'info') { const container = document.getElementById('notification-container'); if (!container) return; const notification = document.createElement('div'); notification.className = `notification ${type}`; let icon = 'info-circle'; if (type === 'success') icon = 'check-circle'; if (type === 'error') icon = 'exclamation-circle'; notification.innerHTML = ` ${message} `; container.appendChild(notification); // 动画显示 requestAnimationFrame(() => { notification.classList.add('show'); }); // 自动消失 setTimeout(() => { notification.classList.remove('show'); notification.addEventListener('transitionend', () => { notification.remove(); }); }, 3000); } } // 初始化 document.addEventListener('DOMContentLoaded', () => { window.authManager = new AuthManager(); });