// ============================================================ // LoginForm — 登录表单 // ============================================================ import { useState, useCallback } from 'react'; import { Input, Button, Checkbox, Typography } from 'antd'; import { UserOutlined, LockOutlined, EyeTwoTone, EyeInvisibleOutlined } from '@ant-design/icons'; import { loginFields } from '../../settings/login-fields'; import { validateForm } from '../../settings/validators'; import { LegalTextModal } from '@/shared/components/LegalTextModal'; import type { LoginFormValues } from '../../model/types'; const { Text } = Typography; interface LoginFormProps { initialUsername?: string; initialPassword?: string; initialRemember?: boolean; initialAutoLogin?: boolean; submitting?: boolean; onSubmit: (values: LoginFormValues) => void; onRememberChange: (checked: boolean) => void; onAutoLoginChange: (checked: boolean) => void; onForgotPassword?: () => void; } export function LoginForm({ initialUsername, initialPassword, initialRemember = false, initialAutoLogin = false, submitting = false, onSubmit, onRememberChange, onAutoLoginChange, onForgotPassword, }: LoginFormProps) { const [username, setUsername] = useState(initialUsername || ''); const [password, setPassword] = useState(initialPassword || ''); const [remember, setRemember] = useState(initialRemember); const [autoLogin, setAutoLogin] = useState(initialAutoLogin); const [agreed, setAgreed] = useState(true); const [errors, setErrors] = useState>({}); // 协议弹窗 const [legalType, setLegalType] = useState<'service' | 'points' | null>(null); const clearError = (name: string) => setErrors((p) => { const n = { ...p }; delete n[name]; return n; }); const handleSubmit = useCallback(() => { const values = { username, password }; const fieldErrors = validateForm(values, loginFields); if (Object.keys(fieldErrors).length > 0) { setErrors(fieldErrors); return; } if (!agreed) { setErrors({ _agreement: ['请先阅读并同意用户协议'] }); return; } setErrors({}); onSubmit({ username, password, remember, autoLogin: remember && autoLogin }); }, [username, password, remember, autoLogin, agreed, onSubmit]); return ( <>
{/* 用户名 */}
} placeholder="用户名" value={username} onChange={(e) => { setUsername(e.target.value); clearError('username'); }} status={errors.username ? 'error' : undefined} allowClear /> {errors.username && ( {errors.username[0]} )}
{/* 密码 */}
} placeholder="密码" value={password} onChange={(e) => { setPassword(e.target.value); clearError('password'); }} iconRender={(visible) => (visible ? : )} onPressEnter={handleSubmit} status={errors.password ? 'error' : undefined} allowClear /> {errors.password && ( {errors.password[0]} )}
{/* 记住密码 / 自动登录 / 忘记密码 */}
{ const checked = e.target.checked; setRemember(checked); onRememberChange(checked); // 取消记住密码 → 同时取消自动登录 if (!checked) { setAutoLogin(false); onAutoLoginChange(false); } }} className="text-xs" > 记住密码 { const checked = e.target.checked; setAutoLogin(checked); onAutoLoginChange(checked); // 勾选自动登录 → 同时勾选记住密码 if (checked && !remember) { setRemember(true); onRememberChange(true); } }} className="text-xs" > 自动登录
onForgotPassword?.()}> 忘记密码?
{/* 用户协议 */}
{ setAgreed(e.target.checked); clearError('_agreement'); }} onKeyDown={(event)=>{ if (event.key === 'Enter' || event.keyCode === 13) { setAgreed(!agreed); } }} className="text-xs" > 已阅读并同意 { e.stopPropagation(); setLegalType('service'); }} > 《用户服务协议》 { e.stopPropagation(); setLegalType('points'); }} > 《积分充值服务协议》 {errors._agreement && ( {errors._agreement[0]} )}
{/* 登录按钮 */}
{/* 协议弹窗 */} {legalType && setLegalType(null)} />} ); }