liveh5-nuxt/app/pages/login/index.vue
xingyy 13bc4f4883 refactor(login): 优化登录页面逻辑
- 移除了多余的注释代码
- 简化了验证码发送逻辑
- 删除了未使用的函数
- 优化了代码结构,提高了代码可读性
2025-03-12 11:18:37 +08:00

305 lines
8.5 KiB
Vue

<script setup>
import { useRouter, useRoute } from 'vue-router';
import Vcode from "vue3-puzzle-vcode";
import { useI18n } from 'vue-i18n'
import countryCode from '../countryRegion/data/index.js'
import {senCode, userLogin,userCaptcha,userCaptchaValidate,} from "@/api/auth/index.js";
import {authStore} from "@/stores/auth/index.js";
import {message} from '@/components/x-message/useMessage.js'
import {fddCheck} from "~/api/goods/index.js";
import zu6020 from '@/static/images/zu6020@2x.png'
import PuzzleComponent from '@/components/puzzleComponent/index.vue'
import { ref } from 'vue';
const {userInfo,token,selectedZone}= authStore()
const router = useRouter();
const route = useRoute();
const { locale } = useI18n()
const imgs=ref([zu6020])
definePageMeta({
name: 'login',
i18n: 'login.title'
})
const loadingRef=ref({
loading1:false,
loading2:false,
})
const isExist=ref(false)//帐号是否存在 true存在
const isReal=ref(false) //isReal 是否实名过
const codeInput=ref(null)
function goToPage() {
router.push('/countryRegion');
}
const interval=ref(null)
const startCountdown=()=> {
if (interval.value){
clearInterval(interval.value);
}
countdown.value = 60;
interval.value = setInterval(() => {
if (countdown.value > 0) {
countdown.value--;
} else {
clearInterval(interval.value);
}
}, 1000);
}
const countdown = ref(0);
const phoneNum = ref('')
const code = ref('')
const pane = ref(0)
// 根据语言获取默认国家
const getDefaultCountry = () => {
let defaultCode = 'CN' // 默认中国大陆
switch (locale.value) {
case 'zh-CN':
defaultCode = 'CN'
break
case 'zh-TW':
defaultCode = 'TW'
break
case 'ja-JP':
defaultCode = 'JP'
break
case 'en-US':
defaultCode = 'US'
break
}
const country = countryCode.find(c => c.code === defaultCode)
return {
zone: country.zone,
name: locale.value === 'zh-CN' ? country.cn :
locale.value === 'zh-TW' ? country.tw :
locale.value === 'ja-JP' ? country.ja :
country.en
}
}
const defaultCountry = getDefaultCountry()
const selectedCountry = ref('')
onMounted(()=>{
selectedZone.value=route.query.zone || defaultCountry.zone
selectedCountry.value=route.query.countryName || defaultCountry.name
})
const vanSwipeRef=ref(null)
const captcha=ref({
nonceStr: "",
blockX: 256 ,
blockWidth:50,
blockHeight:50,
canvasWidth:320,
canvasHeight:191,
place:0,
canvasSrc:'',
blockSrc:'',
blockY:0
})
const getCode =async () => {
loadingRef.value.loading1=true
const res=await userCaptcha(captcha.value)
if (res.status===0){
captcha.value.canvasSrc=`data:image/png;base64,${res.data.canvasSrc}`
captcha.value.blockSrc=`data:image/png;base64,${res.data.blockSrc}`
captcha.value.blockY=res.data.blockY
captcha.value.nonceStr=res.data.nonceStr
isShow.value=true
loadingRef.value.loading1=false
}
}
const goBack = () => {
code.value = ''
pane.value = 0
vanSwipeRef.value?.swipeTo(pane.value)
}
const goLogin =async () => {
loadingRef.value.loading2=true
const res=await userLogin({
telNum:phoneNum.value,
zone:selectedZone.value,
code:code.value
})
if (res.status===0){
userInfo.value=res.data.accountInfo
token.value=res.data.token
if (res.data?.accountInfo?.userExtend?.isReal===0){
await router.push({
path: '/realAuth',
query:{
statusCode:0
}
})
}else if (res.data.isJumpFdd){
const res1=await fddCheck()
if (res1.status===0){
window.location.href=res1.data.h5Url
}
}else {
await router.push('/');
}
}
loadingRef.value.loading2=false
}
const isKeyboardVisible = ref(false)
const windowHeight = ref(window.innerHeight)
const isFocused = ref(false)
onMounted(() => {
// 记录初始窗口高度
windowHeight.value = window.innerHeight
// 监听窗口大小变化
window.addEventListener('resize', () => {
// 如果当前高度明显小于初始高度,认为键盘已打开
isKeyboardVisible.value = window.innerHeight < windowHeight.value * 0.8
})
})
onUnmounted(() => {
window.removeEventListener('resize', () => {})
})
const isShow=ref(false)
const onLeave =async (moveX, callback) => {
loadingRef.value.loading1=true
const res=await senCode({
telNum:phoneNum.value,
zone:selectedZone.value,
verifyCaptcha:{
blockX:moveX,
nonceStr:captcha.value.nonceStr
}
})
loadingRef.value.loading1=false
if (res.status===408){
callback(false)
getCode()
}else if([407,0].includes(res.status)){
callback(true)
setTimeout(() => {
pane.value = 1
vanSwipeRef.value?.swipeTo(pane.value)
startCountdown();
isShow.value=false
}, 1000)
}
}
</script>
<template>
<div class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-bottom bg-cover grow-1 px-[31px] pt-[86px]">
<div class="w-full flex justify-center mb-[100px]">
<img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt="">
</div>
<van-swipe ref="vanSwipeRef" :show-indicators="false" :touchable="false" :lazy-render="true" :loop="false">
<van-swipe-item >
<div v-if="pane===0">
<div class="">
<div class="w-full flex justify-between" @click="goToPage">
<div class="text-[16px] text-[#000]">
{{ selectedCountry }}
</div>
<div><van-icon color="#777" name="arrow" size="14" /></div>
</div>
<div class="border-b-[1.7px] mt-[8px]">
<van-field v-model="phoneNum" clearable :placeholder="$t('login.phonePlaceholder')">
<template #label>
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
+{{ selectedZone }}
</div>
</template>
</van-field>
</div>
</div>
<div class="mt-[55px]">
<van-button :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('login.getCode')" color="#2B53AC" block style="height: 48px" @click="getCode">{{ $t('login.getCode') }}</van-button>
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode') }}</van-button>
</div>
</div>
</van-swipe-item>
<van-swipe-item>
<div v-if="pane===1">
<div class="flex mb-[16px]">
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('login.hasSendTo') }}</div>
<div class="text-[16px] text-[#000]">+{{ selectedZone }} {{ phoneNum }}</div>
</div>
<div class="relative">
<van-password-input
:value="code"
:gutter="10"
:mask="false"
:focused="isFocused"
/>
<input
v-model="code"
type="tel"
maxlength="6"
ref="codeInput"
class="opacity-0 absolute top-0 left-0 h-full w-full"
@input="code = $event.target.value.replace(/\D/g, '').slice(0, 6)"
@focus="isFocused = true"
@blur="isFocused = false"
/>
</div>
<div class="flex justify-between">
<div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'} text-14px`">
{{ $t('login.reSend') }}<span v-if="countdown>0">({{countdown}})</span>
</div>
<div @click="goBack" class="text-#2B53AC text-14px">
{{ $t('login.back') }}
</div>
</div>
<div class="mt-[17px]">
<van-button v-if="code.length === 6" type="primary" block :loading="loadingRef.loading2" :loading-text="$t('login.login')" style="height: 48px" @click="goLogin">{{ $t('login.login') }}</van-button>
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.login') }}</van-button>
</div>
</div>
</van-swipe-item>
</van-swipe>
<div v-if="!isKeyboardVisible" class="text-center text-14px absolute left-1/2 transform translate-x--1/2 bottom-20px">
{{ $t('login.agreement') }}<span class="text-#3454AF " @click="$router.push('/privacyPolicy')">{{ $t('login.privacyPolicy') }}</span>
</div>
<van-popup v-model:show="isShow" round>
<PuzzleComponent
:options="captcha"
@leave="onLeave"
/>
</van-popup>
</div>
</template>
<style scoped lang="scss">
:deep(.van-cell.van-field) {
padding-left: 0;
}
:deep(.van-password-input) {
margin: 0;
}
:deep(.van-password-input__item) {
border: 1px solid #E5E5E5;
width: 41px;
height: 41px;
}
.verify-popup-content {
width: 90vw;
max-width: 350px;
padding: 20px;
box-sizing: border-box;
}
:deep(.van-popup) {
background: transparent;
}
</style>