480 lines
16 KiB
JavaScript
480 lines
16 KiB
JavaScript
/**
|
||
* 首页认证集成 - 处理登录状态检查和用户菜单
|
||
*/
|
||
class HomeAuthIntegration {
|
||
|
||
constructor() {
|
||
this.currentUser = null;
|
||
this.isAuthenticated = false;
|
||
this.init();
|
||
}
|
||
|
||
/**
|
||
* 初始化
|
||
*/
|
||
async init() {
|
||
await this.checkAuthStatus();
|
||
this.setupEventListeners();
|
||
this.updateUI();
|
||
|
||
// 隐藏加载遮罩
|
||
const loader = document.getElementById('authCheckLoader');
|
||
if (loader) {
|
||
loader.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查认证状态
|
||
*/
|
||
async checkAuthStatus() {
|
||
try {
|
||
const authStatus = await AuthService.checkAuthStatus();
|
||
this.isAuthenticated = authStatus.isAuthenticated;
|
||
this.currentUser = authStatus.user;
|
||
|
||
// 如果用户已登录,保存用户信息到localStorage供ChatManager使用
|
||
if (this.isAuthenticated && this.currentUser) {
|
||
localStorage.setItem('yundage_current_user', JSON.stringify(this.currentUser));
|
||
} else {
|
||
// 如果用户未登录,清除本地存储的用户信息
|
||
localStorage.removeItem('yundage_current_user');
|
||
}
|
||
|
||
console.log('Auth Status:', authStatus);
|
||
|
||
// 触发认证状态检查完成事件
|
||
window.dispatchEvent(new CustomEvent('authStatusChecked', {
|
||
detail: {
|
||
isAuthenticated: this.isAuthenticated,
|
||
user: this.currentUser
|
||
}
|
||
}));
|
||
|
||
// 路由保护逻辑
|
||
this.handleRouteProtection();
|
||
|
||
} catch (error) {
|
||
console.error('Failed to check auth status:', error);
|
||
this.isAuthenticated = false;
|
||
this.currentUser = null;
|
||
|
||
// 清除本地存储的用户信息
|
||
localStorage.removeItem('yundage_current_user');
|
||
|
||
// 即使检查失败也要触发事件
|
||
window.dispatchEvent(new CustomEvent('authStatusChecked', {
|
||
detail: {
|
||
isAuthenticated: false,
|
||
user: null,
|
||
error: error
|
||
}
|
||
}));
|
||
|
||
// 检查失败时也要处理路由保护
|
||
this.handleRouteProtection();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理路由保护
|
||
*/
|
||
handleRouteProtection() {
|
||
const currentPath = window.location.pathname;
|
||
const isAuthPage = currentPath.includes('/auth/pages/');
|
||
const isMainPage = currentPath.includes('/index.html') ||
|
||
currentPath === '/' ||
|
||
currentPath.endsWith('/yundage/') ||
|
||
currentPath.endsWith('/yundage');
|
||
|
||
// 如果在登录页面且已登录,跳转到首页
|
||
if (this.isAuthenticated && isAuthPage) {
|
||
console.log('已登录用户访问登录页面,跳转到首页');
|
||
setTimeout(() => {
|
||
window.location.href = '../../index.html';
|
||
}, 500);
|
||
return;
|
||
}
|
||
|
||
// 如果在主页且未登录,跳转到登录页面
|
||
if (!this.isAuthenticated && isMainPage) {
|
||
console.log('未登录用户访问主页,跳转到登录页面');
|
||
|
||
// 更新加载遮罩文字
|
||
const loader = document.getElementById('authCheckLoader');
|
||
if (loader) {
|
||
const loaderText = loader.querySelector('p');
|
||
if (loaderText) {
|
||
loaderText.textContent = '正在跳转到登录页面...';
|
||
}
|
||
}
|
||
|
||
// 显示提示
|
||
this.showNotification('请先登录', 'info');
|
||
|
||
// 短暂延迟后跳转
|
||
setTimeout(() => {
|
||
window.location.href = 'auth/pages/login.html?redirect=' + encodeURIComponent(window.location.href);
|
||
}, 500);
|
||
return;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置事件监听器
|
||
*/
|
||
setupEventListeners() {
|
||
// 用户菜单切换
|
||
const userMenuToggle = document.getElementById('userMenuToggle');
|
||
if (userMenuToggle) {
|
||
userMenuToggle.addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
this.toggleUserMenu();
|
||
});
|
||
}
|
||
|
||
// 退出登录按钮
|
||
const logoutBtn = document.getElementById('logoutBtn');
|
||
if (logoutBtn) {
|
||
logoutBtn.addEventListener('click', (e) => {
|
||
e.preventDefault();
|
||
this.handleLogout();
|
||
});
|
||
}
|
||
|
||
// 点击页面其他地方关闭菜单
|
||
document.addEventListener('click', (e) => {
|
||
const userDropdown = document.getElementById('userDropdown');
|
||
const userMenuToggle = document.getElementById('userMenuToggle');
|
||
|
||
if (userDropdown && userMenuToggle) {
|
||
if (!userMenuToggle.contains(e.target) && !userDropdown.contains(e.target)) {
|
||
userDropdown.classList.add('hidden');
|
||
}
|
||
}
|
||
});
|
||
|
||
// 监听存储变化(其他标签页登录/登出)
|
||
window.addEventListener('storage', (e) => {
|
||
if (e.key === TokenManager.TOKEN_KEY || e.key === TokenManager.USER_KEY) {
|
||
this.handleStorageChange();
|
||
}
|
||
});
|
||
|
||
// 定期检查token状态
|
||
this.startTokenCheck();
|
||
}
|
||
|
||
/**
|
||
* 更新UI显示
|
||
*/
|
||
updateUI() {
|
||
const guestMenu = document.getElementById('guestMenu');
|
||
const userMenu = document.getElementById('userMenu');
|
||
const userName = document.getElementById('userName');
|
||
const userAccount = document.getElementById('userAccount');
|
||
|
||
if (this.isAuthenticated && this.currentUser) {
|
||
// 显示已登录状态
|
||
if (guestMenu) guestMenu.classList.add('hidden');
|
||
if (userMenu) userMenu.classList.remove('hidden');
|
||
|
||
// 更新用户信息显示
|
||
if (userName) {
|
||
userName.textContent = this.currentUser.username || this.currentUser.nickname || '用户';
|
||
}
|
||
if (userAccount) {
|
||
userAccount.textContent = this.currentUser.phone || this.currentUser.email || '';
|
||
}
|
||
|
||
// 更新用户头像(可选)
|
||
this.updateUserAvatar();
|
||
|
||
// 添加刷新按钮事件(如果存在)
|
||
this.setupRefreshButton();
|
||
|
||
} else {
|
||
// 显示未登录状态
|
||
if (guestMenu) guestMenu.classList.remove('hidden');
|
||
if (userMenu) userMenu.classList.add('hidden');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置刷新按钮
|
||
*/
|
||
setupRefreshButton() {
|
||
const refreshBtn = document.getElementById('refreshUserInfo');
|
||
if (refreshBtn && !refreshBtn._listenerAdded) {
|
||
refreshBtn._listenerAdded = true;
|
||
refreshBtn.addEventListener('click', async (e) => {
|
||
e.preventDefault();
|
||
await this.refreshUserInfo();
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 刷新用户信息
|
||
*/
|
||
async refreshUserInfo() {
|
||
try {
|
||
console.log('手动刷新用户信息...');
|
||
const result = await AuthService.getUserInfo();
|
||
|
||
if (result.success && result.data) {
|
||
this.currentUser = result.data;
|
||
// 更新本地存储
|
||
localStorage.setItem('yundage_current_user', JSON.stringify(this.currentUser));
|
||
// 更新UI
|
||
this.updateUI();
|
||
|
||
// 显示成功提示
|
||
this.showNotification('用户信息已更新', 'success');
|
||
} else {
|
||
throw new Error(result.message || '获取用户信息失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('刷新用户信息失败:', error);
|
||
|
||
// 特殊处理不同类型的错误
|
||
if (error.message.includes('403')) {
|
||
this.showNotification('没有权限访问此用户信息', 'warning');
|
||
} else if (error.message.includes('404')) {
|
||
this.showNotification('用户不存在', 'error');
|
||
} else {
|
||
this.showNotification('刷新失败:' + error.message, 'error');
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 显示通知消息
|
||
*/
|
||
showNotification(message, type = 'info') {
|
||
// 创建通知元素
|
||
const notification = document.createElement('div');
|
||
notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 transition-all duration-300 transform translate-x-full`;
|
||
|
||
// 根据类型设置样式
|
||
const typeStyles = {
|
||
success: 'bg-green-500 text-white',
|
||
error: 'bg-red-500 text-white',
|
||
warning: 'bg-yellow-500 text-white',
|
||
info: 'bg-blue-500 text-white'
|
||
};
|
||
|
||
notification.className += ` ${typeStyles[type] || typeStyles.info}`;
|
||
notification.textContent = message;
|
||
|
||
// 添加到页面
|
||
document.body.appendChild(notification);
|
||
|
||
// 显示动画
|
||
setTimeout(() => {
|
||
notification.classList.remove('translate-x-full');
|
||
}, 100);
|
||
|
||
// 3秒后自动消失
|
||
setTimeout(() => {
|
||
notification.classList.add('translate-x-full');
|
||
setTimeout(() => {
|
||
notification.remove();
|
||
}, 300);
|
||
}, 3000);
|
||
}
|
||
|
||
/**
|
||
* 切换用户菜单显示
|
||
*/
|
||
toggleUserMenu() {
|
||
const userDropdown = document.getElementById('userDropdown');
|
||
if (userDropdown) {
|
||
userDropdown.classList.toggle('hidden');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理退出登录
|
||
*/
|
||
async handleLogout() {
|
||
try {
|
||
// 显示确认对话框
|
||
const confirmed = confirm('确定要退出登录吗?');
|
||
if (!confirmed) return;
|
||
|
||
// 执行登出
|
||
const result = await AuthService.logout();
|
||
|
||
if (result.success) {
|
||
this.isAuthenticated = false;
|
||
this.currentUser = null;
|
||
// 清除localStorage中的用户信息
|
||
localStorage.removeItem('yundage_current_user');
|
||
this.updateUI();
|
||
|
||
// 隐藏用户菜单
|
||
const userDropdown = document.getElementById('userDropdown');
|
||
if (userDropdown) {
|
||
userDropdown.classList.add('hidden');
|
||
}
|
||
|
||
// 显示成功提示
|
||
this.showNotification('已退出登录', 'success');
|
||
|
||
// 可选:刷新页面
|
||
setTimeout(() => {
|
||
window.location.reload();
|
||
}, 1000);
|
||
} else {
|
||
this.showNotification(result.message || '退出登录失败', 'error');
|
||
}
|
||
} catch (error) {
|
||
console.error('Logout error:', error);
|
||
this.showNotification('退出登录失败', 'error');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理存储变化(跨标签页同步)
|
||
*/
|
||
async handleStorageChange() {
|
||
await this.checkAuthStatus();
|
||
this.updateUI();
|
||
}
|
||
|
||
/**
|
||
* 更新用户头像
|
||
*/
|
||
updateUserAvatar() {
|
||
// 如果用户有头像,可以在这里更新头像显示
|
||
// 当前使用默认的太阳云朵图标
|
||
|
||
const userMenuToggle = document.getElementById('userMenuToggle');
|
||
if (userMenuToggle && this.currentUser && this.currentUser.avatar) {
|
||
// 可以在这里添加自定义头像逻辑
|
||
userMenuToggle.style.backgroundImage = `url(${this.currentUser.avatar})`;
|
||
userMenuToggle.style.backgroundSize = 'cover';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 显示通知消息
|
||
* @param {string} message - 消息内容
|
||
* @param {string} type - 消息类型:success/error/info/warning
|
||
*/
|
||
showNotification(message, type = 'info') {
|
||
// 创建通知元素
|
||
const notification = document.createElement('div');
|
||
notification.className = `fixed top-20 right-4 z-50 px-4 py-3 rounded-lg shadow-lg max-w-sm transition-all duration-300 transform translate-x-full`;
|
||
|
||
// 设置样式
|
||
switch (type) {
|
||
case 'success':
|
||
notification.classList.add('bg-green-500', 'text-white');
|
||
break;
|
||
case 'error':
|
||
notification.classList.add('bg-red-500', 'text-white');
|
||
break;
|
||
case 'warning':
|
||
notification.classList.add('bg-yellow-500', 'text-white');
|
||
break;
|
||
default:
|
||
notification.classList.add('bg-blue-500', 'text-white');
|
||
}
|
||
|
||
notification.innerHTML = `
|
||
<div class="flex items-center gap-2">
|
||
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
|
||
<span>${message}</span>
|
||
<button class="ml-2 text-white hover:text-gray-200" onclick="this.parentElement.parentElement.remove()">
|
||
<i class="fas fa-times"></i>
|
||
</button>
|
||
</div>
|
||
`;
|
||
|
||
document.body.appendChild(notification);
|
||
|
||
// 显示动画
|
||
setTimeout(() => {
|
||
notification.classList.remove('translate-x-full');
|
||
}, 100);
|
||
|
||
// 自动隐藏
|
||
setTimeout(() => {
|
||
notification.classList.add('translate-x-full');
|
||
setTimeout(() => {
|
||
if (notification.parentElement) {
|
||
notification.remove();
|
||
}
|
||
}, 300);
|
||
}, 3000);
|
||
}
|
||
|
||
/**
|
||
* 开始token检查定时器
|
||
*/
|
||
startTokenCheck() {
|
||
// 每5分钟检查一次token状态
|
||
setInterval(async () => {
|
||
const isValid = TokenManager.isTokenValid();
|
||
|
||
if (this.isAuthenticated && !isValid) {
|
||
// Token已过期,尝试刷新
|
||
const refreshResult = await AuthService.refreshToken();
|
||
|
||
if (!refreshResult.success) {
|
||
// 刷新失败,清除登录状态
|
||
this.isAuthenticated = false;
|
||
this.currentUser = null;
|
||
this.updateUI();
|
||
this.showNotification('登录已过期,请重新登录', 'warning');
|
||
}
|
||
}
|
||
}, 5 * 60 * 1000); // 5分钟
|
||
}
|
||
|
||
/**
|
||
* 检查是否需要登录才能使用某些功能
|
||
* @param {Function} callback - 需要登录后执行的回调函数
|
||
* @param {string} redirectUrl - 登录后的回跳地址
|
||
*/
|
||
requireAuth(callback, redirectUrl = null) {
|
||
if (this.isAuthenticated) {
|
||
callback();
|
||
} else {
|
||
// 未登录,跳转到登录页面
|
||
const loginUrl = redirectUrl
|
||
? `auth/pages/login.html?redirect=${encodeURIComponent(redirectUrl)}`
|
||
: 'auth/pages/login.html';
|
||
|
||
window.location.href = loginUrl;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取当前用户信息
|
||
* @returns {object|null} 用户信息
|
||
*/
|
||
getCurrentUser() {
|
||
return this.currentUser;
|
||
}
|
||
|
||
/**
|
||
* 检查是否已登录
|
||
* @returns {boolean} 是否已登录
|
||
*/
|
||
isLoggedIn() {
|
||
return this.isAuthenticated;
|
||
}
|
||
}
|
||
|
||
// 页面加载完成后初始化
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
window.homeAuth = new HomeAuthIntegration();
|
||
});
|
||
|
||
// 导出供其他模块使用
|
||
if (typeof module !== 'undefined' && module.exports) {
|
||
module.exports = HomeAuthIntegration;
|
||
} |