// static/js/auth.js export const authData = () => ({ isLoggedIn: false, userEmail: '', isAdmin: false, // Add isAdmin state signupForm: { email: '', password: '', verificationCode: '' }, isSendingCode: false, countdown: 60, verificationCodeMessage: '', loginForm: { email: '', password: '' }, signupMessage: '', authMessage: '', // Combined message for login and forgot password showChangePasswordModal: false, changePasswordForm: { newPassword: '', confirmPassword: '' }, changePasswordMessage: '', resetPasswordForm: { email: '', verificationCode: '', // Add verification code field for reset password newPassword: '', confirmPassword: '' }, resetPasswordMessage: '' }); export const authMethods = (app) => ({ resetPasswordLink() { const email = this.loginForm.email; if (email) { return `/reset-password?email=${encodeURIComponent(email)}`; } return '/reset-password'; }, async sendVerificationCode() { console.log('sendVerificationCode method triggered.'); console.log('Current email:', this.signupForm.email); this.verificationCodeMessage = ''; // 更严格的邮箱格式校验 const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; if (!this.signupForm.email || !emailRegex.test(this.signupForm.email)) { this.verificationCodeMessage = '请输入有效的邮箱地址。'; console.log('Invalid email format.'); return; } this.isSendingCode = true; let timer = setInterval(() => { if (this.countdown > 0) { this.countdown--; } else { clearInterval(timer); this.isSendingCode = false; this.countdown = 60; } }, 1000); try { const response = await fetch('/api/auth/send-verification-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: this.signupForm.email }) }); const data = await response.json(); if (response.ok) { this.verificationCodeMessage = data.message || '验证码已发送,请检查您的邮箱。'; } else { this.verificationCodeMessage = data.detail || data.message || '发送验证码失败。'; // 如果发送失败,立即停止倒计时并重置按钮 clearInterval(timer); this.isSendingCode = false; this.countdown = 60; } } catch (error) { this.verificationCodeMessage = '网络错误或服务器无响应。'; console.error('Send verification code error:', error); // 如果网络错误,立即停止倒计时并重置按钮 clearInterval(timer); this.isSendingCode = false; this.countdown = 60; } }, async sendResetVerificationCode() { console.log('sendResetVerificationCode method triggered.'); console.log('Current email for reset:', this.resetPasswordForm.email); this.resetPasswordMessage = ''; // Clear previous messages const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; if (!this.resetPasswordForm.email || !emailRegex.test(this.resetPasswordForm.email)) { this.resetPasswordMessage = '请输入有效的邮箱地址。'; console.log('Invalid email format for reset.'); return; } this.isSendingCode = true; let timer = setInterval(() => { if (this.countdown > 0) { this.countdown--; } else { clearInterval(timer); this.isSendingCode = false; this.countdown = 60; } }, 1000); try { const response = await fetch('/api/auth/send-reset-password-code', { // New API endpoint for reset password code method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: this.resetPasswordForm.email }) }); const data = await response.json(); if (response.ok) { this.resetPasswordMessage = data.message || '重置密码验证码已发送,请检查您的邮箱。'; } else { this.resetPasswordMessage = data.detail || data.message || '发送重置密码验证码失败。'; clearInterval(timer); this.isSendingCode = false; this.countdown = 60; } } catch (error) { this.resetPasswordMessage = '网络错误或服务器无响应。'; console.error('Send reset verification code error:', error); clearInterval(timer); this.isSendingCode = false; this.countdown = 60; } }, async signup() { this.signupMessage = ''; this.verificationCodeMessage = ''; // Clear verification code message on signup attempt try { const response = await fetch('/api/auth/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: this.signupForm.email, password: this.signupForm.password, verification_code: this.signupForm.verificationCode || '' // Ensure verification_code is always sent }) }); const data = await response.json(); if (response.ok) { this.signupMessage = '注册成功!请登录。'; this.signupForm.email = ''; this.signupForm.password = ''; this.signupForm.verificationCode = ''; // Clear verification code } else { this.signupMessage = data.detail || '注册失败。'; } } catch (error) { this.signupMessage = '网络错误或服务器无响应。'; console.error('Signup error:', error); } }, async login() { this.authMessage = ''; // Clear previous messages try { const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(this.loginForm) }); const data = await response.json(); if (response.ok) { localStorage.setItem('access_token', data.access_token); this.isLoggedIn = true; this.loginForm.email = ''; this.loginForm.password = ''; this.authMessage = '登录成功!'; // Use authMessage await this.fetchUserEmail(); // Fetch user email after successful login this.fetchProxies(); if (window.location.pathname === '/login') { window.location.href = '/'; } } else { this.authMessage = data.detail || '登录失败。'; // Use authMessage } } catch (error) { if (error instanceof TypeError && error.message === 'Failed to fetch') { this.authMessage = '网络错误或服务器无响应。'; // Use authMessage } else { this.authMessage = '邮箱或密码错误。请重新输入!'; // Use authMessage } console.error('Login error:', error); } }, logout() { localStorage.removeItem('access_token'); this.isLoggedIn = false; this.userEmail = ''; this.proxies = []; this.authMessage = '已退出登录。'; // Use authMessage // 只有在非登录页面才重定向到登录页 if (window.location.pathname !== '/login') { window.location.href = '/login'; } }, async forgotPassword() { const email = this.loginForm.email; let redirectUrl = '/reset-password'; if (email) { redirectUrl += `?email=${encodeURIComponent(email)}`; } window.location.href = redirectUrl; }, async fetchUserEmail() { const token = localStorage.getItem('access_token'); if (!token) { this.userEmail = ''; return; } try { const response = await fetch('/api/user/me', { headers: { 'Authorization': `Bearer ${token}` } }); const data = await response.json(); if (response.ok) { this.userEmail = data.email; this.isAdmin = data.is_admin; // Set isAdmin state } else { console.error('Error fetching user email:', data.detail); this.userEmail = '未知用户'; if (response.status === 401) { this.logout(); } } } catch (error) { console.error('Error fetching user email:', error); this.userEmail = '未知用户'; } }, checkLoginStatus() { const token = localStorage.getItem('access_token'); if (token) { this.isLoggedIn = true; this.fetchUserEmail(); // 只有在登录页面才重定向到首页 if (window.location.pathname === '/login') { window.location.href = '/'; } } else { this.isLoggedIn = false; this.userEmail = ''; // 如果在首页,不强制重定向到登录页 // 如果在需要登录的页面(如 /dashboard 或其他受保护路由),则重定向到登录页 // 目前只处理 /login 页面,其他页面需要后端或路由守卫处理 } }, async changePassword() { this.changePasswordMessage = ''; if (this.changePasswordForm.newPassword !== this.changePasswordForm.confirmPassword) { this.changePasswordMessage = '两次输入的密码不一致。'; return; } const token = localStorage.getItem('access_token'); if (!token) { this.changePasswordMessage = '未登录,请先登录。'; return; } try { const response = await fetch('/api/auth/change-password', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ new_password: this.changePasswordForm.newPassword }) }); const data = await response.json(); if (response.ok) { this.changePasswordMessage = '密码修改成功!请重新登录。'; this.showChangePasswordModal = false; this.changePasswordForm.newPassword = ''; this.changePasswordForm.confirmPassword = ''; this.logout(); } else { this.changePasswordMessage = data.detail || '密码修改失败。'; } } catch (error) { this.changePasswordMessage = '网络错误或服务器无响应。'; console.error('Change password error:', error); } }, async resetPassword() { this.resetPasswordMessage = ''; if (this.resetPasswordForm.newPassword !== this.resetPasswordForm.confirmPassword) { this.resetPasswordMessage = '两次输入的密码不一致。'; return; } const urlQueryParams = new URLSearchParams(window.location.search); const resetToken = urlQueryParams.get('token'); if (!resetToken) { this.resetPasswordMessage = '缺少重置密码所需的令牌。'; return; } // 清除URL中的token,避免泄露 const newUrl = window.location.pathname + window.location.hash; history.replaceState(null, '', newUrl); try { const response = await fetch('/api/auth/change-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ new_password: this.resetPasswordForm.newPassword, reset_token: resetToken }) }); const data = await response.json(); if (response.ok) { this.resetPasswordMessage = '密码重置成功!请使用新密码登录。'; this.resetPasswordForm.newPassword = ''; this.resetPasswordForm.confirmPassword = ''; window.location.href = '/login'; } else { this.resetPasswordMessage = data.detail || '密码重置失败。'; } } catch (error) { this.resetPasswordMessage = '网络错误或服务器无响应。'; console.error('Reset password error:', error); } }, async resetPasswordWithCode() { this.resetPasswordMessage = ''; if (this.resetPasswordForm.newPassword !== this.resetPasswordForm.confirmPassword) { this.resetPasswordMessage = '两次输入的密码不一致。'; return; } if (!this.resetPasswordForm.email || !this.resetPasswordForm.verificationCode) { this.resetPasswordMessage = '邮箱和验证码不能为空。'; return; } try { const response = await fetch('/api/auth/reset-password-with-code', { // New API endpoint method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: this.resetPasswordForm.email, verification_code: this.resetPasswordForm.verificationCode, new_password: this.resetPasswordForm.newPassword }) }); const data = await response.json(); if (response.ok) { this.resetPasswordMessage = '密码重置成功!请使用新密码登录。'; this.resetPasswordForm.email = ''; this.resetPasswordForm.verificationCode = ''; this.resetPasswordForm.newPassword = ''; this.resetPasswordForm.confirmPassword = ''; window.location.href = '/login'; } else { this.resetPasswordMessage = data.detail || '密码重置失败。'; } } catch (error) { this.resetPasswordMessage = '网络错误或服务器无响应。'; console.error('Reset password with code error:', error); } } }); export const authMounted = (app) => { app.checkLoginStatus(); // 在应用挂载时检查登录状态 // Check if it's the reset-password page and handle token if (window.location.pathname === '/reset-password') { console.log('Current URL:', window.location.href); const urlQueryParams = new URLSearchParams(window.location.search); // const resetToken = urlQueryParams.get('token'); // Remove token check const emailParam = urlQueryParams.get('email'); if (emailParam) { app.resetPasswordForm.email = emailParam; console.log('Mounted: Email param found and pre-filled:', emailParam); } // Remove token-related logic // if (resetToken) { // console.log('Mounted: Valid reset token found. Clearing URL query param.'); // const newUrl = window.location.pathname + (emailParam ? `?email=${encodeURIComponent(emailParam)}` : '') + window.location.hash; // history.replaceState(null, '', newUrl); // } else { // console.warn('Mounted: No valid reset token found for reset password page.'); // } } };