feat: 添加用户注册功能前端页面
- 新增 Signup.vue 注册页面 - 路由添加 /signup 路由 - Login.vue 注册链接跳转到注册页 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import Dashboard from '@/views/Dashboard.vue'
|
||||
import Login from '@/views/Login.vue'
|
||||
import Signup from '@/views/Signup.vue'
|
||||
import Chat from '@/views/Chat.vue'
|
||||
import Agents from '@/views/Agents.vue'
|
||||
import Team from '@/views/Team.vue'
|
||||
@@ -23,6 +24,11 @@ const router = createRouter({
|
||||
name: 'login',
|
||||
component: Login
|
||||
},
|
||||
{
|
||||
path: '/signup',
|
||||
name: 'signup',
|
||||
component: Signup
|
||||
},
|
||||
{
|
||||
path: '/dashboard',
|
||||
name: 'dashboard',
|
||||
|
||||
@@ -149,7 +149,7 @@ const handleLogin = () => {
|
||||
<!-- 注册链接 -->
|
||||
<p class="text-center mt-6 text-gray-400">
|
||||
Don't have an account?
|
||||
<a href="#" class="text-primary-orange hover:text-orange-400 font-medium transition-colors">Sign up</a>
|
||||
<a @click="router.push('/signup')" class="text-primary-orange hover:text-orange-400 font-medium transition-colors cursor-pointer">Sign up</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
232
web/src/views/Signup.vue
Normal file
232
web/src/views/Signup.vue
Normal file
@@ -0,0 +1,232 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 表单数据
|
||||
const username = ref('')
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const confirmPassword = ref('')
|
||||
const agreeTerms = ref(false)
|
||||
const isLoading = ref(false)
|
||||
const showPassword = ref(false)
|
||||
const showConfirmPassword = ref(false)
|
||||
const errorMsg = ref('')
|
||||
|
||||
// 表单验证
|
||||
const validateForm = () => {
|
||||
errorMsg.value = ''
|
||||
|
||||
if (!username.value || username.value.length < 3) {
|
||||
errorMsg.value = 'Username must be at least 3 characters'
|
||||
return false
|
||||
}
|
||||
|
||||
if (!email.value || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)) {
|
||||
errorMsg.value = 'Please enter a valid email address'
|
||||
return false
|
||||
}
|
||||
|
||||
if (!password.value || password.value.length < 6) {
|
||||
errorMsg.value = 'Password must be at least 6 characters'
|
||||
return false
|
||||
}
|
||||
|
||||
if (password.value !== confirmPassword.value) {
|
||||
errorMsg.value = 'Passwords do not match'
|
||||
return false
|
||||
}
|
||||
|
||||
if (!agreeTerms.value) {
|
||||
errorMsg.value = 'Please agree to the Terms of Service'
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 注册处理
|
||||
const handleSignup = () => {
|
||||
if (!validateForm()) return
|
||||
|
||||
isLoading.value = true
|
||||
// 模拟注册
|
||||
setTimeout(() => {
|
||||
isLoading.value = false
|
||||
// 注册成功,跳转到登录页
|
||||
router.push('/')
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
// 跳转到登录
|
||||
const goToLogin = () => {
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen bg-dark-900 flex items-center justify-center p-4">
|
||||
<!-- 背景装饰 -->
|
||||
<div class="absolute inset-0 overflow-hidden">
|
||||
<div class="absolute top-1/4 -left-20 w-80 h-80 bg-primary-orange/10 rounded-full blur-3xl"></div>
|
||||
<div class="absolute bottom-1/4 -right-20 w-80 h-80 bg-primary-purple/10 rounded-full blur-3xl"></div>
|
||||
</div>
|
||||
|
||||
<!-- 注册卡片 -->
|
||||
<div class="w-full max-w-md relative">
|
||||
<!-- Logo -->
|
||||
<div class="text-center mb-8">
|
||||
<div class="w-14 h-14 rounded-2xl bg-gradient-to-br from-primary-orange to-red-500 flex items-center justify-center mx-auto mb-4 shadow-lg shadow-primary-orange/20">
|
||||
<i class="fa-solid fa-basketball text-white text-2xl"></i>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-white">Create an account</h1>
|
||||
<p class="text-gray-400 mt-2">Join us and start your journey</p>
|
||||
</div>
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<div class="bg-dark-700 rounded-2xl p-8 shadow-xl border border-dark-500/50">
|
||||
<!-- 错误提示 -->
|
||||
<div v-if="errorMsg" class="mb-4 p-3 bg-red-500/10 border border-red-500/30 rounded-lg text-red-400 text-sm flex items-center gap-2">
|
||||
<i class="fa-solid fa-circle-exclamation"></i>
|
||||
{{ errorMsg }}
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleSignup" class="space-y-4">
|
||||
<!-- 用户名 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Username</label>
|
||||
<div class="relative">
|
||||
<i class="fa-solid fa-user absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
<input
|
||||
v-model="username"
|
||||
type="text"
|
||||
placeholder="Choose a username"
|
||||
required
|
||||
class="w-full bg-dark-600 border border-dark-500 rounded-xl py-3 pl-12 pr-4 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange focus:ring-1 focus:ring-primary-orange transition-colors"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 邮箱 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Email</label>
|
||||
<div class="relative">
|
||||
<i class="fa-solid fa-envelope absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
class="w-full bg-dark-600 border border-dark-500 rounded-xl py-3 pl-12 pr-4 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange focus:ring-1 focus:ring-primary-orange transition-colors"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 密码 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Password</label>
|
||||
<div class="relative">
|
||||
<i class="fa-solid fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
<input
|
||||
v-model="password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
placeholder="Create a password"
|
||||
required
|
||||
class="w-full bg-dark-600 border border-dark-500 rounded-xl py-3 pl-12 pr-12 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange focus:ring-1 focus:ring-primary-orange transition-colors"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@click="showPassword = !showPassword"
|
||||
class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-300 transition-colors"
|
||||
>
|
||||
<i :class="['fa-solid', showPassword ? 'fa-eye-slash' : 'fa-eye']"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 确认密码 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-300 mb-2">Confirm Password</label>
|
||||
<div class="relative">
|
||||
<i class="fa-solid fa-lock absolute left-4 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
<input
|
||||
v-model="confirmPassword"
|
||||
:type="showConfirmPassword ? 'text' : 'password'"
|
||||
placeholder="Confirm your password"
|
||||
required
|
||||
class="w-full bg-dark-600 border border-dark-500 rounded-xl py-3 pl-12 pr-12 text-white placeholder-gray-500 focus:outline-none focus:border-primary-orange focus:ring-1 focus:ring-primary-orange transition-colors"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@click="showConfirmPassword = !showConfirmPassword"
|
||||
class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-300 transition-colors"
|
||||
>
|
||||
<i :class="['fa-solid', showConfirmPassword ? 'fa-eye-slash' : 'fa-eye']"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 服务条款 -->
|
||||
<div class="flex items-start">
|
||||
<label class="flex items-center cursor-pointer">
|
||||
<input
|
||||
v-model="agreeTerms"
|
||||
type="checkbox"
|
||||
class="sr-only peer"
|
||||
>
|
||||
<div class="w-5 h-5 border-2 border-dark-400 rounded-md peer-checked:border-primary-orange peer-checked:bg-primary-orange transition-colors flex items-center justify-center">
|
||||
<i v-if="agreeTerms" class="fa-solid fa-check text-white text-xs"></i>
|
||||
</div>
|
||||
<span class="ml-2 text-sm text-gray-400">
|
||||
I agree to the
|
||||
<a href="#" class="text-primary-orange hover:text-orange-400 transition-colors">Terms of Service</a>
|
||||
and
|
||||
<a href="#" class="text-primary-orange hover:text-orange-400 transition-colors">Privacy Policy</a>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="isLoading"
|
||||
class="w-full bg-gradient-to-r from-primary-orange to-red-500 hover:from-orange-500 hover:to-red-600 text-white font-semibold py-3 rounded-xl transition-all duration-300 shadow-lg shadow-primary-orange/20 hover:shadow-primary-orange/40 flex items-center justify-center gap-2 disabled:opacity-70 disabled:cursor-not-allowed"
|
||||
>
|
||||
<i v-if="isLoading" class="fa-solid fa-circle-notch fa-spin"></i>
|
||||
<span>{{ isLoading ? 'Creating account...' : 'Create account' }}</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- 分割线 -->
|
||||
<div class="relative my-6">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-dark-500"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="px-4 bg-dark-700 text-gray-500">Or sign up with</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第三方注册 -->
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<button class="flex items-center justify-center gap-2 bg-dark-600 hover:bg-dark-500 border border-dark-500 rounded-xl py-2.5 text-gray-300 font-medium transition-colors">
|
||||
<i class="fa-brands fa-google"></i>
|
||||
<span>Google</span>
|
||||
</button>
|
||||
<button class="flex items-center justify-center gap-2 bg-dark-600 hover:bg-dark-500 border border-dark-500 rounded-xl py-2.5 text-gray-300 font-medium transition-colors">
|
||||
<i class="fa-brands fa-github"></i>
|
||||
<span>GitHub</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 登录链接 -->
|
||||
<p class="text-center mt-6 text-gray-400">
|
||||
Already have an account?
|
||||
<a @click="goToLogin" class="text-primary-orange hover:text-orange-400 font-medium transition-colors cursor-pointer">Sign in</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user