| <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="registerLoading" | |
| style="width: 100%" | |
| @click="handleRegister" | |
| > | |
| <span v-if="!registerLoading">注册</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, computed } from 'vue' | |
| import { useRouter } from 'vue-router' | |
| import { useStore } from 'vuex' | |
| import { User, Lock, Message, UserFilled } from '@element-plus/icons-vue' | |
| export default { | |
| name: 'RegisterView', | |
| components: { | |
| UserFilled | |
| }, | |
| setup() { | |
| const router = useRouter() | |
| const store = useStore() | |
| const registerFormRef = ref() | |
| // 从store获取登录加载状态(注册和登录共用同一个loading状态) | |
| const registerLoading = computed(() => store.getters['auth/loginLoading']) | |
| // 表单数据 | |
| 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' } | |
| ], | |
| 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 | |
| // 调用store的注册action | |
| await store.dispatch('auth/register', { | |
| username: registerForm.username, | |
| email: registerForm.email, | |
| password: registerForm.password | |
| }) | |
| // 注册成功,跳转到首页 | |
| router.push('/home') | |
| } catch (error) { | |
| console.error('注册失败:', error) | |
| // 错误信息已经在store中通过ElMessage显示了 | |
| } | |
| } | |
| return { | |
| registerFormRef, | |
| registerForm, | |
| registerRules, | |
| registerLoading, | |
| handleRegister, | |
| User, | |
| Lock, | |
| Message | |
| } | |
| } | |
| } | |
| </script> |