311 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			8.6 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)
 | |
| 
 | |
|   }else{
 | |
|     setTimeout(() => {
 | |
|        
 | |
|   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   teleport="body">
 | |
|       <PuzzleComponent
 | |
|       v-if="isShow"
 | |
|       :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>
 |