refactor(frontend): Rework home layout and user interactions
This commit is contained in:
@@ -1,80 +1,155 @@
|
||||
<template>
|
||||
<div class="register-page">
|
||||
<div class="register-container">
|
||||
<div class="register-header">
|
||||
<h1 class="logo">HAOVP</h1>
|
||||
<p class="slogan">创建账号,保存你的观看与创作记录</p>
|
||||
</div>
|
||||
|
||||
<van-form @submit="handleRegister">
|
||||
<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="register-actions">
|
||||
<van-button round block type="primary" native-type="submit" :loading="loading" color="#00a1d6">
|
||||
注册
|
||||
</van-button>
|
||||
<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>
|
||||
</van-form>
|
||||
|
||||
<div class="register-footer">
|
||||
<router-link to="/login" class="link">已有账号?去登录</router-link>
|
||||
</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 { ref, reactive, onMounted } from 'vue'
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showToast, showSuccessToast } from 'vant'
|
||||
import { showSuccessToast, showToast } from 'vant'
|
||||
import { authApi, type CaptchaResult } from '@/api/auth.ts'
|
||||
|
||||
const router = useRouter()
|
||||
@@ -91,9 +166,7 @@ const form = reactive({
|
||||
captcha: ''
|
||||
})
|
||||
|
||||
const validatePassword = () => {
|
||||
return form.password === form.confirmPassword
|
||||
}
|
||||
const validatePassword = () => form.password === form.confirmPassword
|
||||
|
||||
const refreshCaptcha = async () => {
|
||||
try {
|
||||
@@ -138,63 +211,235 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.register-page {
|
||||
.auth-page {
|
||||
min-height: 100vh;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(34, 197, 94, 0.22), transparent 28%),
|
||||
radial-gradient(circle at bottom right, rgba(59, 130, 246, 0.24), transparent 26%),
|
||||
linear-gradient(135deg, #0b1323 0%, #1d3557 55%, #0f766e 100%);
|
||||
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: 20px;
|
||||
padding: 28px 20px;
|
||||
}
|
||||
|
||||
.register-container {
|
||||
width: 100%;
|
||||
max-width: 430px;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-radius: 28px;
|
||||
padding: 34px 28px 28px;
|
||||
.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;
|
||||
}
|
||||
|
||||
.register-header {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
.eyebrow {
|
||||
margin: 0 0 12px;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255, 255, 255, 0.68);
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: #00a1d6;
|
||||
margin: 0;
|
||||
.showcase-copy {
|
||||
h1 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 40px;
|
||||
line-height: 1.18;
|
||||
}
|
||||
|
||||
.slogan {
|
||||
margin-top: 10px;
|
||||
color: #64748b;
|
||||
.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: 20px;
|
||||
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: 20px;
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #00a1d6;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
.link {
|
||||
color: #00a1d6;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.auth-shell {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.auth-showcase {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.captcha-btn {
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
@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>
|
||||
|
||||
Reference in New Issue
Block a user