Your Name b1eab32c75 初始提交: FLNXI电商素材系统官方网站
- Next.js 项目框架
- 完整的认证系统集成
- 数据库配置和部署脚本
- 产品价格体系和文档
- Docker 部署配置
2025-12-13 21:38:32 +08:00

320 lines
11 KiB
TypeScript
Raw Permalink 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.

'use client'
import { useState } from 'react'
import { Mail, Lock, User as UserIcon, ArrowLeft, AlertCircle, CheckCircle } from 'lucide-react'
import Link from 'next/link'
import Image from 'next/image'
import { useRouter } from 'next/navigation'
export default function SignUpPage() {
const router = useRouter()
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
confirmPassword: '',
})
const [agreedToTerms, setAgreedToTerms] = useState(false)
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const [success, setSuccess] = useState(false)
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
})
setError('') // 清除错误提示
}
const validateForm = () => {
if (!formData.name.trim()) {
setError('请输入用户名')
return false
}
if (!formData.email.trim()) {
setError('请输入邮箱地址')
return false
}
// 简单的邮箱格式验证
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(formData.email)) {
setError('请输入有效的邮箱地址')
return false
}
if (!formData.password) {
setError('请输入密码')
return false
}
if (formData.password.length < 6) {
setError('密码长度至少6位')
return false
}
if (formData.password !== formData.confirmPassword) {
setError('两次输入的密码不一致')
return false
}
if (!agreedToTerms) {
setError('请阅读并同意服务条款')
return false
}
return true
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!validateForm()) {
return
}
setLoading(true)
setError('')
try {
const response = await fetch('/api/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: formData.name,
email: formData.email,
password: formData.password,
}),
})
const data = await response.json()
if (!response.ok) {
setError(data.message || '注册失败,请重试')
} else {
setSuccess(true)
// 3秒后跳转到登录页面
setTimeout(() => {
router.push('/auth/signin?registered=true')
}, 3000)
}
} catch (err) {
setError('注册失败,请稍后重试')
} finally {
setLoading(false)
}
}
if (success) {
return (
<div className="min-h-screen bg-gradient-to-b from-apple-gray-50 to-white flex items-center justify-center px-4">
<div className="max-w-md w-full text-center">
<div className="bg-white rounded-3xl apple-shadow-lg p-12">
<div className="w-16 h-16 bg-gradient-to-r from-green-500 to-emerald-600 rounded-full flex items-center justify-center mx-auto mb-6">
<CheckCircle className="w-8 h-8 text-white" />
</div>
<h2 className="text-3xl font-bold text-apple-gray-900 mb-4">
注册成功!
</h2>
<p className="text-apple-gray-600 mb-8">
您的账户已创建成功,3秒后自动跳转到登录页面...
</p>
<Link
href="/auth/signin"
className="inline-block px-8 py-3 bg-gradient-to-r from-apple-blue to-blue-600 text-white rounded-full font-semibold button-hover apple-shadow"
>
立即登录
</Link>
</div>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gradient-to-b from-apple-gray-50 to-white flex items-center justify-center px-4 py-12">
<div className="max-w-md w-full">
{/* 返回首页 */}
<Link
href="/"
className="inline-flex items-center space-x-2 text-apple-gray-600 hover:text-apple-blue transition-colors mb-8"
>
<ArrowLeft className="w-4 h-4" />
<span>返回首页</span>
</Link>
{/* Logo and Title */}
<div className="text-center mb-8">
<div className="flex justify-center mb-4">
<div className="relative w-16 h-16">
<Image
src="/images/logo.png"
alt="FLNXI Logo"
fill
className="object-contain"
priority
/>
</div>
</div>
<h1 className="text-3xl font-bold text-apple-gray-900 mb-2">
注册 FLNXI
</h1>
<p className="text-apple-gray-600">
创建您的账户,开始管理素材
</p>
</div>
{/* 注册卡片 */}
<div className="bg-white rounded-3xl apple-shadow-lg p-8">
{/* 错误提示 */}
{error && (
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-xl flex items-start space-x-3">
<AlertCircle className="w-5 h-5 text-red-600 flex-shrink-0 mt-0.5" />
<p className="text-sm text-red-800">{error}</p>
</div>
)}
{/* 注册表单 */}
<form onSubmit={handleSubmit} className="space-y-5">
{/* 用户名输入 */}
<div>
<label className="block text-sm font-medium text-apple-gray-700 mb-2">
用户名
</label>
<div className="relative">
<UserIcon className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-apple-gray-400" />
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
className="w-full pl-12 pr-4 py-3 border-2 border-apple-gray-200 rounded-xl focus:ring-2 focus:ring-apple-blue focus:border-transparent outline-none transition-all"
placeholder="请输入用户名"
required
/>
</div>
</div>
{/* 邮箱输入 */}
<div>
<label className="block text-sm font-medium text-apple-gray-700 mb-2">
邮箱地址
</label>
<div className="relative">
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-apple-gray-400" />
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
className="w-full pl-12 pr-4 py-3 border-2 border-apple-gray-200 rounded-xl focus:ring-2 focus:ring-apple-blue focus:border-transparent outline-none transition-all"
placeholder="your@email.com"
required
/>
</div>
</div>
{/* 密码输入 */}
<div>
<label className="block text-sm font-medium text-apple-gray-700 mb-2">
密码
</label>
<div className="relative">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-apple-gray-400" />
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
className="w-full pl-12 pr-4 py-3 border-2 border-apple-gray-200 rounded-xl focus:ring-2 focus:ring-apple-blue focus:border-transparent outline-none transition-all"
placeholder="至少6位字符"
required
/>
</div>
</div>
{/* 确认密码输入 */}
<div>
<label className="block text-sm font-medium text-apple-gray-700 mb-2">
确认密码
</label>
<div className="relative">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-apple-gray-400" />
<input
type="password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
className="w-full pl-12 pr-4 py-3 border-2 border-apple-gray-200 rounded-xl focus:ring-2 focus:ring-apple-blue focus:border-transparent outline-none transition-all"
placeholder="再次输入密码"
required
/>
</div>
</div>
{/* 服务条款 */}
<div className="flex items-start space-x-3">
<input
type="checkbox"
id="terms"
checked={agreedToTerms}
onChange={(e) => setAgreedToTerms(e.target.checked)}
className="mt-1 w-4 h-4 text-apple-blue border-apple-gray-300 rounded focus:ring-apple-blue"
/>
<label htmlFor="terms" className="text-sm text-apple-gray-600">
我已阅读并同意
<a href="#" className="text-apple-blue hover:underline ml-1">
服务条款
</a>
和
<a href="#" className="text-apple-blue hover:underline ml-1">
隐私政策
</a>
</label>
</div>
{/* 注册按钮 */}
<button
type="submit"
disabled={loading}
className="w-full py-4 bg-gradient-to-r from-apple-blue to-blue-600 text-white font-semibold rounded-xl button-hover apple-shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all text-lg"
>
{loading ? (
<span className="flex items-center justify-center">
<svg className="animate-spin h-5 w-5 mr-3" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
注册中...
</span>
) : (
'立即注册'
)}
</button>
</form>
{/* 底部登录链接 */}
<div className="mt-6 pt-6 border-t border-apple-gray-100 text-center text-sm text-apple-gray-600">
<p>
已有账户?
<Link href="/auth/signin" className="text-apple-blue hover:underline font-semibold ml-1">
立即登录
</Link>
</p>
</div>
</div>
{/* 额外信息 */}
<div className="mt-6 text-center text-sm text-apple-gray-500">
<p>注册即表示您同意我们的服务条款和隐私政策</p>
</div>
</div>
</div>
)
}