blob: ad3461d496d3e1ad8302499199fa7f4cd7a12f66 [file] [log] [blame]
<template>
<div class="register-page">
<!-- 背景装饰 -->
<div class="bg-decoration">
<div class="shape shape-1"></div>
<div class="shape shape-2"></div>
<div class="shape shape-3"></div>
</div>
<!-- 注册表单容器 -->
<div class="register-container">
<div class="register-card">
<!-- 头部信息 -->
<div class="register-header">
<div class="logo">
<el-icon size="48" color="#a8edea"><UserFilled /></el-icon>
</div>
<h1 class="title">加入 PT Tracker</h1>
<p class="subtitle">开始你的资源分享之旅</p>
</div>
<!-- 注册表单 -->
<el-form
ref="registerFormRef"
:model="registerForm"
:rules="registerRules"
class="register-form"
size="large"
>
<el-form-item prop="username">
<el-input
v-model="registerForm.username"
placeholder="请输入用户名"
clearable
:prefix-icon="User"
/>
</el-form-item>
<el-form-item prop="email">
<el-input
v-model="registerForm.email"
placeholder="请输入邮箱地址"
clearable
:prefix-icon="Message"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="registerForm.password"
type="password"
placeholder="请输入密码"
show-password
:prefix-icon="Lock"
/>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input
v-model="registerForm.confirmPassword"
type="password"
placeholder="请确认密码"
show-password
:prefix-icon="Lock"
/>
</el-form-item>
<el-form-item prop="agreement">
<el-checkbox v-model="registerForm.agreement">
我已阅读并同意
<el-link type="primary" :underline="false">《用户协议》</el-link>
<el-link type="primary" :underline="false">《隐私政策》</el-link>
</el-checkbox>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:loading="loading"
style="width: 100%"
@click="handleRegister"
>
<span v-if="!loading">注册</span>
<span v-else>注册中...</span>
</el-button>
</el-form-item>
</el-form>
<!-- 底部链接 -->
<div class="register-footer">
<span class="footer-text">已有账号?</span>
<el-link
type="primary"
:underline="false"
@click="$router.push('/login')"
>
立即登录
</el-link>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { User, Lock, Message, UserFilled } from '@element-plus/icons-vue'
export default {
name: 'RegisterView',
components: {
UserFilled
},
setup() {
const router = useRouter()
const registerFormRef = ref()
const loading = ref(false)
// 表单数据
const registerForm = reactive({
username: '',
email: '',
password: '',
confirmPassword: '',
agreement: false
})
// 自定义验证规则
const validateConfirmPassword = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== registerForm.password) {
callback(new Error('两次输入密码不一致'))
} else {
callback()
}
}
const validateAgreement = (rule, value, callback) => {
if (!value) {
callback(new Error('请先同意用户协议和隐私政策'))
} else {
callback()
}
}
// 验证规则
const registerRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 20, message: '用户名长度在3到20个字符', trigger: 'blur' },
{ pattern: /^[a-zA-Z0-9_]+$/, message: '用户名只能包含字母、数字和下划线', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 20, message: '密码长度在6到20个字符', trigger: 'blur' },
{ pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]/, message: '密码必须包含大小写字母和数字', trigger: 'blur' }
],
confirmPassword: [
{ required: true, validator: validateConfirmPassword, trigger: 'blur' }
],
agreement: [
{ required: true, validator: validateAgreement, trigger: 'change' }
]
}
// 注册处理
const handleRegister = async () => {
try {
// 表单验证
const valid = await registerFormRef.value.validate()
if (!valid) return
loading.value = true
// 模拟注册API请求
await new Promise(resolve => setTimeout(resolve, 1500))
// 模拟注册成功
ElMessage.success('注册成功!请登录您的账号')
// 跳转到登录页
router.push('/login')
} catch (error) {
console.error('注册失败:', error)
ElMessage.error('注册失败,请稍后重试')
} finally {
loading.value = false
}
}
return {
registerFormRef,
registerForm,
registerRules,
loading,
handleRegister,
User,
Lock,
Message
}
}
}
</script>
<style lang="scss" scoped>
.register-page {
min-height: 100vh;
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
// 背景装饰(与登录页相同的动画效果)
.bg-decoration {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 1;
.shape {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.15);
animation: float 8s ease-in-out infinite;
&.shape-1 {
width: 180px;
height: 180px;
top: 15%;
left: 15%;
animation-delay: 0s;
}
&.shape-2 {
width: 120px;
height: 120px;
top: 50%;
right: 15%;
animation-delay: -3s;
}
&.shape-3 {
width: 90px;
height: 90px;
bottom: 25%;
left: 25%;
animation-delay: -6s;
}
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px) rotate(0deg);
}
50% {
transform: translateY(-15px) rotate(180deg);
}
}
// 注册容器
.register-container {
position: relative;
z-index: 10;
width: 100%;
max-width: 420px;
}
.register-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
.register-header {
text-align: center;
margin-bottom: 32px;
.logo {
margin-bottom: 16px;
}
.title {
font-size: 32px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 8px;
letter-spacing: -0.5px;
}
.subtitle {
font-size: 15px;
color: #7f8c8d;
margin: 0;
font-weight: 400;
}
}
.register-form {
.el-form-item {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.el-checkbox {
:deep(.el-checkbox__label) {
font-size: 14px;
color: #606266;
line-height: 1.5;
}
}
.el-button {
font-size: 16px;
font-weight: 500;
height: 48px;
border-radius: 8px;
}
}
.register-footer {
text-align: center;
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid #ebeef5;
.footer-text {
color: #909399;
font-size: 14px;
margin-right: 8px;
}
.el-link {
font-size: 14px;
font-weight: 500;
}
}
}
// 响应式设计
@media (max-width: 768px) {
.register-page {
padding: 16px;
}
.register-card {
padding: 32px 24px;
.register-header .title {
font-size: 28px;
}
}
}
</style>