| import React, { useState } from 'react'; | |
| import { Link } from 'react-router-dom'; | |
| import { UserPlus, Mail, Lock, User as UserIcon, AlertCircle } from 'lucide-react'; | |
| import { authAPI } from '../utils/api'; | |
| import { User } from '../types'; | |
| interface RegisterProps { | |
| onRegister: (user: User, token: string) => void; | |
| } | |
| const Register: React.FC<RegisterProps> = ({ onRegister }) => { | |
| const [formData, setFormData] = useState({ | |
| username: '', | |
| email: '', | |
| password: '', | |
| confirmPassword: '', | |
| }); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState(''); | |
| const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
| setFormData({ | |
| ...formData, | |
| [e.target.name]: e.target.value, | |
| }); | |
| setError(''); | |
| }; | |
| const handleSubmit = async (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| setLoading(true); | |
| setError(''); | |
| if (formData.password !== formData.confirmPassword) { | |
| setError('两次输入的密码不一致'); | |
| setLoading(false); | |
| return; | |
| } | |
| if (formData.password.length < 6) { | |
| setError('密码长度至少为6位'); | |
| setLoading(false); | |
| return; | |
| } | |
| try { | |
| const { confirmPassword, ...registerData } = formData; | |
| const response = await authAPI.register(registerData); | |
| onRegister(response.user, response.token); | |
| } catch (error: any) { | |
| setError(error.response?.data?.message || '注册失败,请重试'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| return ( | |
| <div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> | |
| <div className="max-w-md w-full space-y-8"> | |
| <div className="text-center"> | |
| <div className="mx-auto h-12 w-12 bg-primary-600 rounded-full flex items-center justify-center"> | |
| <UserPlus className="h-6 w-6 text-white" /> | |
| </div> | |
| <h2 className="mt-6 text-3xl font-bold text-gray-900"> | |
| 创建新账号 | |
| </h2> | |
| <p className="mt-2 text-sm text-gray-600"> | |
| 已有账号?{' '} | |
| <Link | |
| to="/login" | |
| className="font-medium text-primary-600 hover:text-primary-500" | |
| > | |
| 立即登录 | |
| </Link> | |
| </p> | |
| </div> | |
| <form className="mt-8 space-y-6" onSubmit={handleSubmit}> | |
| {error && ( | |
| <div className="bg-red-50 border border-red-200 rounded-lg p-4 flex items-center space-x-2"> | |
| <AlertCircle className="h-5 w-5 text-red-500" /> | |
| <span className="text-red-700 text-sm">{error}</span> | |
| </div> | |
| )} | |
| <div className="space-y-4"> | |
| <div> | |
| <label htmlFor="username" className="block text-sm font-medium text-gray-700"> | |
| 用户名 | |
| </label> | |
| <div className="mt-1 relative"> | |
| <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <UserIcon className="h-5 w-5 text-gray-400" /> | |
| </div> | |
| <input | |
| id="username" | |
| name="username" | |
| type="text" | |
| required | |
| value={formData.username} | |
| onChange={handleChange} | |
| className="input-field pl-10" | |
| placeholder="请输入用户名" | |
| /> | |
| </div> | |
| </div> | |
| <div> | |
| <label htmlFor="email" className="block text-sm font-medium text-gray-700"> | |
| 邮箱地址 | |
| </label> | |
| <div className="mt-1 relative"> | |
| <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <Mail className="h-5 w-5 text-gray-400" /> | |
| </div> | |
| <input | |
| id="email" | |
| name="email" | |
| type="email" | |
| required | |
| value={formData.email} | |
| onChange={handleChange} | |
| className="input-field pl-10" | |
| placeholder="请输入邮箱地址" | |
| /> | |
| </div> | |
| </div> | |
| <div> | |
| <label htmlFor="password" className="block text-sm font-medium text-gray-700"> | |
| 密码 | |
| </label> | |
| <div className="mt-1 relative"> | |
| <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <Lock className="h-5 w-5 text-gray-400" /> | |
| </div> | |
| <input | |
| id="password" | |
| name="password" | |
| type="password" | |
| required | |
| value={formData.password} | |
| onChange={handleChange} | |
| className="input-field pl-10" | |
| placeholder="请输入密码(至少6位)" | |
| /> | |
| </div> | |
| </div> | |
| <div> | |
| <label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700"> | |
| 确认密码 | |
| </label> | |
| <div className="mt-1 relative"> | |
| <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <Lock className="h-5 w-5 text-gray-400" /> | |
| </div> | |
| <input | |
| id="confirmPassword" | |
| name="confirmPassword" | |
| type="password" | |
| required | |
| value={formData.confirmPassword} | |
| onChange={handleChange} | |
| className="input-field pl-10" | |
| placeholder="请再次输入密码" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| <button | |
| type="submit" | |
| disabled={loading} | |
| className="w-full btn-primary disabled:opacity-50 disabled:cursor-not-allowed" | |
| > | |
| {loading ? ( | |
| <div className="flex items-center justify-center"> | |
| <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div> | |
| 注册中... | |
| </div> | |
| ) : ( | |
| '注册' | |
| )} | |
| </button> | |
| </form> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default Register; | |