|
|
|
|
|
export const authData = () => ({ |
|
|
isLoggedIn: false, |
|
|
userEmail: '', |
|
|
isAdmin: false, |
|
|
signupForm: { |
|
|
email: '', |
|
|
password: '', |
|
|
verificationCode: '' |
|
|
}, |
|
|
isSendingCode: false, |
|
|
countdown: 60, |
|
|
verificationCodeMessage: '', |
|
|
loginForm: { |
|
|
email: '', |
|
|
password: '' |
|
|
}, |
|
|
signupMessage: '', |
|
|
authMessage: '', |
|
|
showChangePasswordModal: false, |
|
|
changePasswordForm: { |
|
|
newPassword: '', |
|
|
confirmPassword: '' |
|
|
}, |
|
|
changePasswordMessage: '', |
|
|
resetPasswordForm: { |
|
|
email: '', |
|
|
verificationCode: '', |
|
|
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 = ''; |
|
|
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', { |
|
|
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 = ''; |
|
|
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 || '' |
|
|
}) |
|
|
}); |
|
|
const data = await response.json(); |
|
|
if (response.ok) { |
|
|
this.signupMessage = '注册成功!请登录。'; |
|
|
this.signupForm.email = ''; |
|
|
this.signupForm.password = ''; |
|
|
this.signupForm.verificationCode = ''; |
|
|
} else { |
|
|
this.signupMessage = data.detail || '注册失败。'; |
|
|
} |
|
|
} catch (error) { |
|
|
this.signupMessage = '网络错误或服务器无响应。'; |
|
|
console.error('Signup error:', error); |
|
|
} |
|
|
}, |
|
|
async login() { |
|
|
this.authMessage = ''; |
|
|
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 = '登录成功!'; |
|
|
await this.fetchUserEmail(); |
|
|
this.fetchProxies(); |
|
|
if (window.location.pathname === '/login') { |
|
|
window.location.href = '/'; |
|
|
} |
|
|
} else { |
|
|
this.authMessage = data.detail || '登录失败。'; |
|
|
} |
|
|
} catch (error) { |
|
|
if (error instanceof TypeError && error.message === 'Failed to fetch') { |
|
|
this.authMessage = '网络错误或服务器无响应。'; |
|
|
} else { |
|
|
this.authMessage = '邮箱或密码错误。请重新输入!'; |
|
|
} |
|
|
console.error('Login error:', error); |
|
|
} |
|
|
}, |
|
|
logout() { |
|
|
localStorage.removeItem('access_token'); |
|
|
this.isLoggedIn = false; |
|
|
this.userEmail = ''; |
|
|
this.proxies = []; |
|
|
this.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; |
|
|
} 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 = ''; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
}, |
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
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', { |
|
|
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(); |
|
|
|
|
|
if (window.location.pathname === '/reset-password') { |
|
|
console.log('Current URL:', window.location.href); |
|
|
const urlQueryParams = new URLSearchParams(window.location.search); |
|
|
|
|
|
const emailParam = urlQueryParams.get('email'); |
|
|
|
|
|
if (emailParam) { |
|
|
app.resetPasswordForm.email = emailParam; |
|
|
console.log('Mounted: Email param found and pre-filled:', emailParam); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
}; |
|
|
|