231 lines
4.4 KiB
Plaintext
231 lines
4.4 KiB
Plaintext
<template>
|
|
<view class="page-container">
|
|
<scroll-view class="content-scroll" direction="vertical">
|
|
<!-- 顶部 -->
|
|
<view class="logo-section">
|
|
<image class="logo" src="/static/logo.png" mode="aspectFit"></image>
|
|
<text class="page-title">验证码登录</text>
|
|
<text class="page-subtitle">使用手机验证码快速登录</text>
|
|
</view>
|
|
|
|
<!-- 表单区域 -->
|
|
<view class="form-section">
|
|
<!-- 手机号输入 -->
|
|
<view class="input-wrapper">
|
|
<input
|
|
class="input-field"
|
|
type="number"
|
|
v-model="phone"
|
|
placeholder="请输入手机号"
|
|
maxlength="11"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 验证码输入 -->
|
|
<view class="input-wrapper">
|
|
<input
|
|
class="input-field"
|
|
type="number"
|
|
v-model="code"
|
|
placeholder="请输入验证码"
|
|
maxlength="6"
|
|
/>
|
|
<countdown-btn
|
|
ref="countdownBtnRef"
|
|
:phone="phone"
|
|
codeType="login"
|
|
@send="handleSendCode"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 登录按钮 -->
|
|
<view
|
|
class="btn-login"
|
|
:class="canSubmit ? 'btn-active' : 'btn-disabled'"
|
|
@tap="handleLogin"
|
|
>
|
|
<text class="btn-text">登录</text>
|
|
</view>
|
|
|
|
<!-- 切换到密码登录 -->
|
|
<text class="switch-text" @tap="handleBack">密码登录</text>
|
|
</view>
|
|
|
|
<!-- 底部注册 -->
|
|
<view class="footer-section">
|
|
<text class="footer-text">还没有账号? </text>
|
|
<text class="register-text" @tap="handleRegister">注册</text>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { apiLoginByCode, apiSendCode } from '../../api/auth'
|
|
import CountdownBtn from '../../components/countdown-btn.uvue'
|
|
import { setUserInfo } from '../../store/user'
|
|
|
|
const phone = ref('')
|
|
const code = ref('')
|
|
const countdownBtnRef = ref<any>(null)
|
|
|
|
const canSubmit = computed((): boolean => {
|
|
const phoneReg = /^1[3-9]\d{9}$/
|
|
return phoneReg.test(phone.value) && code.value.length === 6
|
|
})
|
|
|
|
/**
|
|
* 发送验证码
|
|
*/
|
|
async function handleSendCode(p: string) {
|
|
if (!/^1[3-9]\d{9}$/.test(p)) {
|
|
uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
const res = await apiSendCode({ phone: p, type: 'login' })
|
|
if (res && res.code === 0) {
|
|
uni.showToast({ title: '验证码已发送', icon: 'success' })
|
|
countdownBtnRef.value?.startCountdown()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 登录
|
|
*/
|
|
async function handleLogin() {
|
|
if (!canSubmit.value) return
|
|
|
|
const res = await apiLoginByCode({ phone: phone.value, code: code.value })
|
|
if (res && res.data) {
|
|
setUserInfo(res.data)
|
|
uni.showToast({ title: '登录成功', icon: 'success' })
|
|
setTimeout(() => {
|
|
uni.reLaunch({ url: '/pages/index/index' })
|
|
}, 1000)
|
|
}
|
|
}
|
|
|
|
function handleBack() {
|
|
uni.navigateBack()
|
|
}
|
|
|
|
function handleRegister() {
|
|
uni.navigateTo({ url: '/pages/register/index' })
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.page-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
background-color: #FFFFFF;
|
|
}
|
|
|
|
.content-scroll {
|
|
flex: 1;
|
|
padding: 24px 24px calc(24px + var(--uni-safe-area-inset-bottom));
|
|
}
|
|
|
|
.logo-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin-bottom: 32px;
|
|
}
|
|
|
|
.logo {
|
|
width: 80px;
|
|
height: 80px;
|
|
border-radius: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 24px;
|
|
font-weight: 600;
|
|
color: #1F2937;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.page-subtitle {
|
|
font-size: 14px;
|
|
color: #9CA3AF;
|
|
}
|
|
|
|
.form-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex: 1;
|
|
}
|
|
|
|
.input-wrapper {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
height: 52px;
|
|
background-color: #F9FAFB;
|
|
border-radius: 12px;
|
|
padding: 0 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.input-field {
|
|
flex: 1;
|
|
font-size: 16px;
|
|
color: #1F2937;
|
|
}
|
|
|
|
.btn-login {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 52px;
|
|
border-radius: 26px;
|
|
margin-bottom: 20px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.btn-active {
|
|
background-color: #6C63FF;
|
|
}
|
|
|
|
.btn-disabled {
|
|
background-color: #E5E7EB;
|
|
}
|
|
|
|
.btn-text {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
.switch-text {
|
|
font-size: 14px;
|
|
color: #6C63FF;
|
|
text-align: center;
|
|
}
|
|
|
|
.footer-section {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-top: auto;
|
|
padding-top: 24px;
|
|
}
|
|
|
|
.footer-text {
|
|
font-size: 14px;
|
|
color: #6B7280;
|
|
}
|
|
|
|
.register-text {
|
|
font-size: 14px;
|
|
color: #6C63FF;
|
|
font-weight: 600;
|
|
}
|
|
</style>
|