From ea7c5e56a3cc24843e2aa04e96fc0035b612ea01 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Sat, 24 May 2025 15:33:31 +0800 Subject: [PATCH] update --- docker-compose.yml | 2 +- src/App.vue | 314 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 315 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index a8e62be..86327ca 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: build: context: . dockerfile: Dockerfile - image: tradus-web:1.3.15 + image: tradus-web:1.3.16 container_name: tradus-web ports: - '6000:80' diff --git a/src/App.vue b/src/App.vue index 10381f1..dace941 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,6 +13,7 @@ const userInfo = computed(() => userStore.userInfo) const showMobileMenu = ref(false) const showUserMenu = ref(false) const showLoginModal = ref(false) +const showResetPasswordModal = ref(false) const loginMode = ref('login') // 'login' 或 'register' // 获取用户信息 @@ -69,6 +70,13 @@ const formData = ref({ verificationCode: '', }) +// 重置密码表单数据 +const resetPasswordData = ref({ + email: '', + verificationCode: '', + newPassword: '', +}) + // 表单错误信息 const formErrors = ref({ email: '', @@ -76,15 +84,25 @@ const formErrors = ref({ verificationCode: '', }) +// 重置密码表单错误信息 +const resetPasswordErrors = ref({ + email: '', + verificationCode: '', + newPassword: '', +}) + // 密码显示状态 const showPassword = ref(false) +const showNewPassword = ref(false) // 验证码相关状态 const sendingCode = ref(false) const countdown = ref(0) +const resetCountdown = ref(0) // 加载状态 const isLoading = ref(false) +const isResetLoading = ref(false) // 发送验证码 const sendVerificationCode = async () => { @@ -116,6 +134,50 @@ const sendVerificationCode = async () => { } } +// 发送重置密码验证码 +const sendResetVerificationCode = async () => { + if (!resetPasswordData.value.email) { + resetPasswordErrors.value.email = '请输入邮箱' + return + } + + try { + sendingCode.value = true + resetPasswordErrors.value.email = '' + + // 调用发送验证码接口 + const response = await fetch( + `${import.meta.env.MODE === 'development' ? 'http://127.0.0.1:8000' : 'https://api.ibtc.work'}/user/send-verification-code`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ mail: resetPasswordData.value.email }), + }, + ) + + if (!response.ok) { + throw new Error('发送验证码失败,请重试') + } + + resetCountdown.value = 60 + + // 倒计时 + const timer = setInterval(() => { + resetCountdown.value-- + if (resetCountdown.value <= 0) { + clearInterval(timer) + } + }, 1000) + } catch (err) { + resetPasswordErrors.value.email = err instanceof Error ? err.message : '发送验证码失败,请重试' + console.error('发送重置密码验证码失败:', err) + } finally { + sendingCode.value = false + } +} + // 验证表单 const validateForm = () => { let isValid = true @@ -154,6 +216,83 @@ const validateForm = () => { return isValid } +// 验证重置密码表单 +const validateResetPasswordForm = () => { + let isValid = true + resetPasswordErrors.value = { + email: '', + verificationCode: '', + newPassword: '', + } + + // 验证邮箱 + if (!resetPasswordData.value.email) { + resetPasswordErrors.value.email = '请输入邮箱' + isValid = false + } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(resetPasswordData.value.email)) { + resetPasswordErrors.value.email = '请输入有效的邮箱地址' + isValid = false + } + + // 验证验证码 + if (!resetPasswordData.value.verificationCode) { + resetPasswordErrors.value.verificationCode = '请输入验证码' + isValid = false + } + + // 验证新密码 + if (!resetPasswordData.value.newPassword) { + resetPasswordErrors.value.newPassword = '请输入新密码' + isValid = false + } else if (resetPasswordData.value.newPassword.length < 6) { + resetPasswordErrors.value.newPassword = '密码长度不能小于6位' + isValid = false + } + + return isValid +} + +// 处理重置密码提交 +const handleResetPasswordSubmit = async () => { + if (!validateResetPasswordForm()) return + + isResetLoading.value = true + try { + // 调用重置密码接口 + const response = await fetch( + `${import.meta.env.MODE === 'development' ? 'http://127.0.0.1:8000' : 'https://api.ibtc.work'}/user/reset_password`, + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + mail: resetPasswordData.value.email, + verification_code: resetPasswordData.value.verificationCode, + new_password: resetPasswordData.value.newPassword, + }), + }, + ) + + if (!response.ok) { + const errorData = await response.json() + throw new Error(errorData.message || '重置密码失败') + } + + // 重置密码成功,关闭模态框 + closeResetPasswordModal() + // 提示用户重置成功,并打开登录模态框 + alert('密码重置成功,请使用新密码登录') + openAuthModal('login') + } catch (error) { + console.error('重置密码失败:', error) + resetPasswordErrors.value.email = + error instanceof Error ? error.message : '重置密码失败,请检查输入信息' + } finally { + isResetLoading.value = false + } +} + // 处理表单提交 const handleSubmit = async () => { if (!validateForm()) return @@ -242,6 +381,28 @@ const openAuthModal = (mode: 'login' | 'register') => { showLoginModal.value = true } +// 关闭重置密码模态框 +const closeResetPasswordModal = () => { + showResetPasswordModal.value = false + // 重置表单和错误信息 + resetPasswordData.value = { + email: '', + verificationCode: '', + newPassword: '', + } + resetPasswordErrors.value = { + email: '', + verificationCode: '', + newPassword: '', + } +} + +// 打开重置密码模态框 +const openResetPasswordModal = () => { + closeAuthModal() // 关闭登录模态框 + showResetPasswordModal.value = true +} + onMounted(() => { document.addEventListener('click', closeMenus) if (isAuthenticated.value) { @@ -590,6 +751,12 @@ onUnmounted(() => { + + +
+ +
+
{{ loginMode === 'login' ? '还没有账号?' : '已有账号?' }}
+ + + @@ -1738,4 +2031,25 @@ html { border-color: var(--color-border); color: var(--color-text-secondary); } + +/* 忘记密码链接样式 */ +.forgot-password { + text-align: right; + margin-top: 0.5rem; + margin-bottom: 1rem; +} + +.forgot-password-link { + background: none; + border: none; + color: var(--color-accent); + font-size: 0.9rem; + cursor: pointer; + padding: 0; + text-decoration: none; +} + +.forgot-password-link:hover { + text-decoration: underline; +}