This commit is contained in:
李志鹏
2025-10-31 16:42:17 +08:00
2 changed files with 105 additions and 19 deletions

View File

@@ -22,7 +22,6 @@
v-else-if="step === 'verify'" v-else-if="step === 'verify'"
:ct="emailCode" :ct="emailCode"
@nextStep="handleCheckVerifyCode" @nextStep="handleCheckVerifyCode"
@resend="handleSendVerifyCode"
/> />
<Password v-else-if="step === 'password'" @sucess="handleSuccess" /> <Password v-else-if="step === 'password'" @sucess="handleSuccess" />
</div> </div>
@@ -42,7 +41,7 @@ import Mail from './components/Mail.vue'
import Verify from './components/Verify.vue' import Verify from './components/Verify.vue'
import Password from './components/Password.vue' import Password from './components/Password.vue'
import { showToast } from 'vant' import { showToast } from 'vant'
import { precheckEmail, resetPassword } from '@/api/login' import { resetPassword } from '@/api/login'
import { encryptPassword } from '@/utils/tools' import { encryptPassword } from '@/utils/tools'
const router = useRouter() const router = useRouter()
@@ -80,10 +79,8 @@ const handleSendVerifyCode = (data: any) => {
if (data?.email) { if (data?.email) {
fromData.value.email = data?.email fromData.value.email = data?.email
} }
precheckEmail({ email: fromData.value.email }).then(() => { // 只切换步骤,验证码的发送由 Verify 组件负责
showToast('the verification code has been sent to your email') handleStep('verify')
handleStep('verify')
})
} }
const handleCheckVerifyCode = (data: any) => { const handleCheckVerifyCode = (data: any) => {

View File

@@ -31,8 +31,10 @@
<div class="btn" @click="handleConfirmCaptcha">Confirm</div> <div class="btn" @click="handleConfirmCaptcha">Confirm</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue' import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import { showToast } from 'vant' import { showToast } from 'vant'
import { getLocal, removeLocal, setLocal } from '@/utils/local'
import { precheckEmail } from '@/api/login'
// Props // Props
const props = defineProps({ const props = defineProps({
@@ -48,7 +50,7 @@ const props = defineProps({
const agreePolicy = ref(false) const agreePolicy = ref(false)
// Emits // Emits
const emit = defineEmits(['nextStep','resend']) const emit = defineEmits(['nextStep'])
// Reactive data // Reactive data
const loading = ref(false) const loading = ref(false)
@@ -66,24 +68,88 @@ const cIndex = computed(() => {
// const lastCode = computed(() => getCtData.value[ctSize.value - 1]) // const lastCode = computed(() => getCtData.value[ctSize.value - 1])
const countdown = ref(60) const countdown = ref(60)
const handleCountdown = () => { const countdownTimer = ref<number | null>(null)
const timer = setInterval(() => { const COUNTDOWN_KEY = 'verify_code_countdown'
const COUNTDOWN_EMAIL_KEY = 'verify_code_email'
const COUNTDOWN_DURATION = 60 // 60秒倒计时
// 清除倒计时数据
const clearCountdownData = () => {
removeLocal(COUNTDOWN_KEY)
removeLocal(COUNTDOWN_EMAIL_KEY)
}
// 保存倒计时开始时间
const saveCountdownStart = () => {
const timestamp = Date.now()
setLocal(String(timestamp), COUNTDOWN_KEY)
setLocal(props.email, COUNTDOWN_EMAIL_KEY)
}
// 从 localStorage 恢复倒计时
const restoreCountdown = () => {
const savedTimestamp = getLocal(COUNTDOWN_KEY)
const savedEmail = getLocal(COUNTDOWN_EMAIL_KEY)
// 检查是否有保存的倒计时,且是同一个邮箱
if (savedTimestamp && savedEmail === props.email) {
const elapsed = Math.floor((Date.now() - Number(savedTimestamp)) / 1000)
const remaining = COUNTDOWN_DURATION - elapsed
if (remaining > 0) {
// 如果还有剩余时间,恢复倒计时
countdown.value = remaining
startCountdown()
return true
} else {
// 如果已经过期,清除数据
clearCountdownData()
}
}
return false
}
// 开始倒计时
const startCountdown = () => {
// 清除之前的定时器
if (countdownTimer.value) {
clearInterval(countdownTimer.value)
}
countdownTimer.value = setInterval(() => {
countdown.value-- countdown.value--
if (countdown.value <= 0) { if (countdown.value <= 0) {
clearInterval(timer) if (countdownTimer.value) {
clearInterval(countdownTimer.value)
countdownTimer.value = null
}
clearCountdownData()
} }
}, 1000) }, 1000) as unknown as number
} }
const handleSendVerifyCode = () => { // 发送验证码
handleCountdown() const handleSendVerifyCode = async () => {
if (loading.value) return
loading.value = true
try {
await precheckEmail({ email: props.email })
showToast('the verification code has been sent to your email')
countdown.value = COUNTDOWN_DURATION
saveCountdownStart()
startCountdown()
} catch (error) {
console.error('发送验证码失败:', error)
showToast('Failed to send verification code, please try again')
} finally {
loading.value = false
}
} }
const handleResend = () => { const handleResend = async () => {
if (countdown.value > 0) return if (countdown.value > 0) return
countdown.value = 60 await handleSendVerifyCode()
handleSendVerifyCode()
emit('resend')
} }
const handleConfirmCaptcha = () => { const handleConfirmCaptcha = () => {
@@ -97,6 +163,12 @@ const handleConfirmCaptcha = () => {
showToast('please enter the correct verification code.') showToast('please enter the correct verification code.')
return return
} }
// 验证成功后清除倒计时数据
clearCountdownData()
if (countdownTimer.value) {
clearInterval(countdownTimer.value)
countdownTimer.value = null
}
emit('nextStep', { code: password }) emit('nextStep', { code: password })
} }
@@ -208,7 +280,24 @@ watch(cIndex, () => {
// Lifecycle // Lifecycle
onMounted(() => { onMounted(() => {
resetCaret() resetCaret()
handleSendVerifyCode() // 尝试恢复倒计时,如果无法恢复则发送验证码
const restored = restoreCountdown()
if (!restored) {
// 如果没有恢复倒计时,说明倒计时已结束或不存在,需要发送验证码
handleSendVerifyCode()
}
// 如果恢复了倒计时,说明倒计时还未结束,不发送验证码
})
onUnmounted(() => {
// 组件卸载时清理定时器
if (countdownTimer.value) {
clearInterval(countdownTimer.value)
countdownTimer.value = null
}
if (timeout.value) {
clearTimeout(timeout.value)
}
}) })
// Expose methods for parent component // Expose methods for parent component