Some checks failed
Build and Push Docker Image / buildx (push) Has been cancelled
353 lines
9.5 KiB
JavaScript
353 lines
9.5 KiB
JavaScript
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();
|
|
}
|
|
}
|
|
}
|