Files
uni-qnc-tob/src/pages/login.vue
2024-11-24 15:21:01 +08:00

204 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { getCode, login } from '@/api/apis'
const phoneNumber = ref('')
const verificationCode = ref('')
const password = ref('')
const isPasswordLogin = ref(false)
const isAgreed = ref(false)
const isCountingDown = ref(false)
const countdown = ref(60)
let timer = null
// 聚焦状态变量
const phoneFocused = ref(false)
const codeFocused = ref(false)
const passwordFocused = ref(false)
const isPhoneNumberValid = computed(() => {
return /^1[3-9]\d{9}$/.test(phoneNumber.value)
})
const canLogin = computed(() => {
if (!isPhoneNumberValid.value)
return false
if (isPasswordLogin.value) {
return password.value.length >= 6
}
else {
return verificationCode.value.length === 6
}
})
function sendVerificationCode() {
if (isCountingDown.value || !isPhoneNumberValid.value)
return
if (!isPhoneNumberValid.value) {
uni.showToast({ title: '请输入有效的手机号', icon: 'none' })
return
}
getCode({
mobile: phoneNumber.value,
actionType: 'login',
}).then((res) => {
if (res.code === 200) {
uni.showToast({ title: '获取成功', icon: 'none' })
startCountdown()
}
})
}
function startCountdown() {
isCountingDown.value = true
countdown.value = 60
timer = setInterval(() => {
if (countdown.value > 0) {
countdown.value--
}
else {
clearInterval(timer)
isCountingDown.value = false
}
}, 1000)
}
function handleLogin() {
if (!canLogin.value) {
uni.showToast({ title: '请完善信息', icon: 'none' })
return
}
if (!isAgreed.value) {
uni.showToast({ title: '请先同意用户协议', icon: 'none' })
return
}
login({ mobile: phoneNumber.value, code: verificationCode.value }).then((res) => {
console.log('res.data.AccessToken', res.data.accessToken)
if (res.code === 200) {
uni.setStorageSync('token', res.data.accessToken)
uni.showToast({ title: '登录成功', icon: 'none' })
uni.reLaunch({
url: '/pages/index',
})
}
else {
uni.showToast({ title: res.msg, icon: 'none' })
}
})
}
function toUserAgreement() {
uni.navigateTo({
url: '/pages/userAgreement',
})
}
function toPrivacyPolicy() {
uni.navigateTo({
url: '/pages/privacyPolicy',
})
}
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
</script>
<template>
<view class="login px-8">
<view class="mb-8 pt-8 text-left">
<view class="flex flex-col items-center">
<image
class="h-18 w-18 rounded-full shadow"
src="/static/image/logo.png"
mode="scaleToFill"
/>
<image
class="mt-4 h-10"
src="/static/image/logo_title.png"
mode="aspectFit"
/>
</view>
</view>
<view class="space-y-5">
<view class="input-container bg-blue-300/20" :class="[phoneFocused ? 'focused' : '']">
<input
v-model="phoneNumber" class="input-field" type="number" placeholder="请输入手机号" maxlength="11"
@focus="phoneFocused = true" @blur="phoneFocused = false"
>
</view>
<view v-if="!isPasswordLogin">
<view class="flex items-center justify-between">
<view class="input-container bg-blue-300/20" :class="[codeFocused ? 'focused' : '']">
<input
v-model="verificationCode" class="input-field" type="number" placeholder="请输入验证码" maxlength="6"
@focus="codeFocused = true" @blur="codeFocused = false"
>
</view>
<view
class="ml-2 rounded-lg px-4 py-2 text-sm font-bold transition duration-300 focus:outline-none"
:class="isCountingDown || !isPhoneNumberValid ? 'cursor-not-allowed bg-gray-300 text-gray-500' : 'bg-blue-500 text-white hover:bg-blue-600'"
@click="sendVerificationCode"
>
{{ isCountingDown ? `${countdown}s重新获取` : '获取验证码' }}
</view>
</view>
</view>
<view v-if="isPasswordLogin" class="input-container" :class="[passwordFocused ? 'focused' : '']">
<input
v-model="password" class="input-field" type="password" placeholder="请输入密码"
@focus="passwordFocused = true" @blur="passwordFocused = false"
>
</view>
<view class="flex items-start space-x-2">
<wd-checkbox v-model="isAgreed" class="mt-1" />
<text class="text-xs text-gray-400 leading-tight">
未注册手机号登录后将自动生成账号并且代表您已阅读并同意
<text class="cursor-pointer text-blue-400" @click="toUserAgreement">
用户协议
</text>
<text class="cursor-pointer text-blue-400" @click="toPrivacyPolicy">
隐私政策
</text>
</text>
</view>
</view>
<button
class="mt-20 block w-full flex-shrink-0 rounded-full bg-blue-500 py-3 text-lg text-white font-bold transition duration-300"
@click="handleLogin"
>
登录
</button>
</view>
</template>
<style scoped>
.login{
}
.input-container {
border: 2px solid rgba(125, 211, 252, 0.0);
border-radius: 1rem;
@apply transition duration-200
}
.input-container.focused {
border: 2px solid #3b82f6;
}
.input-field {
width: 100%;
padding: 1rem;
transition: border-color 0.3s ease;
outline: none;
background: transparent;
}
</style>
<route lang="json">
{
"layout": "login",
"title": "登录"
}
</route>