Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/lanecarford_front
This commit is contained in:
26
package-lock.json
generated
26
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"axios": "^1.3.6",
|
||||
"crypto-js": "^4.2.0",
|
||||
"gsap": "^3.13.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
@@ -22,6 +23,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.2.0",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/node": "^18.16.0",
|
||||
"@vant/auto-import-resolver": "^1.3.0",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
@@ -654,6 +656,13 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/crypto-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
|
||||
"integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.1.tgz",
|
||||
@@ -2104,6 +2113,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/css-select/-/css-select-4.3.0.tgz",
|
||||
@@ -8935,6 +8950,12 @@
|
||||
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/crypto-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
|
||||
"integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.1.tgz",
|
||||
@@ -10039,6 +10060,11 @@
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/css-select/-/css-select-4.3.0.tgz",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.3.6",
|
||||
"crypto-js": "^4.2.0",
|
||||
"gsap": "^3.13.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
@@ -26,6 +27,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.2.0",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/node": "^18.16.0",
|
||||
"@vant/auto-import-resolver": "^1.3.0",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { useGenerateStore } from '@/stores/modules/generate'
|
||||
const VerifyIDs = (num: number) => {
|
||||
const ids = [
|
||||
!!useGenerateStore().customerId,
|
||||
!!useGenerateStore().visitRecordId,
|
||||
!!useGenerateStore().styleId,
|
||||
// !!useGenerateStore().modelPhotoId,
|
||||
true,
|
||||
!!useGenerateStore().originalTryOnId,
|
||||
];
|
||||
return ids.splice(0, num).every(id => id) ? true : "/stylist/customer";
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由缓存机制:
|
||||
* 1. 设置路由的meta属性为{ cache: true },表示需要缓存
|
||||
* 2. App.vue中使用RouteCache组件,通过路由的name来进行匹配
|
||||
* 3. 路由的name默认是文件名,如果文件名与name不一致,通过defineOptions({ name: 'componentName' })来设置
|
||||
*
|
||||
* 自定义验证规则:
|
||||
* meta:{ verify: ()=> boolean || string }
|
||||
* 1. boolean true 跳转 false 不跳转
|
||||
* 2. string 跳转的路由path
|
||||
*/
|
||||
|
||||
|
||||
/** 验证id
|
||||
* @param num 验证id的数量1-5
|
||||
* 1. 顾客id
|
||||
* 2. 进店记录id
|
||||
* 3. 服装id
|
||||
* 4. 模特照片id
|
||||
* 5. 原始试穿id-优先AI魔改
|
||||
* @returns boolean
|
||||
*/
|
||||
const router = createRouter({
|
||||
history: createWebHistory('/'),
|
||||
// history: createWebHistory(import.meta.env.VITE_APP_URL),
|
||||
@@ -45,22 +70,25 @@ const router = createRouter({
|
||||
{
|
||||
path: 'index',
|
||||
name: 'index',
|
||||
component: () => import('@/views/stylist/index.vue')
|
||||
component: () => import('@/views/stylist/index.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
path: 'sex',
|
||||
name: 'sex',
|
||||
component: () => import('@/views/stylist/sex.vue')
|
||||
component: () => import('@/views/stylist/sex.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
path: 'dressfor',
|
||||
name: 'dressfor',
|
||||
component: () => import('@/views/stylist/dressfor.vue')
|
||||
component: () => import('@/views/stylist/dressfor.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
path: 'customer',
|
||||
name: 'customer',
|
||||
component: () => import('@/views/stylist/customer.vue')
|
||||
component: () => import('@/views/stylist/customer.vue'),
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -68,7 +96,7 @@ const router = createRouter({
|
||||
path: '/asistant',
|
||||
name: 'asistant',
|
||||
component: () => import('../views/asistant/index.vue'),
|
||||
meta: { cache: true }
|
||||
meta: { cache: true, verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
path: '/workshop',
|
||||
@@ -83,57 +111,67 @@ const router = createRouter({
|
||||
path: '/workshop/selectStyle',
|
||||
name: 'SelectStyle',
|
||||
component: () => import('../views/Workshop/selectStyle.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
path: '/workshop/selectModel',
|
||||
name: 'SelectModel',
|
||||
component: () => import('../views/Workshop/selectModel.vue')
|
||||
component: () => import('../views/Workshop/selectModel.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(3) }
|
||||
},
|
||||
{
|
||||
path: '/workshop/product',
|
||||
name: 'Product',
|
||||
component: () => import('../views/Workshop/product.vue')
|
||||
component: () => import('../views/Workshop/product.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(4) }
|
||||
},
|
||||
{
|
||||
// 上传照片1
|
||||
path: '/workshop/uploadFace',
|
||||
name: 'uploadFace',
|
||||
component: () => import('../views/Workshop/uploadFace1.vue')
|
||||
component: () => import('../views/Workshop/uploadFace1.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(5) }
|
||||
},
|
||||
{
|
||||
// 上传照片2
|
||||
path: '/workshop/uploadFace2',
|
||||
name: 'uploadFace2',
|
||||
component: () => import('../views/Workshop/uploadFace2.vue')
|
||||
component: () => import('../views/Workshop/uploadFace2.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(5) }
|
||||
},
|
||||
{
|
||||
// 自定义创作
|
||||
path: '/workshop/customize',
|
||||
name: 'customize',
|
||||
component: () => import('../views/Workshop/customize.vue')
|
||||
component: () => import('../views/Workshop/customize.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(5) }
|
||||
},
|
||||
{
|
||||
// library
|
||||
path: '/workshop/library',
|
||||
name: 'library',
|
||||
component: () => import('../views/Workshop/library.vue')
|
||||
component: () => import('../views/Workshop/library.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
path: '/workshop/profile',
|
||||
name: 'profile',
|
||||
component: () => import('../views/Workshop/profile.vue')
|
||||
component: () => import('../views/Workshop/profile.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(1) }
|
||||
},
|
||||
{
|
||||
// creation
|
||||
path: '/workshop/creation',
|
||||
name: 'creation',
|
||||
component: () => import('../views/Workshop/creation/index.vue')
|
||||
component: () => import('../views/Workshop/creation/index.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
},
|
||||
{
|
||||
// 完成创建
|
||||
path: '/workshop/end',
|
||||
name: 'end',
|
||||
component: () => import('../views/Workshop/end.vue')
|
||||
component: () => import('../views/Workshop/end.vue'),
|
||||
meta: { verify: ()=> VerifyIDs(2) }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,10 +5,22 @@ const whiteList = ['/login']
|
||||
console.log(whiteList)
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
next()
|
||||
requestAnimationFrame(() => {
|
||||
const verify = to.meta?.verify;
|
||||
if (typeof verify === 'function') {
|
||||
const res = verify()
|
||||
if (res === false) {
|
||||
return next(false)
|
||||
} else if (typeof res === 'string') {
|
||||
console.log(res)
|
||||
return next({ path: res })
|
||||
}
|
||||
}
|
||||
next()
|
||||
})
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
// finish progress bar
|
||||
// NProgress.done()
|
||||
// finish progress bar
|
||||
// NProgress.done()
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// 每一个存储的模块,命名规则use开头,store结尾
|
||||
import { defineStore } from 'pinia'
|
||||
import MyEvent from '@/utils/myEvent'
|
||||
import { uploadCustomerPhoto } from '@/api/workshop'
|
||||
MyEvent.add('clear-generate-state', () => useGenerateStore().clearGenerateData())
|
||||
|
||||
export const useGenerateStore = defineStore({
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
function getUniversalZoomLevel() {
|
||||
// 现代浏览器方案
|
||||
if (window.visualViewport) {
|
||||
@@ -146,3 +148,12 @@ export async function DownloadImages(list: Array<{ url: string, name?: string }>
|
||||
}
|
||||
typeof onSuccess === "function" && onSuccess(successCount, errCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5加密密码
|
||||
* @param password 原始密码
|
||||
* @returns MD5加密后的密码
|
||||
*/
|
||||
export function encryptPassword(password: string): string {
|
||||
return CryptoJS.MD5(password).toString()
|
||||
}
|
||||
@@ -281,6 +281,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
> .icon-selected {
|
||||
|
||||
@@ -220,6 +220,7 @@
|
||||
border: 0.24rem solid #000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
> .icon {
|
||||
margin: 0 1.8rem;
|
||||
}
|
||||
@@ -246,6 +247,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,6 +179,7 @@ const { isLoading } = toRefs(data);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
> .operation{
|
||||
position: absolute;
|
||||
|
||||
@@ -196,7 +196,9 @@ const startRecording = () => {
|
||||
if (!speechRecognition) {
|
||||
// 检查浏览器支持
|
||||
if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) {
|
||||
alert('您的浏览器不支持语音识别功能')
|
||||
// alert('您的浏览器不支持语音识别功能')
|
||||
showToast('Your browser does not support speech recognition, please try again with another browser')
|
||||
isRecording.value = false
|
||||
return
|
||||
}
|
||||
|
||||
@@ -244,7 +246,7 @@ const startRecording = () => {
|
||||
|
||||
// 显示临时结果(可选)
|
||||
if (interimTranscript) {
|
||||
console.log('临时识别结果:', interimTranscript)
|
||||
console.log('语音转文字识别中:', interimTranscript)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +263,7 @@ const startRecording = () => {
|
||||
console.error('语音识别错误:', event.error)
|
||||
isRecording.value = false
|
||||
// alert('语音识别失败,请重试')
|
||||
showToast('Speech recognition failed, please try again')
|
||||
showToast(event.error)
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import { useUserInfoStore } from '@/stores'
|
||||
import { showToast } from 'vant'
|
||||
import { google } from '@/assets/base64'
|
||||
import { fetchRegisterOrLogin } from '@/api/login'
|
||||
import { encryptPassword } from '@/utils/tools'
|
||||
|
||||
const router = useRouter()
|
||||
const userInfoStore = useUserInfoStore()
|
||||
@@ -109,7 +110,8 @@ const handleLogin = async () => {
|
||||
|
||||
isLoading.value = true
|
||||
|
||||
fetchRegisterOrLogin({ ...formData, operationType: 'LOGIN' }).then((response) => {
|
||||
const encryptedPassword = encryptPassword(formData.password)
|
||||
fetchRegisterOrLogin({ ...formData, password: encryptedPassword, operationType: 'LOGIN' }).then((response) => {
|
||||
console.log('登录成功', response)
|
||||
userInfoStore.setToken(response.token)
|
||||
userInfoStore.setUserInfo(response.user)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
v-else-if="step === 'verify'"
|
||||
:ct="emailCode"
|
||||
@nextStep="handleCheckVerifyCode"
|
||||
@resend="handleSendVerifyCode"
|
||||
/>
|
||||
<Password v-else-if="step === 'password'" @sucess="handleSuccess" />
|
||||
</div>
|
||||
@@ -42,7 +41,8 @@ import Mail from './components/Mail.vue'
|
||||
import Verify from './components/Verify.vue'
|
||||
import Password from './components/Password.vue'
|
||||
import { showToast } from 'vant'
|
||||
import { precheckEmail, resetPassword } from '@/api/login'
|
||||
import { resetPassword } from '@/api/login'
|
||||
import { encryptPassword } from '@/utils/tools'
|
||||
|
||||
const router = useRouter()
|
||||
const step = ref<'mail' | 'verify' | 'password'>('mail')
|
||||
@@ -79,10 +79,8 @@ const handleSendVerifyCode = (data: any) => {
|
||||
if (data?.email) {
|
||||
fromData.value.email = data?.email
|
||||
}
|
||||
precheckEmail({ email: fromData.value.email }).then(() => {
|
||||
showToast('the verification code has been sent to your email')
|
||||
handleStep('verify')
|
||||
})
|
||||
// 只切换步骤,验证码的发送由 Verify 组件负责
|
||||
handleStep('verify')
|
||||
}
|
||||
|
||||
const handleCheckVerifyCode = (data: any) => {
|
||||
@@ -92,7 +90,7 @@ const handleCheckVerifyCode = (data: any) => {
|
||||
}
|
||||
|
||||
const handleSuccess = (data: any) => {
|
||||
fromData.value.password = data.password
|
||||
fromData.value.password = encryptPassword(data.password)
|
||||
resetPassword(fromData.value).then((res) => {
|
||||
// console.log('res', res)
|
||||
showToast('the password has been reset')
|
||||
|
||||
@@ -56,6 +56,7 @@ import { useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import { google } from '@/assets/base64'
|
||||
import { fetchRegisterOrLogin } from '@/api/login'
|
||||
import { encryptPassword } from '@/utils/tools'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -121,7 +122,8 @@ const handleConfirm = async () => {
|
||||
|
||||
isLoading.value = true
|
||||
|
||||
fetchRegisterOrLogin({ ...formData, operationType: 'REGISTER' })
|
||||
const encryptedPassword = encryptPassword(formData.password)
|
||||
fetchRegisterOrLogin({ ...formData, password: encryptedPassword, operationType: 'REGISTER' })
|
||||
.then((res) => {
|
||||
console.log('res', res)
|
||||
showToast('register success')
|
||||
|
||||
@@ -31,8 +31,10 @@
|
||||
<div class="btn" @click="handleConfirmCaptcha">Confirm</div>
|
||||
</template>
|
||||
<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 { getLocal, removeLocal, setLocal } from '@/utils/local'
|
||||
import { precheckEmail } from '@/api/login'
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
@@ -48,7 +50,7 @@ const props = defineProps({
|
||||
|
||||
const agreePolicy = ref(false)
|
||||
// Emits
|
||||
const emit = defineEmits(['nextStep','resend'])
|
||||
const emit = defineEmits(['nextStep'])
|
||||
|
||||
// Reactive data
|
||||
const loading = ref(false)
|
||||
@@ -66,24 +68,88 @@ const cIndex = computed(() => {
|
||||
// const lastCode = computed(() => getCtData.value[ctSize.value - 1])
|
||||
|
||||
const countdown = ref(60)
|
||||
const handleCountdown = () => {
|
||||
const timer = setInterval(() => {
|
||||
const countdownTimer = ref<number | null>(null)
|
||||
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--
|
||||
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
|
||||
countdown.value = 60
|
||||
handleSendVerifyCode()
|
||||
emit('resend')
|
||||
await handleSendVerifyCode()
|
||||
}
|
||||
|
||||
const handleConfirmCaptcha = () => {
|
||||
@@ -97,6 +163,12 @@ const handleConfirmCaptcha = () => {
|
||||
showToast('please enter the correct verification code.')
|
||||
return
|
||||
}
|
||||
// 验证成功后清除倒计时数据
|
||||
clearCountdownData()
|
||||
if (countdownTimer.value) {
|
||||
clearInterval(countdownTimer.value)
|
||||
countdownTimer.value = null
|
||||
}
|
||||
emit('nextStep', { code: password })
|
||||
}
|
||||
|
||||
@@ -208,7 +280,24 @@ watch(cIndex, () => {
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user