Files
gamegroup2/frontend/src/views/Register.vue
T
2026-04-17 17:37:15 +08:00

327 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- src/views/Register.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import PasswordInput from '@/components/common/PasswordInput.vue'
const router = useRouter()
const userStore = useUserStore()
const username = ref('')
const email = ref('')
const password = ref('')
const passwordConfirm = ref('')
const loading = ref(false)
async function handleRegister() {
if (!username.value || !email.value || !password.value) {
ElMessage.warning('请填写所有必填项')
return
}
if (password.value !== passwordConfirm.value) {
ElMessage.warning('两次输入的密码不一致')
return
}
if (password.value.length < 6) {
ElMessage.warning('密码长度至少为 6 位')
return
}
try {
loading.value = true
await userStore.register({
username: username.value,
email: email.value,
password: password.value,
passwordConfirm: passwordConfirm.value
})
ElMessage.success('注册成功')
router.push({ name: 'Home' })
} catch (error: any) {
ElMessage.error(error.message || '注册失败')
} finally {
loading.value = false
}
}
function goToLogin() {
router.push({ name: 'Login' })
}
</script>
<template>
<div class="register-page">
<!-- CSS 星星背景 -->
<div class="stars" aria-hidden="true"></div>
<div class="stars stars--sm" aria-hidden="true"></div>
<div class="register-card">
<div class="card-header">
<h1 class="brand">
<span class="brand-text">Game Group</span>
</h1>
<p class="subtitle">创建你的账号</p>
</div>
<form class="register-form" @submit.prevent="handleRegister">
<div class="form-group">
<label for="username">用户名</label>
<input
id="username"
v-model="username"
type="text"
placeholder="请输入用户名"
required
/>
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input
id="email"
v-model="email"
type="email"
placeholder="请输入邮箱"
required
/>
</div>
<div class="form-group">
<label for="password">密码</label>
<PasswordInput
id="password"
v-model="password"
placeholder="请输入密码(至少6位)"
required
/>
</div>
<div class="form-group">
<label for="passwordConfirm">确认密码</label>
<PasswordInput
id="passwordConfirm"
v-model="passwordConfirm"
placeholder="请再次输入密码"
required
/>
</div>
<button type="submit" class="submit-btn" :disabled="loading">
<span v-if="loading" class="btn-loader"></span>
{{ loading ? '注册中...' : '注册' }}
</button>
</form>
<div class="footer-links">
<span>已有账号</span>
<a @click="goToLogin">立即登录</a>
</div>
</div>
</div>
</template>
<style scoped>
/* ── 深空背景 ── */
.register-page {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 24px;
background: linear-gradient(160deg, #0f172a 0%, #1e1b4b 50%, #0f172a 100%);
overflow: hidden;
}
/* ── CSS 星星 ── */
.stars {
position: fixed;
inset: 0;
background-image:
radial-gradient(1px 1px at 10% 20%, rgba(255,255,255,0.8) 50%, transparent 100%),
radial-gradient(1px 1px at 30% 65%, rgba(255,255,255,0.6) 50%, transparent 100%),
radial-gradient(1.5px 1.5px at 50% 10%, rgba(255,255,255,0.9) 50%, transparent 100%),
radial-gradient(1px 1px at 70% 40%, rgba(255,255,255,0.5) 50%, transparent 100%),
radial-gradient(1px 1px at 85% 75%, rgba(255,255,255,0.7) 50%, transparent 100%),
radial-gradient(1.5px 1.5px at 15% 80%, rgba(255,255,255,0.6) 50%, transparent 100%),
radial-gradient(1px 1px at 55% 90%, rgba(255,255,255,0.5) 50%, transparent 100%),
radial-gradient(1px 1px at 92% 15%, rgba(255,255,255,0.7) 50%, transparent 100%),
radial-gradient(1.2px 1.2px at 40% 45%, rgba(255,255,255,0.6) 50%, transparent 100%),
radial-gradient(1px 1px at 25% 35%, rgba(255,255,255,0.4) 50%, transparent 100%);
animation: twinkle 4s ease-in-out infinite alternate;
pointer-events: none;
}
.stars--sm {
background-image:
radial-gradient(0.8px 0.8px at 5% 50%, rgba(255,255,255,0.4) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 20% 10%, rgba(255,255,255,0.3) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 45% 70%, rgba(255,255,255,0.35) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 60% 25%, rgba(255,255,255,0.3) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 78% 85%, rgba(255,255,255,0.4) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 95% 55%, rgba(255,255,255,0.3) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 35% 95%, rgba(255,255,255,0.35) 50%, transparent 100%),
radial-gradient(0.8px 0.8px at 65% 5%, rgba(255,255,255,0.3) 50%, transparent 100%);
animation: twinkle 6s ease-in-out 1s infinite alternate;
}
@keyframes twinkle {
0% { opacity: 0.6; }
100% { opacity: 1; }
}
/* ── 毛玻璃卡片 ── */
.register-card {
position: relative;
z-index: 1;
width: 100%;
max-width: 420px;
padding: 44px 40px 40px;
background: rgba(30, 41, 59, 0.55);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(99, 102, 241, 0.2);
border-radius: var(--gg-radius-xl);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
/* ── 头部品牌 ── */
.card-header {
text-align: center;
margin-bottom: 32px;
}
.brand {
margin: 0 0 8px;
}
.brand-text {
font-size: 32px;
font-weight: 800;
letter-spacing: -0.5px;
background: var(--gg-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.subtitle {
margin: 0;
font-size: 15px;
color: var(--gg-text-secondary);
font-weight: 400;
}
/* ── 表单 ── */
.register-form {
display: flex;
flex-direction: column;
gap: 18px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-group label {
font-size: 13px;
font-weight: 500;
color: var(--gg-text-secondary);
letter-spacing: 0.02em;
}
.form-group input {
padding: 12px 16px;
background: var(--gg-bg);
border: 1px solid var(--gg-border);
border-radius: var(--gg-radius-sm);
color: var(--gg-text);
font-size: 14px;
transition: border-color 0.25s, box-shadow 0.25s;
}
.form-group input::placeholder {
color: var(--gg-text-muted);
}
.form-group input:focus {
outline: none;
border-color: var(--gg-primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.25);
}
/* ── 提交按钮 ── */
.submit-btn {
position: relative;
padding: 14px;
margin-top: 4px;
border: none;
border-radius: var(--gg-radius-sm);
background: var(--gg-gradient);
color: #fff;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: box-shadow 0.3s, transform 0.15s;
}
.submit-btn:hover:not(:disabled) {
box-shadow: 0 0 24px rgba(99, 102, 241, 0.45), 0 0 8px rgba(168, 85, 247, 0.3);
transform: translateY(-1px);
}
.submit-btn:active:not(:disabled) {
transform: translateY(0);
}
.submit-btn:disabled {
opacity: 0.55;
cursor: not-allowed;
}
.btn-loader {
display: inline-block;
width: 14px;
height: 14px;
margin-right: 8px;
border: 2px solid rgba(255,255,255,0.3);
border-top-color: #fff;
border-radius: 50%;
animation: spin 0.6s linear infinite;
vertical-align: middle;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* ── 底部链接 ── */
.footer-links {
margin-top: 24px;
text-align: center;
font-size: 14px;
color: var(--gg-text-muted);
}
.footer-links a {
color: var(--gg-primary-light);
cursor: pointer;
font-weight: 500;
margin-left: 4px;
transition: color 0.2s;
}
.footer-links a:hover {
color: var(--gg-accent-light);
}
</style>