| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- import React, { useState } from 'react';
- import { useForm } from 'react-hook-form';
- import { EyeIcon, EyeSlashIcon, UserIcon, LockClosedIcon } from '@heroicons/react/24/outline';
- import { useNavigate } from 'react-router-dom';
- import { useAuth } from '@/client/home/hooks/AuthProvider';
- import { authClient } from '@/client/api';
- const RegisterPage: React.FC = () => {
- const { register, handleSubmit, watch, formState: { errors } } = useForm();
- const [showPassword, setShowPassword] = useState(false);
- const [showConfirmPassword, setShowConfirmPassword] = useState(false);
- const [loading, setLoading] = useState(false);
- const { login } = useAuth();
- const navigate = useNavigate();
- const password = watch('password', '');
- const onSubmit = async (data: any) => {
- try {
- setLoading(true);
-
- // 调用注册API
- const response = await authClient.register.$post({
- json: {
- username: data.username,
- password: data.password,
- }
- });
-
- if (response.status !== 201) {
- const result = await response.json();
- throw new Error(result.message || '注册失败');
- }
-
- // 注册成功后自动登录
- await login(data.username, data.password);
-
- // 跳转到首页
- navigate('/');
- } catch (error) {
- console.error('Registration error:', error);
- alert((error as Error).message || '注册失败,请稍后重试');
- } finally {
- setLoading(false);
- }
- };
- return (
- <div className="flex justify-center items-center min-h-screen bg-gray-100">
- <div className="w-full max-w-md bg-white rounded-lg shadow-md overflow-hidden">
- <div className="p-6 sm:p-8">
- <div className="text-center mb-8">
- <h2 className="text-2xl font-bold text-gray-900">账号注册</h2>
- <p className="mt-2 text-sm text-gray-600">创建新账号以开始使用</p>
- </div>
-
- <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
- <div>
- <label htmlFor="username" className="block text-sm font-medium text-gray-700 mb-1">
- 用户名
- </label>
- <div className="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"
- type="text"
- className={`w-full pl-10 pr-3 py-2 border ${errors.username ? 'border-red-300' : 'border-gray-300'} rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent`}
- placeholder="请输入用户名"
- {...register('username', {
- required: '用户名不能为空',
- minLength: { value: 3, message: '用户名至少3个字符' },
- maxLength: { value: 20, message: '用户名不能超过20个字符' }
- })}
- />
- </div>
- {errors.username && (
- <p className="mt-1 text-sm text-red-600">{errors.username.message?.toString()}</p>
- )}
- </div>
-
- <div>
- <label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-1">
- 密码
- </label>
- <div className="relative">
- <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
- <LockClosedIcon className="h-5 w-5 text-gray-400" />
- </div>
- <input
- id="password"
- type={showPassword ? 'text' : 'password'}
- className={`w-full pl-10 pr-10 py-2 border ${errors.password ? 'border-red-300' : 'border-gray-300'} rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent`}
- placeholder="请输入密码"
- {...register('password', {
- required: '密码不能为空',
- minLength: { value: 6, message: '密码至少6个字符' },
- maxLength: { value: 30, message: '密码不能超过30个字符' }
- })}
- />
- <button
- type="button"
- className="absolute inset-y-0 right-0 pr-3 flex items-center"
- onClick={() => setShowPassword(!showPassword)}
- >
- {showPassword ? (
- <EyeSlashIcon className="h-5 w-5 text-gray-400" />
- ) : (
- <EyeIcon className="h-5 w-5 text-gray-400" />
- )}
- </button>
- </div>
- {errors.password && (
- <p className="mt-1 text-sm text-red-600">{errors.password.message?.toString()}</p>
- )}
- </div>
-
- <div>
- <label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700 mb-1">
- 确认密码
- </label>
- <div className="relative">
- <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
- <LockClosedIcon className="h-5 w-5 text-gray-400" />
- </div>
- <input
- id="confirmPassword"
- type={showConfirmPassword ? 'text' : 'password'}
- className={`w-full pl-10 pr-10 py-2 border ${errors.confirmPassword ? 'border-red-300' : 'border-gray-300'} rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent`}
- placeholder="请再次输入密码"
- {...register('confirmPassword', {
- required: '请确认密码',
- validate: value => value === password || '两次密码输入不一致'
- })}
- />
- <button
- type="button"
- className="absolute inset-y-0 right-0 pr-3 flex items-center"
- onClick={() => setShowConfirmPassword(!showConfirmPassword)}
- >
- {showConfirmPassword ? (
- <EyeSlashIcon className="h-5 w-5 text-gray-400" />
- ) : (
- <EyeIcon className="h-5 w-5 text-gray-400" />
- )}
- </button>
- </div>
- {errors.confirmPassword && (
- <p className="mt-1 text-sm text-red-600">{errors.confirmPassword.message?.toString()}</p>
- )}
- </div>
-
- <div>
- <button
- type="submit"
- disabled={loading}
- className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
- >
- {loading ? '注册中...' : '注册'}
- </button>
- </div>
- </form>
-
- <div className="mt-6">
- <div className="relative">
- <div className="absolute inset-0 flex items-center">
- <div className="w-full border-t border-gray-300"></div>
- </div>
- <div className="relative flex justify-center text-sm">
- <span className="px-2 bg-white text-gray-500">已有账号?</span>
- </div>
- </div>
-
- <div className="mt-4">
- <button
- type="button"
- onClick={() => navigate('/login')}
- className="w-full flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
- >
- 返回登录
- </button>
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- };
- export default RegisterPage;
|