保存进度

This commit is contained in:
ovo 2024-12-13 13:58:42 +08:00
parent bd9987d600
commit 40fec98273
3 changed files with 255 additions and 20 deletions

View File

@ -6,13 +6,13 @@ const router = createRouter({
routes: [
{
path: '/login',
name: 'login',
name: 'Login',
component: () => import('../views/LoginView.vue'),
meta: { requiresAuth: false }
},
{
path: '/register',
name: 'register',
name: 'Register',
component: () => import('../views/RegisterView.vue'),
meta: { requiresAuth: false }
},

View File

@ -171,7 +171,7 @@
<div class="register-link">
还没有账号
<router-link to="/register" class="register-btn">立即注册</router-link>
<router-link to="/register">立即注册</router-link>
</div>
</el-card>

View File

@ -186,6 +186,43 @@
已有账号
<router-link to="/login" class="login-btn">立即登录</router-link>
</div>
<!-- 滑块验证码对话框 -->
<el-dialog
v-model="sliderVisible"
title="安全验证"
width="420px"
:show-close="false"
:close-on-click-modal="false"
custom-class="slider-dialog"
>
<div class="slider-container">
<div class="slider-header">
<div class="shield-icon">
<el-icon :size="32"><CircleCheck /></el-icon>
</div>
<span>请完成安全验证</span>
</div>
<el-slider
v-model="sliderValue"
:min="0"
:max="100"
:show-tooltip="false"
@change="handleSliderChange"
class="custom-slider"
>
<template #button>
<el-icon>
<component :is="sliderValue >= 100 ? 'Select' : 'DArrowRight'" />
</el-icon>
</template>
</el-slider>
<div class="slider-text">
<el-icon><Right /></el-icon>
请向右滑动完成验证
</div>
</div>
</el-dialog>
</el-card>
</div>
</template>
@ -193,7 +230,7 @@
<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 { User, Lock, Phone, Message, Platform, Right, Key, DArrowRight, Select, CircleCheck } from '@element-plus/icons-vue'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import { userApi } from '@/api/user'
@ -310,30 +347,65 @@ const startEmailCooldown = () => {
}, 1000)
}
//
const sendPhoneCode = async () => {
// if (phoneCooldown.value > 0 || !registerForm.phone) {
// ElMessage.warning('')
// return
// }
//
const sliderVisible = ref(false)
const sliderValue = ref(0)
const verifiedSuccess = ref(false)
const verifyType = ref<'phone' | 'email'>('phone')
//
//
const handleSliderChange = (value: number) => {
if (value >= 100) {
verifiedSuccess.value = true
sliderVisible.value = false
sliderValue.value = 0
//
if (verifyType.value === 'phone') {
handleSendPhoneCode()
} else {
handleSendEmailCode()
}
}
}
//
const sendPhoneCode = () => {
if (phoneCooldown.value > 0 || !registerForm.phone) return
if (!/^1[3-9]\d{9}$/.test(registerForm.phone)) {
ElMessage.warning('请输入正确的手机号')
return
}
await userApi.sendVerifyPhoneCode(registerForm.phone)
ElMessage.success('手机验证码已发送')
startPhoneCooldown()
verifyType.value = 'phone'
sliderVisible.value = true
}
//
const sendEmailCode = async () => {
//
const handleSendPhoneCode = async () => {
try {
await userApi.sendVerifyPhoneCode(registerForm.phone)
ElMessage.success('手机验证码已发送')
startPhoneCooldown()
} catch (error) {
ElMessage.error('发送失败')
}
}
//
const sendEmailCode = () => {
if (emailCooldown.value > 0 || !registerForm.email) return
await userApi.sendVerifyEmailCode(registerForm.email)
ElMessage.success('邮箱验证码已发送')
startEmailCooldown()
verifyType.value = 'email'
sliderVisible.value = true
}
//
const handleSendEmailCode = async () => {
try {
await userApi.sendVerifyEmailCode(registerForm.email)
ElMessage.success('邮箱验证码已发送')
startEmailCooldown()
} catch (error) {
ElMessage.error('发送失败')
}
}
</script>
@ -640,4 +712,167 @@ const sendEmailCode = async () => {
margin-top: 10px;
}
}
/* 滑块验证码样式 */
.slider-container {
padding: 0;
text-align: center;
}
.slider-header {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
margin-bottom: 35px;
color: #303133;
font-size: 18px;
font-weight: 500;
}
.slider-text {
margin-top: 20px;
color: #909399;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.custom-slider {
padding: 10px;
background: #f8f9fa;
border-radius: 25px;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.08);
}
:deep(.el-slider__runway) {
height: 50px;
background-color: white;
border-radius: 25px;
transition: all 0.3s;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.06);
}
:deep(.el-slider__bar) {
height: 50px;
background: linear-gradient(90deg,
rgba(64, 158, 255, 0.9),
rgba(103, 194, 58, 0.9)
);
backdrop-filter: blur(4px);
border-radius: 25px;
transition: all 0.3s;
box-shadow: 0 4px 12px rgba(103, 194, 58, 0.25);
}
:deep(.el-slider__button-wrapper) {
width: 50px;
height: 50px;
top: 0;
transition: all 0.3s;
}
:deep(.el-slider__button) {
width: 50px;
height: 50px;
border: none;
background: linear-gradient(135deg, #409eff, #36cfc9, #67c23a);
background-size: 200% 200%;
animation: gradient 3s ease infinite;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 15px rgba(64, 158, 255, 0.4);
transition: all 0.3s;
}
@keyframes gradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
:deep(.el-slider__button:hover) {
transform: scale(1.08);
box-shadow: 0 6px 20px rgba(64, 158, 255, 0.5);
}
:deep(.el-slider__button .el-icon) {
font-size: 24px;
color: #fff;
transition: all 0.3s;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}
@keyframes success-pulse {
0% {
box-shadow: 0 0 0 0 rgba(103, 194, 58, 0.6);
}
70% {
box-shadow: 0 0 0 15px rgba(103, 194, 58, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(103, 194, 58, 0);
}
}
:deep(.el-slider__bar[style*="100%"]) {
background: linear-gradient(90deg, #67c23a, #95de64);
animation: success-pulse 2s infinite;
}
:deep(.slider-dialog) {
border-radius: 20px;
overflow: hidden;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
:deep(.slider-dialog .el-dialog__header) {
margin: 0;
padding: 20px 24px;
background: #f8f9fa;
border-bottom: 1px solid #ebeef5;
position: relative;
overflow: hidden;
}
:deep(.slider-dialog .el-dialog__header::before) {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, #409eff, #67c23a);
}
:deep(.slider-dialog .el-dialog__title) {
font-size: 18px;
font-weight: 600;
color: #303133;
}
:deep(.slider-dialog .el-dialog__body) {
padding: 40px;
}
.shield-icon {
width: 64px;
height: 64px;
background: linear-gradient(135deg, #e6f3ff, #f0f9eb);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #409EFF;
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
</style>