import { useState } from 'react' import { Link } from 'wouter' interface FormData { username: string email: string password: string confirmPassword: string age: string birthDate: string phone: string website: string bio: string country: string newsletter: boolean terms: boolean } type FormErrors = Record; export default function FormTestPage() { const [formData, setFormData] = useState({ username: '', email: '', password: '', confirmPassword: '', age: '', birthDate: '', phone: '', website: '', bio: '', country: '', newsletter: false, terms: false }) const [errors, setErrors] = useState({}) const [isSubmitting, setIsSubmitting] = useState(false) const [submitResult, setSubmitResult] = useState<'success' | 'error' | null>(null) const [submitMessage, setSubmitMessage] = useState('') const validateField = (name: string, value: string | boolean): string => { switch (name) { case 'username': if (!value) return '用户名不能为空' if (typeof value === 'string' && value.length < 3) return '用户名至少需要3个字符' if (typeof value === 'string' && !/^[a-zA-Z0-9_]+$/.test(value)) return '用户名只能包含字母、数字和下划线' return '' case 'email': if (!value) return '邮箱不能为空' if (typeof value === 'string' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return '请输入有效的邮箱地址' return '' case 'password': if (!value) return '密码不能为空' if (typeof value === 'string' && value.length < 6) return '密码至少需要6个字符' if (typeof value === 'string' && !/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) return '密码必须包含大小写字母和数字' return '' case 'confirmPassword': if (!value) return '请确认密码' if (value !== formData.password) return '两次输入的密码不一致' return '' case 'age': { if (!value) return '年龄不能为空' const age = parseInt(value as string) if (isNaN(age) || age < 18 || age > 120) return '年龄必须在18-120之间' return '' } case 'phone': if (!value) return '手机号不能为空' if (typeof value === 'string' && !/^1[3-9]\d{9}$/.test(value)) return '请输入有效的手机号' return '' case 'terms': if (!value) return '请同意服务条款' return '' default: return '' } } const handleInputChange = (name: string, value: string | boolean) => { console.log(`Input changed: ${name} = ${value}`) setFormData(prev => ({ ...prev, [name]: value })) // 实时验证 const error = validateField(name, value) setErrors(prev => ({ ...prev, [name]: error })) } const validateForm = (): boolean => { const newErrors: FormErrors = {} let isValid = true Object.keys(formData).forEach(key => { const error = validateField(key, formData[key as keyof FormData]) if (error) { newErrors[key] = error isValid = false } }) setErrors(newErrors) return isValid } const simulateSubmit = async (): Promise<{ success: boolean; message: string }> => { // 模拟网络延迟 await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 2000)) // 模拟随机失败 if (Math.random() < 0.3) { throw new Error('网络错误:服务器暂时不可用,请稍后重试') } // 模拟服务器验证错误 if (formData.username.toLowerCase() === 'admin') { throw new Error('用户名 "admin" 已被占用,请选择其他用户名') } return { success: true, message: '注册成功!欢迎加入我们的平台。' } } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!validateForm()) { setSubmitResult('error') setSubmitMessage('请修正表单中的错误') return } setIsSubmitting(true) setSubmitResult(null) setSubmitMessage('') try { const result = await simulateSubmit() setSubmitResult('success') setSubmitMessage(result.message) } catch (error) { setSubmitResult('error') setSubmitMessage(error instanceof Error ? error.message : '提交失败,请重试') } finally { setIsSubmitting(false) } } const resetForm = () => { setFormData({ username: '', email: '', password: '', confirmPassword: '', age: '', birthDate: '', phone: '', website: '', bio: '', country: '', newsletter: false, terms: false }) setErrors({}) setSubmitResult(null) setSubmitMessage('') } return (

用户注册表单

测试各种表单输入、验证和提交功能

{/* 用户名 */}
handleInputChange('username', e.target.value)} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white ${ errors.username ? 'border-red-500' : 'border-gray-300 dark:border-gray-600' }`} placeholder="请输入用户名" /> {errors.username && (

{errors.username}

)}
{/* 邮箱 */}
handleInputChange('email', e.target.value)} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white ${ errors.email ? 'border-red-500' : 'border-gray-300 dark:border-gray-600' }`} placeholder="请输入邮箱地址" /> {errors.email && (

{errors.email}

)}
{/* 密码 */}
handleInputChange('password', e.target.value)} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white ${ errors.password ? 'border-red-500' : 'border-gray-300 dark:border-gray-600' }`} placeholder="请输入密码" /> {errors.password && (

{errors.password}

)}
handleInputChange('confirmPassword', e.target.value)} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white ${ errors.confirmPassword ? 'border-red-500' : 'border-gray-300 dark:border-gray-600' }`} placeholder="请再次输入密码" /> {errors.confirmPassword && (

{errors.confirmPassword}

)}
{/* 年龄和生日 */}
handleInputChange('age', e.target.value)} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white ${ errors.age ? 'border-red-500' : 'border-gray-300 dark:border-gray-600' }`} placeholder="请输入年龄" min="18" max="120" /> {errors.age && (

{errors.age}

)}
handleInputChange('birthDate', e.target.value)} className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white" />
{/* 手机和网站 */}
handleInputChange('phone', e.target.value)} className={`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white ${ errors.phone ? 'border-red-500' : 'border-gray-300 dark:border-gray-600' }`} placeholder="请输入手机号" /> {errors.phone && (

{errors.phone}

)}
handleInputChange('website', e.target.value)} className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white" placeholder="https://example.com" />
{/* 国家选择 */}
{/* 个人简介 */}