yl-frontend/src/views/RegisterView.vue

644 lines
15 KiB
Vue

<template>
<div class="register-container">
<div class="background">
<div class="shape"></div>
<div class="shape"></div>
</div>
<el-card class="register-card" :body-style="{ padding: '30px' }">
<div class="register-content">
<div class="basic-info">
<div class="register-header">
<div class="logo">
<el-icon :size="40" color="#409EFF"><Platform /></el-icon>
</div>
<h2>智慧养老平台</h2>
<p class="subtitle">创建新账号</p>
</div>
<el-form
ref="registerFormRef"
:model="registerForm"
:rules="rules"
label-position="top"
class="animated-form"
>
<el-form-item label="姓名" prop="username">
<el-input
v-model="registerForm.username"
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><User /></el-icon>
</div>
</template>
</el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="registerForm.password"
type="password"
show-password
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><Lock /></el-icon>
</div>
</template>
</el-input>
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
show-password
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><Lock /></el-icon>
</div>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
<div class="verify-info">
<div class="divider">联系方式验证</div>
<div class="verify-section">
<div class="verify-title">
<el-icon><Phone /></el-icon>
<span>手机验证</span>
</div>
<el-form
:model="registerForm"
:rules="rules"
label-position="top"
>
<el-form-item label="手机号" prop="phone">
<div class="verify-code-input">
<el-input
v-model="registerForm.phone"
placeholder="请输入手机号"
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><Phone /></el-icon>
</div>
</template>
</el-input>
<el-button
type="primary"
:disabled="phoneCooldown > 0 || !registerForm.phone"
@click="sendPhoneCode"
>
{{ phoneCooldown > 0 ? `${phoneCooldown}s` : '获取验证码' }}
</el-button>
</div>
</el-form-item>
<el-form-item label="验证码" prop="phoneCode">
<el-input
v-model="registerForm.phoneCode"
placeholder="请输入手机验证码"
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><Key /></el-icon>
</div>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
<div class="verify-section">
<div class="verify-title">
<el-icon><Message /></el-icon>
<span>邮箱验证</span>
</div>
<el-form
:model="registerForm"
:rules="rules"
label-position="top"
>
<el-form-item label="邮箱号" prop="email">
<div class="verify-code-input">
<el-input
v-model="registerForm.email"
placeholder="请输入邮箱"
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><Message /></el-icon>
</div>
</template>
</el-input>
<el-button
type="primary"
:disabled="emailCooldown > 0 || !registerForm.email"
@click="sendEmailCode"
>
{{ emailCooldown > 0 ? `${emailCooldown}s` : '获取验证码' }}
</el-button>
</div>
</el-form-item>
<el-form-item label="验证码" prop="emailCode">
<el-input
v-model="registerForm.emailCode"
placeholder="请输入邮箱验证码"
class="custom-input"
>
<template #prefix>
<div class="input-icon">
<el-icon><Key /></el-icon>
</div>
</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
</div>
<el-button
type="primary"
class="register-button"
:loading="loading"
@click="handleRegister"
>
<span class="button-text">注 册</span>
<el-icon class="button-icon"><Right /></el-icon>
</el-button>
<div class="login-link">
已有账号?
<router-link to="/login" class="login-btn">立即登录</router-link>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { User, Lock, Phone, Message, Platform, Right, Key } from '@element-plus/icons-vue'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import { userApi } from '@/api/user'
const router = useRouter()
const registerFormRef = ref<FormInstance>()
const loading = ref(false)
const registerForm = reactive({
username: '',
phone: '',
password: '',
confirmPassword: '',
phoneCode: '',
email: '',
emailCode: ''
})
const validatePass = (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== registerForm.password) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
const validateEmail = (rule: any, value: string, callback: any) => {
if (value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
callback(new Error('请输入正确的邮箱地址'))
} else {
callback()
}
}
const rules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, message: '用户名长度不能小于3个字符', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度不能小于6个字符', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请再次输入密码', trigger: 'blur' },
{ validator: validatePass, trigger: 'blur' }
],
phoneCode: [
{ required: true, message: '请输入验证码', trigger: 'blur' }
],
email: [
{ validator: validateEmail, trigger: 'blur' }
],
emailCode: [
{ required: true, message: '请输入邮箱验证码', trigger: 'blur' }
]
}
const handleRegister = async () => {
if (!registerFormRef.value) return
await registerFormRef.value.validate(async (valid) => {
if (valid) {
loading.value = true
try {
// 这里添加实的注册逻辑
// const response = await register(registerForm)
// 模拟注册成功
await new Promise(resolve => setTimeout(resolve, 1000))
ElMessage.success('注册成功')
router.push('/login')
} catch (error) {
ElMessage.error('注册失败,请稍后重试')
} finally {
loading.value = false
}
}
})
}
// 添加验证码相关逻辑
const phoneCooldown = ref(0)
const emailCooldown = ref(0)
// 手机验证码倒计时
const startPhoneCooldown = () => {
phoneCooldown.value = 60
const timer = setInterval(() => {
phoneCooldown.value--
if (phoneCooldown.value <= 0) {
clearInterval(timer)
}
}, 1000)
}
// 邮箱验证码倒计时
const startEmailCooldown = () => {
emailCooldown.value = 60
const timer = setInterval(() => {
emailCooldown.value--
if (emailCooldown.value <= 0) {
clearInterval(timer)
}
}, 1000)
}
// 发送手机验证码
const sendPhoneCode = () => {
if (phoneCooldown.value > 0 || !registerForm.phone) {
ElMessage.warning('请先输入手机号')
return
}
// 验证手机号格式
if (!/^1[3-9]\d{9}$/.test(registerForm.phone)) {
ElMessage.warning('请输入正确的手机号')
return
}
// 这里添加发送验证码的逻辑
ElMessage.success('手机验证码已发送')
startPhoneCooldown()
}
// 发送邮箱验证码
const sendEmailCode = async () => {
if (emailCooldown.value > 0 || !registerForm.email) return
const result = await userApi.sendVerifyEmailCode(registerForm.email)
console.log(result)
console.log(result.code)
ElMessage.success('邮箱验证码已发送')
startEmailCooldown()
}
</script>
<style scoped>
.register-container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(45deg, #1a1a1a, #434343);
position: relative;
overflow: hidden;
}
.background {
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
}
.shape {
position: absolute;
border-radius: 50%;
background: linear-gradient(45deg, #ff6b6b, #ff8e8e);
animation: float 6s ease-in-out infinite;
}
.shape:nth-child(1) {
width: 500px;
height: 500px;
top: -250px;
right: -100px;
background: linear-gradient(45deg, #4481eb, #04befe);
}
.shape:nth-child(2) {
width: 400px;
height: 400px;
bottom: -200px;
left: -100px;
background: linear-gradient(45deg, #ff6b6b, #ff8e8e);
animation-delay: -3s;
}
@keyframes float {
0% {
transform: translateY(0) rotate(0deg);
}
50% {
transform: translateY(-20px) rotate(5deg);
}
100% {
transform: translateY(0) rotate(0deg);
}
}
.register-card {
width: 1100px;
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
border: 1px solid rgba(255, 255, 255, 0.18);
position: relative;
z-index: 1;
transition: transform 0.3s ease;
}
.register-card:hover {
transform: translateY(-5px);
}
.register-header {
text-align: center;
margin-bottom: 30px;
}
.logo {
margin-bottom: 20px;
}
.subtitle {
color: #606266;
margin-top: 10px;
}
.custom-input {
height: 50px;
border-radius: 10px;
}
.custom-input :deep(.el-input__wrapper) {
padding-left: 45px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.input-icon {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: #909399;
}
.verify-code-input {
display: flex;
gap: 10px;
align-items: flex-start;
}
.verify-code-input .el-input {
flex: 1;
}
.verify-code-input .el-button {
width: 120px;
height: 50px;
margin-top: 0;
}
.verify-section .verify-code-input + .el-form-item .el-input {
margin-left: calc(100% - 100%);
}
.register-button {
width: 100%;
margin-bottom: 20px;
}
.login-link {
text-align: center;
font-size: 14px;
color: #606266;
}
.login-link a {
color: #409EFF;
text-decoration: none;
}
.login-link a:hover {
color: #66b1ff;
}
.divider {
text-align: center;
color: #909399;
font-size: 14px;
margin: 20px 0;
position: relative;
display: flex;
align-items: center;
}
.divider::before,
.divider::after {
content: '';
flex: 1;
height: 1px;
background: #dcdfe6;
margin: 0 16px;
}
.verify-section {
background: #f8f9fa;
border-radius: 12px;
padding: 20px;
margin-bottom: 15px;
}
.verify-section .el-form-item {
margin-bottom: 20px;
}
.verify-section :deep(.el-form-item__label) {
float: none;
display: block;
text-align: left;
padding: 0 0 8px;
line-height: 1.5;
white-space: normal;
}
.verify-section :deep(.el-form-item__content) {
margin-left: 0 !important;
}
.verify-code-input {
display: flex;
gap: 10px;
align-items: flex-start;
width: 100%;
}
.verify-code-input .el-input {
flex: 1;
}
.verify-code-input .el-button {
width: 120px;
height: 50px;
margin-top: 0;
flex-shrink: 0;
}
.verify-title {
display: flex;
align-items: center;
gap: 8px;
color: #409EFF;
font-size: 16px;
font-weight: 500;
margin-bottom: 16px;
}
.verify-title .el-icon {
font-size: 20px;
}
/* 优化输入框样式 */
.custom-input {
height: 50px;
}
.custom-input :deep(.el-input__wrapper) {
background: white;
border: 1px solid #e4e7ed;
box-shadow: none !important;
transition: all 0.3s;
}
.custom-input :deep(.el-input__wrapper:hover) {
border-color: #c0c4cc;
}
.custom-input :deep(.el-input__wrapper.is-focus) {
border-color: #409EFF;
}
/* 优化按钮样式 */
.el-button {
border-radius: 8px;
font-weight: 500;
transition: all 0.3s;
}
.el-button:not(:disabled):hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
}
.register-content {
display: flex;
gap: 30px;
margin-bottom: 30px;
}
.basic-info {
flex: 0.8;
padding-right: 30px;
border-right: 1px solid #e4e7ed;
}
.verify-info {
flex: 1.2;
}
/* 响应式布局 */
@media (max-width: 992px) {
.register-card {
width: 95%;
max-width: 500px;
}
.register-content {
flex-direction: column;
gap: 20px;
}
.basic-info {
padding-right: 0;
border-right: none;
border-bottom: 1px solid #e4e7ed;
padding-bottom: 20px;
flex: none;
}
.verify-info {
flex: none;
}
.verify-code-input {
flex-direction: column;
}
.verify-section .el-form-item:not(:first-child) .el-input {
width: 100%;
margin-left: 0;
}
.verify-code-input .el-button {
width: 100%;
margin-top: 10px;
}
}
</style>