264 lines
5.9 KiB
Vue
264 lines
5.9 KiB
Vue
<template>
|
|
<view class="login-container">
|
|
<view class="login-header">
|
|
<text class="title">欢迎使用预约系统</text>
|
|
<text class="subtitle">请登录或注册</text>
|
|
</view>
|
|
|
|
<view class="login-form">
|
|
<!-- 手机号输入 -->
|
|
<view class="form-item">
|
|
<t-input v-model:value="phone" placeholder="请输入手机号" type="number" :maxlength="11" clearable>
|
|
<template #prefixIcon>
|
|
<text class="prefix-icon">📱</text>
|
|
</template>
|
|
</t-input>
|
|
</view>
|
|
|
|
<!-- 验证码登录 -->
|
|
<view class="form-item" v-if="loginType === 'code'">
|
|
<t-input v-model:value="code" placeholder="请输入验证码" type="number" :maxlength="6" clearable>
|
|
<template #prefixIcon>
|
|
<text class="prefix-icon">🔐</text>
|
|
</template>
|
|
<template #suffix>
|
|
<t-button size="small" variant="text" :disabled="codeDisabled" @click="sendCode">
|
|
{{ codeButtonText }}
|
|
</t-button>
|
|
</template>
|
|
</t-input>
|
|
</view>
|
|
|
|
<!-- 登录按钮 -->
|
|
<view class="form-actions">
|
|
<t-button v-if="loginType === 'code'" t-class="btn-primary" theme="primary" size="large" block :loading="loading"
|
|
@click="codeLogin">
|
|
验证码登录
|
|
</t-button>
|
|
|
|
<t-button v-else t-class="btn-primary" theme="primary" size="large" block :loading="loading" @click="oneClickLogin">
|
|
一键登录
|
|
</t-button>
|
|
</view>
|
|
|
|
<view class="form-switch">
|
|
<text @click="toggleLoginType">
|
|
{{ loginType === 'code' ? '使用一键登录' : '使用验证码登录' }}
|
|
</text>
|
|
<text class="register-link" @click="goToRegister">注册新账号</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import { api } from '@/utils/api'
|
|
|
|
const phone = ref('13777777777')
|
|
const code = ref('')
|
|
const loginType = ref<'code' | 'one-click'>('one-click')
|
|
const loading = ref(false)
|
|
const codeDisabled = ref(false)
|
|
const countdown = ref(0)
|
|
|
|
const codeButtonText = ref('发送验证码')
|
|
|
|
// 切换登录方式
|
|
const toggleLoginType = () => {
|
|
loginType.value = loginType.value === 'code' ? 'one-click' : 'code'
|
|
}
|
|
|
|
// 发送验证码
|
|
const sendCode = async () => {
|
|
console.log(phone.value);
|
|
if (!phone.value || phone.value.length !== 11) {
|
|
uni.showToast({
|
|
title: '请输入正确的手机号',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
try {
|
|
await api.auth.sendCode('+86' + phone.value)
|
|
uni.showToast({
|
|
title: '验证码已发送',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 开始倒计时
|
|
codeDisabled.value = true
|
|
countdown.value = 60
|
|
const timer = setInterval(() => {
|
|
countdown.value--
|
|
codeButtonText.value = `${countdown.value}秒后重发`
|
|
if (countdown.value <= 0) {
|
|
clearInterval(timer)
|
|
codeDisabled.value = false
|
|
codeButtonText.value = '发送验证码'
|
|
}
|
|
}, 1000)
|
|
} catch (error) {
|
|
console.error('发送验证码失败', error)
|
|
}
|
|
}
|
|
|
|
// 验证码登录
|
|
const codeLogin = async () => {
|
|
if (!phone.value || phone.value.length !== 11) {
|
|
uni.showToast({
|
|
title: '请输入正确的手机号',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
if (!code.value || code.value.length !== 6) {
|
|
uni.showToast({
|
|
title: '请输入验证码',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
try {
|
|
const res = await api.auth.verificationLogin('+86' + phone.value, code.value)
|
|
uni.setStorageSync('token', res.token)
|
|
uni.setStorageSync('user', res.user)
|
|
|
|
uni.showToast({
|
|
title: '登录成功',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 直接跳转到首页
|
|
uni.reLaunch({ url: '/pages/index/index' })
|
|
} catch (error) {
|
|
console.error('登录失败', error)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 一键登录
|
|
const oneClickLogin = async () => {
|
|
if (!phone.value || phone.value.length !== 11) {
|
|
uni.showToast({
|
|
title: '请输入正确的手机号',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
try {
|
|
const res = await api.auth.oneClickLogin('+86' + phone.value)
|
|
uni.setStorageSync('token', res.token)
|
|
uni.setStorageSync('user', res.user)
|
|
|
|
uni.showToast({
|
|
title: '登录成功',
|
|
icon: 'success'
|
|
})
|
|
|
|
// 直接跳转到首页
|
|
uni.reLaunch({ url: '/pages/index/index' })
|
|
} catch (error) {
|
|
console.error('登录失败', error)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
// 跳转到注册页
|
|
const goToRegister = () => {
|
|
uni.navigateTo({ url: '/pages/register/register' })
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.login-container {
|
|
min-height: 100vh;
|
|
background: linear-gradient(135deg, #FF7A00 0%, #FF9500 100%);
|
|
padding: 80rpx 40rpx;
|
|
}
|
|
|
|
.login-header {
|
|
text-align: center;
|
|
margin-bottom: 100rpx;
|
|
}
|
|
|
|
.title {
|
|
display: block;
|
|
font-size: 48rpx;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.subtitle {
|
|
display: block;
|
|
font-size: 28rpx;
|
|
color: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
.login-form {
|
|
background: #ffffff;
|
|
border-radius: 32rpx;
|
|
padding: 60rpx 40rpx;
|
|
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.form-item {
|
|
margin-bottom: 32rpx;
|
|
}
|
|
|
|
.prefix-icon {
|
|
font-size: 32rpx;
|
|
color: #FF7A00;
|
|
}
|
|
|
|
.form-actions {
|
|
margin-top: 60rpx;
|
|
}
|
|
|
|
.form-switch {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-top: 32rpx;
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.form-switch text {
|
|
padding: 16rpx 0;
|
|
}
|
|
|
|
.register-link {
|
|
color: #FF7A00 !important;
|
|
font-weight: bold;
|
|
}
|
|
</style>
|
|
|
|
<style>
|
|
/* 按钮自定义样式 - 使用全局样式 */
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, #FF7A00 0%, #FF9500 100%) !important;
|
|
border: none !important;
|
|
border-radius: 8rpx !important;
|
|
color: #FFFFFF !important;
|
|
box-shadow: 0 4rpx 12rpx rgba(255, 122, 0, 0.3) !important;
|
|
outline: none !important;
|
|
}
|
|
|
|
.btn-primary::after {
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
.btn-primary:active {
|
|
background: linear-gradient(135deg, #FF6900 0%, #FF8500 100%) !important;
|
|
}
|
|
</style> |