446 lines
9.7 KiB
Vue
446 lines
9.7 KiB
Vue
<template>
|
||
<div class="auth-page">
|
||
<div class="auth-shell">
|
||
<section class="auth-showcase">
|
||
<div class="showcase-copy">
|
||
<p class="eyebrow">
|
||
New Account
|
||
</p>
|
||
<h1>创建账号,进入你的创作与互动空间</h1>
|
||
<p class="lead">
|
||
注册成功后可以保存观看记录、创建收藏夹、进入消息中心,并继续使用上传、审核与播放联调后的完整链路。
|
||
</p>
|
||
</div>
|
||
|
||
<div class="showcase-board">
|
||
<div class="board-card">
|
||
<strong>保存记录</strong>
|
||
<span>同步个人资料、播放历史、收藏夹和消息通知。</span>
|
||
</div>
|
||
<div class="board-card">
|
||
<strong>参与互动</strong>
|
||
<span>评论、回复、关注、私信和通知都依赖注册后的个人身份。</span>
|
||
</div>
|
||
<div class="board-card">
|
||
<strong>开始创作</strong>
|
||
<span>上传视频并进入个人主页,逐步搭建自己的创作者空间。</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="auth-panel">
|
||
<div class="panel-top">
|
||
<button
|
||
class="back-home"
|
||
@click="router.push('/')"
|
||
>
|
||
返回首页
|
||
</button>
|
||
<div class="brand-lockup">
|
||
<h1 class="logo">
|
||
HAOVP
|
||
</h1>
|
||
<p class="slogan">
|
||
创建账号,保存你的观看与创作记录
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<van-form @submit="handleRegister">
|
||
<div class="captcha-banner">
|
||
<div>
|
||
<strong>注册验证</strong>
|
||
<span>当前注册同样要求验证码,点击图片可以刷新。</span>
|
||
</div>
|
||
<van-image
|
||
:src="captchaImage"
|
||
fit="contain"
|
||
class="captcha-image"
|
||
@click="refreshCaptcha"
|
||
/>
|
||
</div>
|
||
|
||
<van-cell-group inset>
|
||
<van-field
|
||
v-model="form.username"
|
||
name="username"
|
||
label="用户名"
|
||
placeholder="请输入用户名"
|
||
:rules="[{ required: true, message: '请输入用户名' }]"
|
||
/>
|
||
<van-field
|
||
v-model="form.email"
|
||
name="email"
|
||
label="邮箱"
|
||
placeholder="请输入邮箱"
|
||
:rules="[{ required: true, message: '请输入邮箱' }]"
|
||
/>
|
||
<van-field
|
||
v-model="form.phone"
|
||
name="phone"
|
||
label="手机号"
|
||
placeholder="请输入手机号"
|
||
/>
|
||
<van-field
|
||
v-model="form.password"
|
||
type="password"
|
||
name="password"
|
||
label="密码"
|
||
placeholder="请输入密码"
|
||
:rules="[{ required: true, message: '请输入密码' }, { pattern: /^.{6,}$/, message: '密码至少6位' }]"
|
||
/>
|
||
<van-field
|
||
v-model="form.confirmPassword"
|
||
type="password"
|
||
name="confirmPassword"
|
||
label="确认密码"
|
||
placeholder="请再次输入密码"
|
||
:rules="[{ required: true, message: '请确认密码' }, { validator: validatePassword, message: '两次密码不一致' }]"
|
||
/>
|
||
<van-field
|
||
v-model="form.captcha"
|
||
name="captcha"
|
||
label="验证码"
|
||
placeholder="请输入验证码"
|
||
:rules="[{ required: true, message: '请输入验证码' }]"
|
||
>
|
||
<template #button>
|
||
<van-image
|
||
:src="captchaImage"
|
||
fit="contain"
|
||
class="captcha-btn"
|
||
@click="refreshCaptcha"
|
||
/>
|
||
</template>
|
||
</van-field>
|
||
</van-cell-group>
|
||
|
||
<div class="tips-row">
|
||
<span>注册成功后将跳转到登录页,请使用刚创建的账号继续登录。</span>
|
||
</div>
|
||
|
||
<div class="register-actions">
|
||
<van-button
|
||
round
|
||
block
|
||
type="primary"
|
||
native-type="submit"
|
||
:loading="loading"
|
||
class="submit-btn"
|
||
>
|
||
注册
|
||
</van-button>
|
||
</div>
|
||
</van-form>
|
||
|
||
<div class="register-footer">
|
||
<router-link
|
||
to="/login"
|
||
class="link"
|
||
>
|
||
已有账号?去登录
|
||
</router-link>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { onMounted, reactive, ref } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { showSuccessToast, showToast } from 'vant'
|
||
import { authApi, type CaptchaResult } from '@/api/auth.ts'
|
||
|
||
const router = useRouter()
|
||
const loading = ref(false)
|
||
const captchaKey = ref('')
|
||
const captchaImage = ref('')
|
||
|
||
const form = reactive({
|
||
username: '',
|
||
email: '',
|
||
phone: '',
|
||
password: '',
|
||
confirmPassword: '',
|
||
captcha: ''
|
||
})
|
||
|
||
const validatePassword = () => form.password === form.confirmPassword
|
||
|
||
const refreshCaptcha = async () => {
|
||
try {
|
||
const res: CaptchaResult = await authApi.getCaptcha()
|
||
captchaKey.value = res.captchaKey
|
||
captchaImage.value = res.captchaImage
|
||
} catch (error) {
|
||
showToast('获取验证码失败')
|
||
}
|
||
}
|
||
|
||
const handleRegister = async () => {
|
||
if (!validatePassword()) {
|
||
showToast('两次密码不一致')
|
||
return
|
||
}
|
||
|
||
loading.value = true
|
||
try {
|
||
await authApi.register({
|
||
username: form.username,
|
||
email: form.email,
|
||
phone: form.phone,
|
||
password: form.password,
|
||
confirmPassword: form.confirmPassword,
|
||
captcha: form.captcha,
|
||
captchaKey: captchaKey.value
|
||
})
|
||
showSuccessToast('注册成功')
|
||
router.push('/login')
|
||
} catch (error: any) {
|
||
showToast(error.message || '注册失败')
|
||
refreshCaptcha()
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
refreshCaptcha()
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.auth-page {
|
||
min-height: 100vh;
|
||
background:
|
||
radial-gradient(circle at 18% 18%, rgba(34, 197, 94, 0.16), transparent 24%),
|
||
radial-gradient(circle at 82% 82%, rgba(59, 130, 246, 0.2), transparent 22%),
|
||
linear-gradient(135deg, #08111f 0%, #12345b 52%, #0f766e 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 28px 20px;
|
||
}
|
||
|
||
.auth-shell {
|
||
width: min(1180px, 100%);
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.15fr) 460px;
|
||
gap: 20px;
|
||
}
|
||
|
||
.auth-showcase,
|
||
.auth-panel {
|
||
border-radius: 30px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.auth-showcase {
|
||
padding: 34px 32px;
|
||
color: #fff;
|
||
background:
|
||
radial-gradient(circle at top right, rgba(255, 255, 255, 0.2), transparent 28%),
|
||
linear-gradient(135deg, rgba(15, 23, 42, 0.92), rgba(15, 118, 110, 0.92));
|
||
box-shadow: 0 24px 80px rgba(4, 16, 33, 0.34);
|
||
display: grid;
|
||
align-content: space-between;
|
||
}
|
||
|
||
.eyebrow {
|
||
margin: 0 0 12px;
|
||
font-size: 12px;
|
||
letter-spacing: 0.18em;
|
||
text-transform: uppercase;
|
||
color: rgba(255, 255, 255, 0.68);
|
||
}
|
||
|
||
.showcase-copy {
|
||
h1 {
|
||
margin: 0 0 12px;
|
||
font-size: 40px;
|
||
line-height: 1.18;
|
||
}
|
||
|
||
.lead {
|
||
margin: 0;
|
||
max-width: 620px;
|
||
color: rgba(255, 255, 255, 0.82);
|
||
line-height: 1.8;
|
||
}
|
||
}
|
||
|
||
.showcase-board {
|
||
display: grid;
|
||
gap: 12px;
|
||
margin-top: 28px;
|
||
}
|
||
|
||
.board-card {
|
||
padding: 18px 20px;
|
||
border-radius: 20px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
backdrop-filter: blur(12px);
|
||
|
||
strong {
|
||
display: block;
|
||
margin-bottom: 6px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
span {
|
||
color: rgba(255, 255, 255, 0.76);
|
||
font-size: 13px;
|
||
line-height: 1.7;
|
||
}
|
||
}
|
||
|
||
.auth-panel {
|
||
background: rgba(255, 255, 255, 0.96);
|
||
padding: 28px 26px 26px;
|
||
box-shadow: 0 24px 80px rgba(4, 16, 33, 0.34);
|
||
}
|
||
|
||
.panel-top {
|
||
margin-bottom: 22px;
|
||
}
|
||
|
||
.back-home {
|
||
border: none;
|
||
background: #f8fafc;
|
||
color: #475569;
|
||
padding: 8px 12px;
|
||
border-radius: 999px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.brand-lockup {
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.logo {
|
||
margin: 0;
|
||
font-size: 34px;
|
||
font-weight: 800;
|
||
color: #00a1d6;
|
||
}
|
||
|
||
.slogan {
|
||
margin: 10px 0 0;
|
||
color: #64748b;
|
||
font-size: 13px;
|
||
line-height: 1.7;
|
||
}
|
||
|
||
.captcha-banner {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
padding: 14px 16px;
|
||
border-radius: 18px;
|
||
background: #f8fafc;
|
||
|
||
strong {
|
||
display: block;
|
||
margin-bottom: 4px;
|
||
color: #18191c;
|
||
font-size: 14px;
|
||
}
|
||
|
||
span {
|
||
color: #64748b;
|
||
font-size: 12px;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
|
||
.captcha-image,
|
||
.captcha-btn {
|
||
flex-shrink: 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.captcha-image {
|
||
width: 120px;
|
||
height: 40px;
|
||
}
|
||
|
||
.captcha-btn {
|
||
width: 100px;
|
||
height: 32px;
|
||
}
|
||
|
||
:deep(.van-cell-group--inset) {
|
||
margin: 0;
|
||
border-radius: 20px;
|
||
overflow: hidden;
|
||
box-shadow: inset 0 0 0 1px #eef2f7;
|
||
}
|
||
|
||
:deep(.van-field) {
|
||
padding: 14px 16px;
|
||
}
|
||
|
||
.tips-row {
|
||
margin-top: 12px;
|
||
color: #64748b;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.register-actions {
|
||
margin-top: 22px;
|
||
}
|
||
|
||
.submit-btn {
|
||
:deep(.van-button) {
|
||
background: linear-gradient(135deg, #fb7299, #ff8fab);
|
||
border: none;
|
||
box-shadow: 0 14px 28px rgba(251, 114, 153, 0.24);
|
||
}
|
||
}
|
||
|
||
.register-footer {
|
||
text-align: center;
|
||
margin-top: 22px;
|
||
}
|
||
|
||
.link {
|
||
color: #00a1d6;
|
||
font-size: 14px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
@media (max-width: 960px) {
|
||
.auth-shell {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.auth-showcase {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.auth-page {
|
||
padding: 16px 12px;
|
||
}
|
||
|
||
.auth-panel {
|
||
padding: 22px 18px 20px;
|
||
border-radius: 24px;
|
||
}
|
||
|
||
.captcha-banner {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.logo {
|
||
font-size: 30px;
|
||
}
|
||
}
|
||
</style>
|