This commit is contained in:
2026-05-01 16:08:19 +08:00
parent dce84f677d
commit 14208ccb64
15 changed files with 752 additions and 175 deletions

View File

@@ -10,7 +10,7 @@ import { getStoredLastLoginPhone } from '../../services/authService';
import { CaptchaChallengeField } from './CaptchaChallengeField';
type SmsScene = 'login' | 'reset_password';
type LoginTab = 'phone' | 'password' | 'register';
type LoginTab = 'phone' | 'password';
type LoginScreenProps = {
isOpen: boolean;
@@ -21,8 +21,6 @@ type LoginScreenProps = {
wechatLoading: boolean;
error: string;
captchaChallenge: AuthCaptchaChallenge | null;
initialMode?: 'login' | 'register';
initialInviteCode?: string;
onClose: () => void;
onSendCode: (
phone: string,
@@ -35,11 +33,7 @@ type LoginScreenProps = {
cooldownSeconds: number;
expiresInSeconds: number;
}>;
onPhoneSubmit: (
phone: string,
code: string,
inviteCode?: string,
) => Promise<void>;
onPhoneSubmit: (phone: string, code: string) => Promise<void>;
onPasswordSubmit: (phone: string, password: string) => Promise<void>;
onResetPassword: (
phone: string,
@@ -58,8 +52,6 @@ export function LoginScreen({
wechatLoading,
error,
captchaChallenge,
initialMode = 'login',
initialInviteCode = '',
onClose,
onSendCode,
onPhoneSubmit,
@@ -74,7 +66,6 @@ export function LoginScreen({
const [resetPhone, setResetPhone] = useState('');
const [resetCode, setResetCode] = useState('');
const [resetPasswordValue, setResetPasswordValue] = useState('');
const [inviteCode, setInviteCode] = useState(initialInviteCode);
const [captchaAnswer, setCaptchaAnswer] = useState('');
const [cooldownSeconds, setCooldownSeconds] = useState(0);
const [resetCooldownSeconds, setResetCooldownSeconds] = useState(0);
@@ -97,23 +88,16 @@ export function LoginScreen({
setResetPhone('');
setResetCode('');
setResetPasswordValue('');
setInviteCode(initialInviteCode);
setCaptchaAnswer('');
setCooldownSeconds(0);
setResetCooldownSeconds(0);
setHint('');
setActiveLoginTab(
initialMode === 'register' && phoneLoginEnabled
? 'register'
: phoneLoginEnabled
? 'phone'
: 'password',
);
}, [initialInviteCode, initialMode, isOpen, phoneLoginEnabled]);
setActiveLoginTab(phoneLoginEnabled ? 'phone' : 'password');
}, [isOpen, phoneLoginEnabled]);
useEffect(() => {
if (
(activeLoginTab === 'phone' || activeLoginTab === 'register') &&
activeLoginTab === 'phone' &&
!phoneLoginEnabled &&
passwordLoginEnabled
) {
@@ -215,7 +199,7 @@ export function LoginScreen({
{phoneLoginEnabled ? (
<div
className={`grid gap-2 ${
passwordLoginEnabled ? 'grid-cols-3' : 'grid-cols-2'
passwordLoginEnabled ? 'grid-cols-2' : 'grid-cols-1'
}`}
role="tablist"
aria-label="登录方式"
@@ -234,12 +218,6 @@ export function LoginScreen({
</LoginTabButton>
) : null}
<LoginTabButton
active={activeLoginTab === 'register'}
onClick={() => setActiveLoginTab('register')}
>
</LoginTabButton>
</div>
) : null}
@@ -338,42 +316,6 @@ export function LoginScreen({
/>
) : null}
{phoneLoginEnabled && activeLoginTab === 'register' ? (
<PhoneCodeForm
phone={phone}
code={code}
inviteCode={inviteCode}
captchaAnswer={captchaAnswer}
captchaChallenge={captchaChallenge}
cooldownSeconds={cooldownSeconds}
sendingCode={sendingCode}
loggingIn={loggingIn}
error={error}
hint={hint}
submitLabel="注册"
enabled={phoneLoginEnabled}
showPhoneField
showInviteCodeField
onPhoneChange={setPhone}
onCodeChange={setCode}
onInviteCodeChange={setInviteCode}
onCaptchaAnswerChange={setCaptchaAnswer}
onSendCode={async () => {
setHint('');
const result = await onSendCode(phone, 'login', {
challengeId: captchaChallenge?.challengeId,
answer: captchaAnswer,
});
setCooldownSeconds(result.cooldownSeconds);
setHint(
`短信请求已提交,验证码有效期约 ${Math.max(1, Math.round(result.expiresInSeconds / 60))} 分钟。`,
);
setCaptchaAnswer('');
}}
onSubmit={() => onPhoneSubmit(phone, code, inviteCode)}
/>
) : null}
{!passwordLoginEnabled &&
!phoneLoginEnabled &&
!wechatLoginEnabled ? (
@@ -420,7 +362,6 @@ function LoginTabButton({
function PhoneCodeForm({
phone,
code,
inviteCode = '',
captchaAnswer,
captchaChallenge,
cooldownSeconds,
@@ -431,17 +372,14 @@ function PhoneCodeForm({
submitLabel,
enabled,
showPhoneField,
showInviteCodeField = false,
onPhoneChange,
onCodeChange,
onInviteCodeChange,
onCaptchaAnswerChange,
onSendCode,
onSubmit,
}: {
phone: string;
code: string;
inviteCode?: string;
captchaAnswer: string;
captchaChallenge: AuthCaptchaChallenge | null;
cooldownSeconds: number;
@@ -452,10 +390,8 @@ function PhoneCodeForm({
submitLabel: string;
enabled: boolean;
showPhoneField: boolean;
showInviteCodeField?: boolean;
onPhoneChange: (value: string) => void;
onCodeChange: (value: string) => void;
onInviteCodeChange?: (value: string) => void;
onCaptchaAnswerChange: (value: string) => void;
onSendCode: () => Promise<void>;
onSubmit: () => Promise<void>;
@@ -486,19 +422,6 @@ function PhoneCodeForm({
</label>
) : null}
{showInviteCodeField ? (
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
<span></span>
<input
className="platform-input"
autoComplete="off"
value={inviteCode}
onChange={(event) => onInviteCodeChange?.(event.target.value)}
placeholder="邀请码"
/>
</label>
) : null}
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
<span></span>
<div className="flex gap-3">