269 lines
9.7 KiB
JavaScript
269 lines
9.7 KiB
JavaScript
class AuthManager {
|
||
constructor() {
|
||
// 动态设置API基础URL,支持file:///协议和localhost:3000访问
|
||
this.apiBase = window.location.protocol === 'file:' ? 'http://localhost:3000/api' : '/api';
|
||
this.initEventListeners();
|
||
this.checkAuthStatus();
|
||
}
|
||
|
||
async checkAuthStatus() {
|
||
try {
|
||
const response = await fetch(`${this.apiBase}/auth/me`);
|
||
const data = await response.json();
|
||
|
||
if (data.success && data.user) {
|
||
// 用户已登录,根据角色重定向到正确的仪表板
|
||
const userRole = data.user.role;
|
||
let redirectUrl = '/dashboard';
|
||
|
||
if (userRole === 'student') {
|
||
redirectUrl = '/frontend/html/student_dashboard.html';
|
||
} else if (userRole === 'teacher') {
|
||
redirectUrl = '/frontend/html/teacher_dashboard.html';
|
||
} else if (userRole === 'admin') {
|
||
redirectUrl = '/frontend/html/admin_dashboard.html';
|
||
}
|
||
|
||
// 如果当前页面是登录或注册页面,则重定向到仪表板
|
||
const currentPath = window.location.pathname;
|
||
if (currentPath.includes('login.html') || currentPath.includes('register.html')) {
|
||
window.location.href = redirectUrl;
|
||
}
|
||
// 如果当前页面不是正确的仪表板页面,则重定向
|
||
else if (!currentPath.includes(redirectUrl) &&
|
||
currentPath !== '/' &&
|
||
!currentPath.includes('index.html')) {
|
||
window.location.href = redirectUrl;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.log('用户未登录');
|
||
}
|
||
}
|
||
|
||
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 logoutBtn = document.getElementById('logoutBtn');
|
||
if (logoutBtn) {
|
||
logoutBtn.addEventListener('click', (e) => this.handleLogout(e));
|
||
}
|
||
}
|
||
|
||
async handleLogin(e) {
|
||
e.preventDefault();
|
||
|
||
const form = e.target;
|
||
const formData = new FormData(form);
|
||
const data = Object.fromEntries(formData.entries());
|
||
|
||
const submitBtn = form.querySelector('button[type="submit"]');
|
||
const originalText = submitBtn.innerHTML;
|
||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 登录中...';
|
||
submitBtn.disabled = true;
|
||
|
||
try {
|
||
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');
|
||
|
||
// 根据用户角色跳转到不同的仪表板
|
||
const userRole = result.user?.role;
|
||
let redirectUrl = '/dashboard';
|
||
|
||
if (userRole === 'student') {
|
||
redirectUrl = '/frontend/html/student_dashboard.html';
|
||
} else if (userRole === 'teacher') {
|
||
redirectUrl = '/frontend/html/teacher_dashboard.html';
|
||
} else if (userRole === 'admin') {
|
||
redirectUrl = '/frontend/html/admin_dashboard.html';
|
||
}
|
||
|
||
// 延迟跳转以显示通知
|
||
setTimeout(() => {
|
||
window.location.href = redirectUrl;
|
||
}, 1500);
|
||
} else {
|
||
this.showNotification(result.message || '登录失败', 'error');
|
||
submitBtn.innerHTML = originalText;
|
||
submitBtn.disabled = false;
|
||
}
|
||
} catch (error) {
|
||
console.error('登录错误:', error);
|
||
this.showNotification('网络错误,请重试', 'error');
|
||
submitBtn.innerHTML = originalText;
|
||
submitBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
async handleRegister(e) {
|
||
e.preventDefault();
|
||
|
||
const form = e.target;
|
||
const formData = new FormData(form);
|
||
const data = Object.fromEntries(formData.entries());
|
||
|
||
// 验证密码
|
||
if (data.password !== data.confirmPassword) {
|
||
this.showNotification('两次输入的密码不一致', 'error');
|
||
return;
|
||
}
|
||
|
||
const submitBtn = form.querySelector('button[type="submit"]');
|
||
const originalText = submitBtn.innerHTML;
|
||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 注册中...';
|
||
submitBtn.disabled = 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 = '/html/login.html';
|
||
}, 1500);
|
||
} else {
|
||
this.showNotification(result.message || '注册失败', 'error');
|
||
submitBtn.innerHTML = originalText;
|
||
submitBtn.disabled = false;
|
||
}
|
||
} catch (error) {
|
||
console.error('注册错误:', error);
|
||
this.showNotification('网络错误,请重试', 'error');
|
||
submitBtn.innerHTML = originalText;
|
||
submitBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
async handleLogout(e) {
|
||
e.preventDefault();
|
||
|
||
if (!confirm('确定要退出登录吗?')) {
|
||
return;
|
||
}
|
||
|
||
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 = '/';
|
||
}, 1000);
|
||
} else {
|
||
this.showNotification('退出登录失败', 'error');
|
||
}
|
||
} catch (error) {
|
||
console.error('退出登录错误:', error);
|
||
this.showNotification('网络错误,请重试', 'error');
|
||
}
|
||
}
|
||
|
||
showNotification(message, type = 'info') {
|
||
// 移除现有的通知
|
||
const existingNotification = document.querySelector('.notification');
|
||
if (existingNotification) {
|
||
existingNotification.remove();
|
||
}
|
||
|
||
// 创建新的通知
|
||
const notification = document.createElement('div');
|
||
notification.className = `notification notification-${type}`;
|
||
notification.innerHTML = `
|
||
<i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-circle'}"></i>
|
||
<span>${message}</span>
|
||
`;
|
||
|
||
// 样式
|
||
notification.style.cssText = `
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
|
||
color: white;
|
||
padding: 15px 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
z-index: 1000;
|
||
animation: slideIn 0.3s ease;
|
||
`;
|
||
|
||
document.body.appendChild(notification);
|
||
|
||
// 3秒后自动移除
|
||
setTimeout(() => {
|
||
notification.style.animation = 'slideOut 0.3s ease';
|
||
setTimeout(() => notification.remove(), 300);
|
||
}, 3000);
|
||
|
||
// 添加动画关键帧
|
||
if (!document.querySelector('#notification-styles')) {
|
||
const style = document.createElement('style');
|
||
style.id = 'notification-styles';
|
||
style.textContent = `
|
||
@keyframes slideIn {
|
||
from {
|
||
transform: translateX(100%);
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
transform: translateX(0);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
@keyframes slideOut {
|
||
from {
|
||
transform: translateX(0);
|
||
opacity: 1;
|
||
}
|
||
to {
|
||
transform: translateX(100%);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 初始化认证管理器
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
window.authManager = new AuthManager();
|
||
}); |