import state from './state.js'; import { getToken, setToken, getUser, setUser, getCurrentServer, setCurrentServer as persistCurrentServer, clearAuth } from './storage.js'; import { showToast } from './toast.js'; import { login, register, ApiError } from './api.js'; export default class AuthManager { constructor(calendarView, serverManager) { this.calendarView = calendarView; this.serverManager = serverManager; this.authModal = document.getElementById('authModal'); this.mainContainer = document.getElementById('mainContainer'); this.authTitle = document.getElementById('authTitle'); this.authUsername = document.getElementById('authUsername'); this.authPassword = document.getElementById('authPassword'); this.authServer = document.getElementById('authServer'); this.authMessage = document.getElementById('authMessage'); this.loginBtn = document.getElementById('loginBtn'); this.registerBtn = document.getElementById('registerBtn'); this.switchToRegister = document.getElementById('switchToRegister'); this.switchToLogin = document.getElementById('switchToLogin'); this.closeModalBtn = document.getElementById('closeAuthModal'); this.logoutBtn = document.getElementById('logoutBtn'); this.userDisplay = document.getElementById('userDisplay'); } init() { this.bindEvents(); this.updateAuthUI(); } bindEvents() { if (this.loginBtn) { this.loginBtn.addEventListener('click', () => this.handleLogin()); } if (this.registerBtn) { this.registerBtn.addEventListener('click', () => this.handleRegister()); } if (this.switchToRegister) { this.switchToRegister.addEventListener('click', () => { state.isLoginMode = false; this.updateAuthUI(); }); } if (this.switchToLogin) { this.switchToLogin.addEventListener('click', () => { state.isLoginMode = true; this.updateAuthUI(); }); } if (this.closeModalBtn) { this.closeModalBtn.addEventListener('click', () => { // Allow closing modal even without login this.hideAuthModal(); }); } if (this.logoutBtn) { this.logoutBtn.addEventListener('click', () => { if (state.user) { this.logout(); } else { this.showAuthModal(state.currentServer || window.location.origin); } }); } if (this.authPassword) { this.authPassword.addEventListener('keypress', (event) => { if (event.key === 'Enter') { state.isLoginMode ? this.handleLogin() : this.handleRegister(); } }); } } async handleLogin() { const server = this.getServerInput(); const username = (this.authUsername?.value || '').trim(); const password = this.authPassword?.value || ''; if (!server || !username || !password) { this.showAuthMessage('请输入服务器、用户名和密码'); return; } try { this.showAuthMessage('正在登录...', 'info'); const result = await login(server, username, password); this.afterAuthSuccess(server, result.token, { username: result.username, userId: result.userId }); showToast('登录成功', 'success'); } catch (error) { this.handleAuthError(error); } } async handleRegister() { const server = this.getServerInput(); const username = (this.authUsername?.value || '').trim(); const password = this.authPassword?.value || ''; if (!server || !username || !password) { this.showAuthMessage('请输入服务器、用户名和密码'); return; } if (username.length < 3) { this.showAuthMessage('用户名至少需要3个字符'); return; } if (password.length < 6) { this.showAuthMessage('密码至少需要6个字符'); return; } try { this.showAuthMessage('正在注册...', 'info'); const result = await register(server, username, password); this.afterAuthSuccess(server, result.token, { username: result.username, userId: result.userId }); showToast('注册成功', 'success'); } catch (error) { this.handleAuthError(error); } } getServerInput() { const value = this.authServer?.value.trim(); if (!value) { this.showAuthMessage('请输入服务器地址'); return ''; } try { new URL(value); return value; } catch (error) { this.showAuthMessage('无效的服务器地址格式'); return ''; } } afterAuthSuccess(server, token, user) { state.currentServer = server; state.token = token; state.user = user; persistCurrentServer(server); setToken(server, token); setUser(server, user); if (this.serverManager) { this.serverManager.ensureServerInList(server); } this.hideAuthModal(); this.showMainContainer(); this.updateUserDisplay(); if (this.serverManager) { this.serverManager.setCurrentServer(server); } this.calendarView.loadData(); this.clearAuthForm(); this.clearAuthMessage(); } handleAuthError(error) { if (error instanceof ApiError) { this.showAuthMessage(error.message || '操作失败'); return; } this.showAuthMessage('操作失败,请稍后再试'); } clearAuthForm() { if (this.authPassword) this.authPassword.value = ''; } showAuthMessage(message, type = 'error') { if (!this.authMessage) return; this.authMessage.textContent = message; this.authMessage.className = `auth-message ${type}`; } clearAuthMessage() { if (!this.authMessage) return; this.authMessage.textContent = ''; this.authMessage.className = 'auth-message'; } updateAuthUI() { if (!this.authTitle || !this.loginBtn || !this.registerBtn || !this.switchToLogin || !this.switchToRegister) { return; } if (state.isLoginMode) { this.authTitle.textContent = '登录'; this.loginBtn.style.display = 'block'; this.registerBtn.style.display = 'none'; this.switchToRegister.style.display = 'block'; this.switchToLogin.style.display = 'none'; } else { this.authTitle.textContent = '注册'; this.loginBtn.style.display = 'none'; this.registerBtn.style.display = 'block'; this.switchToRegister.style.display = 'none'; this.switchToLogin.style.display = 'block'; } } showAuthModal(prefillServer) { if (this.authModal) { this.authModal.style.display = 'flex'; } // Don't hide main container anymore const serverValue = prefillServer || state.currentServer || window.location.origin; if (this.authServer) { this.authServer.value = serverValue; } state.isLoginMode = true; this.updateAuthUI(); this.clearAuthMessage(); } hideAuthModal() { if (this.authModal) { this.authModal.style.display = 'none'; } } showMainContainer() { if (this.mainContainer) { this.mainContainer.style.display = 'block'; } this.hideAuthModal(); } hideMainContainer() { if (this.mainContainer) { this.mainContainer.style.display = 'none'; } } updateUserDisplay() { if (this.userDisplay) { this.userDisplay.textContent = state.user ? `用户: ${state.user.username}` : '未登录'; } // Update logout button text based on login state if (this.logoutBtn) { this.logoutBtn.textContent = state.user ? '退出' : '登录'; } } async handleServerSelection(server) { if (!server) { persistCurrentServer(''); state.currentServer = ''; state.token = ''; state.user = null; this.calendarView.clearData(); this.updateUserDisplay(); // Keep main container visible return; } persistCurrentServer(server); state.currentServer = server; const storedToken = getToken(server); const storedUser = getUser(server); if (storedToken && storedUser) { state.token = storedToken; state.user = storedUser; this.showMainContainer(); this.updateUserDisplay(); this.calendarView.loadData(); this.hideAuthModal(); } else { state.token = ''; state.user = null; this.calendarView.clearData(); this.updateUserDisplay(); // Show main container and auth modal together this.showMainContainer(); this.showAuthModal(server); } } logout() { if (state.currentServer) { clearAuth(state.currentServer); } state.token = ''; state.user = null; this.calendarView.clearData(); this.updateUserDisplay(); showToast('已退出登录', 'success'); // Keep main container visible, just show auth modal this.showAuthModal(state.currentServer || window.location.origin); } checkExistingSession() { const storedServer = getCurrentServer(); if (storedServer) { state.currentServer = storedServer; if (this.serverManager) { this.serverManager.ensureServerInList(storedServer); this.serverManager.setCurrentServer(storedServer); } } const storedToken = storedServer ? getToken(storedServer) : ''; const storedUser = storedServer ? getUser(storedServer) : null; // Always show main container first this.showMainContainer(); if (storedServer && storedToken && storedUser) { state.token = storedToken; state.user = storedUser; this.updateUserDisplay(); // Try to load data, will show login if it fails this.calendarView.loadData(); } else { // Render empty calendar this.updateUserDisplay(); this.calendarView.renderCalendar(); } } }