803 lines
19 KiB
Vue
803 lines
19 KiB
Vue
|
<template>
|
|||
|
<div class="register-container">
|
|||
|
<!-- 背景动画 -->
|
|||
|
<div class="background-animation">
|
|||
|
<div class="floating-shapes">
|
|||
|
<div v-for="i in 10" :key="i" class="shape" :style="getShapeStyle(i)"></div>
|
|||
|
</div>
|
|||
|
<div class="particle-system">
|
|||
|
<div v-for="i in 20" :key="i" class="particle" :style="getParticleStyle(i)"></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="register-content">
|
|||
|
<div class="register-card">
|
|||
|
<!-- 头部 -->
|
|||
|
<div class="header-section">
|
|||
|
<div class="logo-icon">🎓</div>
|
|||
|
<h1 class="title">创建账号</h1>
|
|||
|
<p class="subtitle">加入智慧学习平台,开启学习之旅</p>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 注册表单 -->
|
|||
|
<form @submit.prevent="handleRegister" class="register-form">
|
|||
|
<!-- 基本信息 -->
|
|||
|
<div class="form-section">
|
|||
|
<h3 class="section-title">基本信息</h3>
|
|||
|
|
|||
|
<div class="form-row">
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">姓名</label>
|
|||
|
<div class="input-wrapper">
|
|||
|
<input
|
|||
|
v-model="registerForm.name"
|
|||
|
type="text"
|
|||
|
class="form-input"
|
|||
|
placeholder="请输入真实姓名"
|
|||
|
required
|
|||
|
>
|
|||
|
<div class="input-icon">👤</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">用户名</label>
|
|||
|
<div class="input-wrapper">
|
|||
|
<input
|
|||
|
v-model="registerForm.username"
|
|||
|
type="text"
|
|||
|
class="form-input"
|
|||
|
placeholder="设置用户名"
|
|||
|
required
|
|||
|
>
|
|||
|
<div class="input-icon">🏷️</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">邮箱地址</label>
|
|||
|
<div class="input-wrapper">
|
|||
|
<input
|
|||
|
v-model="registerForm.email"
|
|||
|
type="email"
|
|||
|
class="form-input"
|
|||
|
placeholder="请输入邮箱地址"
|
|||
|
required
|
|||
|
>
|
|||
|
<div class="input-icon">📧</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="form-row">
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">密码</label>
|
|||
|
<div class="input-wrapper">
|
|||
|
<input
|
|||
|
v-model="registerForm.password"
|
|||
|
:type="showPassword ? 'text' : 'password'"
|
|||
|
class="form-input"
|
|||
|
placeholder="设置密码"
|
|||
|
required
|
|||
|
>
|
|||
|
<button
|
|||
|
type="button"
|
|||
|
class="password-toggle"
|
|||
|
@click="showPassword = !showPassword"
|
|||
|
>
|
|||
|
{{ showPassword ? '🙈' : '👁️' }}
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
<div class="password-strength">
|
|||
|
<div class="strength-bar" :class="passwordStrength.class">
|
|||
|
<div class="strength-fill" :style="{ width: passwordStrength.width }"></div>
|
|||
|
</div>
|
|||
|
<span class="strength-text">{{ passwordStrength.text }}</span>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">确认密码</label>
|
|||
|
<div class="input-wrapper">
|
|||
|
<input
|
|||
|
v-model="registerForm.confirmPassword"
|
|||
|
:type="showConfirmPassword ? 'text' : 'password'"
|
|||
|
class="form-input"
|
|||
|
placeholder="再次输入密码"
|
|||
|
required
|
|||
|
>
|
|||
|
<button
|
|||
|
type="button"
|
|||
|
class="password-toggle"
|
|||
|
@click="showConfirmPassword = !showConfirmPassword"
|
|||
|
>
|
|||
|
{{ showConfirmPassword ? '🙈' : '👁️' }}
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
<div v-if="registerForm.confirmPassword && !passwordsMatch" class="error-message">
|
|||
|
密码不匹配
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 个人信息 -->
|
|||
|
<div class="form-section">
|
|||
|
<h3 class="section-title">个人信息</h3>
|
|||
|
|
|||
|
<div class="form-row">
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">身份</label>
|
|||
|
<select v-model="registerForm.role" class="form-select" required>
|
|||
|
<option value="">请选择身份</option>
|
|||
|
<option value="student">学生</option>
|
|||
|
<option value="teacher">教师</option>
|
|||
|
<option value="parent">家长</option>
|
|||
|
</select>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">年级/学科</label>
|
|||
|
<select v-model="registerForm.grade" class="form-select">
|
|||
|
<option value="">请选择</option>
|
|||
|
<option v-for="grade in gradeOptions" :key="grade" :value="grade">{{ grade }}</option>
|
|||
|
</select>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="form-group">
|
|||
|
<label class="form-label">学校/机构</label>
|
|||
|
<div class="input-wrapper">
|
|||
|
<input
|
|||
|
v-model="registerForm.school"
|
|||
|
type="text"
|
|||
|
class="form-input"
|
|||
|
placeholder="请输入学校或机构名称"
|
|||
|
>
|
|||
|
<div class="input-icon">🏫</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 协议同意 -->
|
|||
|
<div class="agreement-section">
|
|||
|
<label class="checkbox-wrapper">
|
|||
|
<input v-model="registerForm.agreeTerms" type="checkbox" class="checkbox" required>
|
|||
|
<span class="checkbox-label">
|
|||
|
我已阅读并同意
|
|||
|
<a href="#" class="link">用户协议</a>
|
|||
|
和
|
|||
|
<a href="#" class="link">隐私政策</a>
|
|||
|
</span>
|
|||
|
</label>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 提交按钮 -->
|
|||
|
<button type="submit" class="register-btn" :disabled="!canSubmit || isLoading">
|
|||
|
<span v-if="!isLoading">创建账号</span>
|
|||
|
<span v-else class="loading-spinner">🔄</span>
|
|||
|
</button>
|
|||
|
</form>
|
|||
|
|
|||
|
<!-- 登录链接 -->
|
|||
|
<div class="login-section">
|
|||
|
<span class="login-text">已有账号?</span>
|
|||
|
<router-link to="/login" class="login-link">立即登录</router-link>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 优势展示 -->
|
|||
|
<div class="benefits-section">
|
|||
|
<h3 class="benefits-title">加入我们的优势</h3>
|
|||
|
<div class="benefits-grid">
|
|||
|
<div class="benefit-card">
|
|||
|
<div class="benefit-icon">🚀</div>
|
|||
|
<h4 class="benefit-title">快速上手</h4>
|
|||
|
<p class="benefit-desc">简单易用的界面设计,5分钟即可熟练操作</p>
|
|||
|
</div>
|
|||
|
<div class="benefit-card">
|
|||
|
<div class="benefit-icon">📈</div>
|
|||
|
<h4 class="benefit-title">学习追踪</h4>
|
|||
|
<p class="benefit-desc">实时跟踪学习进度,科学分析学习效果</p>
|
|||
|
</div>
|
|||
|
<div class="benefit-card">
|
|||
|
<div class="benefit-icon">🎯</div>
|
|||
|
<h4 class="benefit-title">个性化</h4>
|
|||
|
<p class="benefit-desc">AI智能推荐,为每个学生定制专属学习路径</p>
|
|||
|
</div>
|
|||
|
<div class="benefit-card">
|
|||
|
<div class="benefit-icon">🤝</div>
|
|||
|
<h4 class="benefit-title">协作学习</h4>
|
|||
|
<p class="benefit-desc">师生互动,同学协作,营造良好学习氛围</p>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script setup lang="ts">
|
|||
|
import { ref, reactive, computed } from 'vue'
|
|||
|
import { useRouter } from 'vue-router'
|
|||
|
|
|||
|
const router = useRouter()
|
|||
|
|
|||
|
// 表单数据
|
|||
|
const registerForm = reactive({
|
|||
|
name: '',
|
|||
|
username: '',
|
|||
|
email: '',
|
|||
|
password: '',
|
|||
|
confirmPassword: '',
|
|||
|
role: '',
|
|||
|
grade: '',
|
|||
|
school: '',
|
|||
|
agreeTerms: false
|
|||
|
})
|
|||
|
|
|||
|
const showPassword = ref(false)
|
|||
|
const showConfirmPassword = ref(false)
|
|||
|
const isLoading = ref(false)
|
|||
|
|
|||
|
// 年级选项
|
|||
|
const gradeOptions = computed(() => {
|
|||
|
if (registerForm.role === 'student') {
|
|||
|
return ['小学一年级', '小学二年级', '小学三年级', '小学四年级', '小学五年级', '小学六年级',
|
|||
|
'初中一年级', '初中二年级', '初中三年级', '高中一年级', '高中二年级', '高中三年级']
|
|||
|
} else if (registerForm.role === 'teacher') {
|
|||
|
return ['语文', '数学', '英语', '物理', '化学', '生物', '历史', '地理', '政治', '体育', '音乐', '美术']
|
|||
|
} else if (registerForm.role === 'parent') {
|
|||
|
return ['小学阶段', '初中阶段', '高中阶段']
|
|||
|
}
|
|||
|
return []
|
|||
|
})
|
|||
|
|
|||
|
// 密码强度检测
|
|||
|
const passwordStrength = computed(() => {
|
|||
|
const password = registerForm.password
|
|||
|
if (!password) return { class: '', width: '0%', text: '' }
|
|||
|
|
|||
|
let score = 0
|
|||
|
if (password.length >= 8) score++
|
|||
|
if (/[a-z]/.test(password)) score++
|
|||
|
if (/[A-Z]/.test(password)) score++
|
|||
|
if (/[0-9]/.test(password)) score++
|
|||
|
if (/[^a-zA-Z0-9]/.test(password)) score++
|
|||
|
|
|||
|
if (score <= 2) return { class: 'weak', width: '33%', text: '弱' }
|
|||
|
if (score <= 3) return { class: 'medium', width: '66%', text: '中等' }
|
|||
|
return { class: 'strong', width: '100%', text: '强' }
|
|||
|
})
|
|||
|
|
|||
|
// 密码匹配检测
|
|||
|
const passwordsMatch = computed(() => {
|
|||
|
return registerForm.password === registerForm.confirmPassword
|
|||
|
})
|
|||
|
|
|||
|
// 是否可以提交
|
|||
|
const canSubmit = computed(() => {
|
|||
|
return registerForm.name &&
|
|||
|
registerForm.username &&
|
|||
|
registerForm.email &&
|
|||
|
registerForm.password &&
|
|||
|
registerForm.confirmPassword &&
|
|||
|
passwordsMatch.value &&
|
|||
|
registerForm.role &&
|
|||
|
registerForm.agreeTerms
|
|||
|
})
|
|||
|
|
|||
|
// 注册处理
|
|||
|
const handleRegister = async () => {
|
|||
|
if (!canSubmit.value) return
|
|||
|
|
|||
|
isLoading.value = true
|
|||
|
|
|||
|
try {
|
|||
|
// 模拟注册API调用
|
|||
|
await new Promise(resolve => setTimeout(resolve, 2000))
|
|||
|
|
|||
|
// 注册成功,跳转到登录页
|
|||
|
router.push('/login')
|
|||
|
} catch (error) {
|
|||
|
console.error('注册失败:', error)
|
|||
|
} finally {
|
|||
|
isLoading.value = false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 浮动形状样式
|
|||
|
const getShapeStyle = (index: number) => {
|
|||
|
const shapes = ['🌟', '⭐', '✨', '💫', '🔥', '💎', '🎯', '🚀', '📚', '🎓']
|
|||
|
const size = Math.random() * 25 + 15
|
|||
|
const left = Math.random() * 100
|
|||
|
const top = Math.random() * 100
|
|||
|
const animationDelay = Math.random() * 8
|
|||
|
const animationDuration = Math.random() * 4 + 6
|
|||
|
|
|||
|
return {
|
|||
|
fontSize: `${size}px`,
|
|||
|
left: `${left}%`,
|
|||
|
top: `${top}%`,
|
|||
|
animationDelay: `${animationDelay}s`,
|
|||
|
animationDuration: `${animationDuration}s`,
|
|||
|
'--content': `'${shapes[index % shapes.length]}'`
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 粒子样式
|
|||
|
const getParticleStyle = (index: number) => {
|
|||
|
const size = Math.random() * 4 + 2
|
|||
|
const left = Math.random() * 100
|
|||
|
const top = Math.random() * 100
|
|||
|
const animationDelay = Math.random() * 5
|
|||
|
const animationDuration = Math.random() * 3 + 3
|
|||
|
|
|||
|
return {
|
|||
|
width: `${size}px`,
|
|||
|
height: `${size}px`,
|
|||
|
left: `${left}%`,
|
|||
|
top: `${top}%`,
|
|||
|
animationDelay: `${animationDelay}s`,
|
|||
|
animationDuration: `${animationDuration}s`
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped>
|
|||
|
.register-container {
|
|||
|
min-height: 100vh;
|
|||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|||
|
position: relative;
|
|||
|
overflow: hidden;
|
|||
|
padding: 2rem;
|
|||
|
}
|
|||
|
|
|||
|
.background-animation {
|
|||
|
position: absolute;
|
|||
|
top: 0;
|
|||
|
left: 0;
|
|||
|
width: 100%;
|
|||
|
height: 100%;
|
|||
|
pointer-events: none;
|
|||
|
z-index: 1;
|
|||
|
}
|
|||
|
|
|||
|
.floating-shapes {
|
|||
|
position: absolute;
|
|||
|
width: 100%;
|
|||
|
height: 100%;
|
|||
|
}
|
|||
|
|
|||
|
.shape {
|
|||
|
position: absolute;
|
|||
|
opacity: 0.08;
|
|||
|
animation: floatUp linear infinite;
|
|||
|
}
|
|||
|
|
|||
|
.shape::before {
|
|||
|
content: var(--content);
|
|||
|
}
|
|||
|
|
|||
|
@keyframes floatUp {
|
|||
|
0% {
|
|||
|
transform: translateY(100vh) rotate(0deg);
|
|||
|
opacity: 0;
|
|||
|
}
|
|||
|
10% {
|
|||
|
opacity: 0.08;
|
|||
|
}
|
|||
|
90% {
|
|||
|
opacity: 0.08;
|
|||
|
}
|
|||
|
100% {
|
|||
|
transform: translateY(-100px) rotate(360deg);
|
|||
|
opacity: 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.particle-system {
|
|||
|
position: absolute;
|
|||
|
width: 100%;
|
|||
|
height: 100%;
|
|||
|
}
|
|||
|
|
|||
|
.particle {
|
|||
|
position: absolute;
|
|||
|
background: rgba(255, 255, 255, 0.3);
|
|||
|
border-radius: 50%;
|
|||
|
animation: particleFloat linear infinite;
|
|||
|
}
|
|||
|
|
|||
|
@keyframes particleFloat {
|
|||
|
0% {
|
|||
|
transform: translateY(100vh);
|
|||
|
opacity: 0;
|
|||
|
}
|
|||
|
10% {
|
|||
|
opacity: 0.3;
|
|||
|
}
|
|||
|
90% {
|
|||
|
opacity: 0.3;
|
|||
|
}
|
|||
|
100% {
|
|||
|
transform: translateY(-50px);
|
|||
|
opacity: 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
.register-content {
|
|||
|
position: relative;
|
|||
|
z-index: 2;
|
|||
|
display: grid;
|
|||
|
grid-template-columns: 1fr 400px;
|
|||
|
gap: 3rem;
|
|||
|
max-width: 1200px;
|
|||
|
margin: 0 auto;
|
|||
|
}
|
|||
|
|
|||
|
.register-card {
|
|||
|
background: rgba(255, 255, 255, 0.1);
|
|||
|
backdrop-filter: blur(20px);
|
|||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|||
|
border-radius: 24px;
|
|||
|
padding: 2.5rem;
|
|||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|||
|
}
|
|||
|
|
|||
|
.header-section {
|
|||
|
text-align: center;
|
|||
|
margin-bottom: 2rem;
|
|||
|
}
|
|||
|
|
|||
|
.logo-icon {
|
|||
|
font-size: 3rem;
|
|||
|
margin-bottom: 1rem;
|
|||
|
}
|
|||
|
|
|||
|
.title {
|
|||
|
font-size: 2.2rem;
|
|||
|
font-weight: 700;
|
|||
|
color: white;
|
|||
|
margin: 0 0 0.5rem 0;
|
|||
|
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
|||
|
}
|
|||
|
|
|||
|
.subtitle {
|
|||
|
font-size: 1rem;
|
|||
|
color: rgba(255, 255, 255, 0.8);
|
|||
|
margin: 0;
|
|||
|
}
|
|||
|
|
|||
|
.register-form {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
gap: 2rem;
|
|||
|
}
|
|||
|
|
|||
|
.form-section {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
gap: 1.5rem;
|
|||
|
}
|
|||
|
|
|||
|
.section-title {
|
|||
|
font-size: 1.2rem;
|
|||
|
font-weight: 600;
|
|||
|
color: white;
|
|||
|
margin: 0;
|
|||
|
padding-bottom: 0.5rem;
|
|||
|
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
|
|||
|
}
|
|||
|
|
|||
|
.form-row {
|
|||
|
display: grid;
|
|||
|
grid-template-columns: 1fr 1fr;
|
|||
|
gap: 1rem;
|
|||
|
}
|
|||
|
|
|||
|
.form-group {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
gap: 0.5rem;
|
|||
|
}
|
|||
|
|
|||
|
.form-label {
|
|||
|
font-size: 0.9rem;
|
|||
|
font-weight: 600;
|
|||
|
color: rgba(255, 255, 255, 0.9);
|
|||
|
}
|
|||
|
|
|||
|
.input-wrapper {
|
|||
|
position: relative;
|
|||
|
}
|
|||
|
|
|||
|
.form-input {
|
|||
|
width: 100%;
|
|||
|
padding: 0.8rem 2.5rem 0.8rem 1rem;
|
|||
|
border: 2px solid rgba(255, 255, 255, 0.2);
|
|||
|
border-radius: 12px;
|
|||
|
background: rgba(255, 255, 255, 0.1);
|
|||
|
color: white;
|
|||
|
font-size: 0.9rem;
|
|||
|
transition: all 0.3s ease;
|
|||
|
box-sizing: border-box;
|
|||
|
}
|
|||
|
|
|||
|
.form-input::placeholder {
|
|||
|
color: rgba(255, 255, 255, 0.5);
|
|||
|
}
|
|||
|
|
|||
|
.form-input:focus {
|
|||
|
outline: none;
|
|||
|
border-color: rgba(79, 172, 254, 0.8);
|
|||
|
background: rgba(255, 255, 255, 0.15);
|
|||
|
box-shadow: 0 0 15px rgba(79, 172, 254, 0.3);
|
|||
|
}
|
|||
|
|
|||
|
.form-select {
|
|||
|
width: 100%;
|
|||
|
padding: 0.8rem 1rem;
|
|||
|
border: 2px solid rgba(255, 255, 255, 0.2);
|
|||
|
border-radius: 12px;
|
|||
|
background: rgba(255, 255, 255, 0.1);
|
|||
|
color: white;
|
|||
|
font-size: 0.9rem;
|
|||
|
transition: all 0.3s ease;
|
|||
|
box-sizing: border-box;
|
|||
|
}
|
|||
|
|
|||
|
.form-select:focus {
|
|||
|
outline: none;
|
|||
|
border-color: rgba(79, 172, 254, 0.8);
|
|||
|
background: rgba(255, 255, 255, 0.15);
|
|||
|
}
|
|||
|
|
|||
|
.form-select option {
|
|||
|
background: #333;
|
|||
|
color: white;
|
|||
|
}
|
|||
|
|
|||
|
.input-icon {
|
|||
|
position: absolute;
|
|||
|
right: 1rem;
|
|||
|
top: 50%;
|
|||
|
transform: translateY(-50%);
|
|||
|
font-size: 1rem;
|
|||
|
opacity: 0.6;
|
|||
|
}
|
|||
|
|
|||
|
.password-toggle {
|
|||
|
position: absolute;
|
|||
|
right: 1rem;
|
|||
|
top: 50%;
|
|||
|
transform: translateY(-50%);
|
|||
|
background: none;
|
|||
|
border: none;
|
|||
|
font-size: 1rem;
|
|||
|
cursor: pointer;
|
|||
|
opacity: 0.6;
|
|||
|
transition: opacity 0.3s ease;
|
|||
|
}
|
|||
|
|
|||
|
.password-toggle:hover {
|
|||
|
opacity: 1;
|
|||
|
}
|
|||
|
|
|||
|
.password-strength {
|
|||
|
display: flex;
|
|||
|
align-items: center;
|
|||
|
gap: 0.5rem;
|
|||
|
margin-top: 0.5rem;
|
|||
|
}
|
|||
|
|
|||
|
.strength-bar {
|
|||
|
flex: 1;
|
|||
|
height: 4px;
|
|||
|
background: rgba(255, 255, 255, 0.2);
|
|||
|
border-radius: 2px;
|
|||
|
overflow: hidden;
|
|||
|
}
|
|||
|
|
|||
|
.strength-fill {
|
|||
|
height: 100%;
|
|||
|
transition: width 0.3s ease;
|
|||
|
}
|
|||
|
|
|||
|
.strength-bar.weak .strength-fill {
|
|||
|
background: #ff4757;
|
|||
|
}
|
|||
|
|
|||
|
.strength-bar.medium .strength-fill {
|
|||
|
background: #ffa502;
|
|||
|
}
|
|||
|
|
|||
|
.strength-bar.strong .strength-fill {
|
|||
|
background: #2ed573;
|
|||
|
}
|
|||
|
|
|||
|
.strength-text {
|
|||
|
font-size: 0.8rem;
|
|||
|
color: rgba(255, 255, 255, 0.7);
|
|||
|
min-width: 30px;
|
|||
|
}
|
|||
|
|
|||
|
.error-message {
|
|||
|
font-size: 0.8rem;
|
|||
|
color: #ff4757;
|
|||
|
margin-top: 0.25rem;
|
|||
|
}
|
|||
|
|
|||
|
.agreement-section {
|
|||
|
padding: 1rem 0;
|
|||
|
}
|
|||
|
|
|||
|
.checkbox-wrapper {
|
|||
|
display: flex;
|
|||
|
align-items: flex-start;
|
|||
|
gap: 0.5rem;
|
|||
|
cursor: pointer;
|
|||
|
}
|
|||
|
|
|||
|
.checkbox {
|
|||
|
width: 18px;
|
|||
|
height: 18px;
|
|||
|
margin-top: 2px;
|
|||
|
accent-color: #4facfe;
|
|||
|
}
|
|||
|
|
|||
|
.checkbox-label {
|
|||
|
font-size: 0.9rem;
|
|||
|
color: rgba(255, 255, 255, 0.8);
|
|||
|
line-height: 1.4;
|
|||
|
}
|
|||
|
|
|||
|
.link {
|
|||
|
color: #4facfe;
|
|||
|
text-decoration: none;
|
|||
|
transition: color 0.3s ease;
|
|||
|
}
|
|||
|
|
|||
|
.link:hover {
|
|||
|
color: #00f2fe;
|
|||
|
}
|
|||
|
|
|||
|
.register-btn {
|
|||
|
width: 100%;
|
|||
|
padding: 1rem;
|
|||
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
|||
|
border: none;
|
|||
|
border-radius: 12px;
|
|||
|
color: white;
|
|||
|
font-size: 1.1rem;
|
|||
|
font-weight: 600;
|
|||
|
cursor: pointer;
|
|||
|
transition: all 0.3s ease;
|
|||
|
position: relative;
|
|||
|
overflow: hidden;
|
|||
|
}
|
|||
|
|
|||
|
.register-btn:hover:not(:disabled) {
|
|||
|
transform: translateY(-2px);
|
|||
|
box-shadow: 0 10px 25px rgba(79, 172, 254, 0.4);
|
|||
|
}
|
|||
|
|
|||
|
.register-btn:disabled {
|
|||
|
opacity: 0.5;
|
|||
|
cursor: not-allowed;
|
|||
|
}
|
|||
|
|
|||
|
.loading-spinner {
|
|||
|
animation: spin 1s linear infinite;
|
|||
|
}
|
|||
|
|
|||
|
@keyframes spin {
|
|||
|
from { transform: rotate(0deg); }
|
|||
|
to { transform: rotate(360deg); }
|
|||
|
}
|
|||
|
|
|||
|
.login-section {
|
|||
|
text-align: center;
|
|||
|
margin-top: 1.5rem;
|
|||
|
}
|
|||
|
|
|||
|
.login-text {
|
|||
|
color: rgba(255, 255, 255, 0.7);
|
|||
|
font-size: 0.9rem;
|
|||
|
}
|
|||
|
|
|||
|
.login-link {
|
|||
|
color: #4facfe;
|
|||
|
text-decoration: none;
|
|||
|
font-weight: 600;
|
|||
|
margin-left: 0.5rem;
|
|||
|
transition: color 0.3s ease;
|
|||
|
}
|
|||
|
|
|||
|
.login-link:hover {
|
|||
|
color: #00f2fe;
|
|||
|
}
|
|||
|
|
|||
|
.benefits-section {
|
|||
|
display: flex;
|
|||
|
flex-direction: column;
|
|||
|
justify-content: center;
|
|||
|
}
|
|||
|
|
|||
|
.benefits-title {
|
|||
|
font-size: 1.8rem;
|
|||
|
font-weight: 700;
|
|||
|
color: white;
|
|||
|
margin-bottom: 2rem;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
|
|||
|
.benefits-grid {
|
|||
|
display: grid;
|
|||
|
grid-template-columns: 1fr 1fr;
|
|||
|
gap: 1.5rem;
|
|||
|
}
|
|||
|
|
|||
|
.benefit-card {
|
|||
|
background: rgba(255, 255, 255, 0.1);
|
|||
|
backdrop-filter: blur(10px);
|
|||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|||
|
border-radius: 16px;
|
|||
|
padding: 1.5rem;
|
|||
|
text-align: center;
|
|||
|
transition: all 0.3s ease;
|
|||
|
}
|
|||
|
|
|||
|
.benefit-card:hover {
|
|||
|
transform: translateY(-5px);
|
|||
|
background: rgba(255, 255, 255, 0.15);
|
|||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
|||
|
}
|
|||
|
|
|||
|
.benefit-icon {
|
|||
|
font-size: 2.5rem;
|
|||
|
margin-bottom: 1rem;
|
|||
|
}
|
|||
|
|
|||
|
.benefit-title {
|
|||
|
font-size: 1.1rem;
|
|||
|
font-weight: 600;
|
|||
|
color: white;
|
|||
|
margin: 0 0 0.5rem 0;
|
|||
|
}
|
|||
|
|
|||
|
.benefit-desc {
|
|||
|
font-size: 0.85rem;
|
|||
|
color: rgba(255, 255, 255, 0.7);
|
|||
|
margin: 0;
|
|||
|
line-height: 1.4;
|
|||
|
}
|
|||
|
|
|||
|
@media (max-width: 1024px) {
|
|||
|
.register-content {
|
|||
|
grid-template-columns: 1fr;
|
|||
|
gap: 2rem;
|
|||
|
}
|
|||
|
|
|||
|
.benefits-grid {
|
|||
|
grid-template-columns: 1fr;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@media (max-width: 768px) {
|
|||
|
.register-card {
|
|||
|
padding: 2rem;
|
|||
|
}
|
|||
|
|
|||
|
.form-row {
|
|||
|
grid-template-columns: 1fr;
|
|||
|
}
|
|||
|
|
|||
|
.title {
|
|||
|
font-size: 1.8rem;
|
|||
|
}
|
|||
|
|
|||
|
.benefits-title {
|
|||
|
font-size: 1.5rem;
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|