1
This commit is contained in:
@@ -15,11 +15,11 @@ import {
|
||||
import {
|
||||
type AuthAuditLogEntry,
|
||||
type AuthCaptchaChallenge,
|
||||
authEntry,
|
||||
type AuthLoginMethod,
|
||||
type AuthRiskBlockSummary,
|
||||
type AuthSessionSummary,
|
||||
type AuthUser,
|
||||
authEntry,
|
||||
bindWechatPhone,
|
||||
changePassword,
|
||||
changePhoneNumber,
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
resetPassword,
|
||||
revokeAuthSession,
|
||||
sendPhoneLoginCode,
|
||||
setStoredLastLoginPhone,
|
||||
startWechatLogin,
|
||||
} from '../../services/authService';
|
||||
import { AccountModal } from './AccountModal';
|
||||
@@ -694,6 +695,7 @@ export function AuthGate({ children }: AuthGateProps) {
|
||||
setError('');
|
||||
try {
|
||||
const nextUser = await loginWithPhoneCode(phone, code);
|
||||
setStoredLastLoginPhone(phone);
|
||||
setLoginCaptchaChallenge(null);
|
||||
activateReadyUser(nextUser);
|
||||
} catch (loginError) {
|
||||
@@ -711,6 +713,7 @@ export function AuthGate({ children }: AuthGateProps) {
|
||||
setError('');
|
||||
try {
|
||||
const nextUser = await authEntry(username, password);
|
||||
setStoredLastLoginPhone(username);
|
||||
activateReadyUser(nextUser);
|
||||
} catch (loginError) {
|
||||
setError(
|
||||
@@ -727,6 +730,7 @@ export function AuthGate({ children }: AuthGateProps) {
|
||||
setError('');
|
||||
try {
|
||||
const nextUser = await resetPassword(phone, code, newPassword);
|
||||
setStoredLastLoginPhone(phone);
|
||||
activateReadyUser(nextUser);
|
||||
} catch (resetError) {
|
||||
setError(
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
AuthCaptchaChallenge,
|
||||
AuthLoginMethod,
|
||||
} from '../../services/authService';
|
||||
import { getStoredLastLoginPhone } from '../../services/authService';
|
||||
import { CaptchaChallengeField } from './CaptchaChallengeField';
|
||||
|
||||
type SmsScene = 'login' | 'reset_password';
|
||||
@@ -57,11 +58,9 @@ export function LoginScreen({
|
||||
onResetPassword,
|
||||
onStartWechatLogin,
|
||||
}: LoginScreenProps) {
|
||||
const [activeTab, setActiveTab] = useState<'login' | 'register'>('login');
|
||||
const [isResetPanelOpen, setIsResetPanelOpen] = useState(false);
|
||||
const [username, setUsername] = useState('');
|
||||
const [phone, setPhone] = useState(() => getStoredLastLoginPhone());
|
||||
const [password, setPassword] = useState('');
|
||||
const [phone, setPhone] = useState('');
|
||||
const [code, setCode] = useState('');
|
||||
const [resetPhone, setResetPhone] = useState('');
|
||||
const [resetCode, setResetCode] = useState('');
|
||||
@@ -154,75 +153,55 @@ export function LoginScreen({
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col gap-4 px-5 py-5">
|
||||
<div className="grid grid-cols-2 gap-2 rounded-full bg-[var(--platform-subpanel-bg)] p-1">
|
||||
<TabButton
|
||||
active={activeTab === 'login'}
|
||||
label="登录"
|
||||
onClick={() => setActiveTab('login')}
|
||||
/>
|
||||
<TabButton
|
||||
active={activeTab === 'register'}
|
||||
label="注册"
|
||||
onClick={() => setActiveTab('register')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{activeTab === 'login' ? (
|
||||
{passwordLoginEnabled ? (
|
||||
<form
|
||||
className="flex flex-col gap-4"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (!passwordLoginEnabled) {
|
||||
return;
|
||||
}
|
||||
void onPasswordSubmit(username, password);
|
||||
void onPasswordSubmit(phone, password);
|
||||
}}
|
||||
>
|
||||
{passwordLoginEnabled ? (
|
||||
<>
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>账号</span>
|
||||
<input
|
||||
className="platform-input"
|
||||
autoComplete="username"
|
||||
value={username}
|
||||
onChange={(event) => setUsername(event.target.value)}
|
||||
placeholder="用户名"
|
||||
/>
|
||||
</label>
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>密码</span>
|
||||
<input
|
||||
className="platform-input"
|
||||
autoComplete="current-password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
placeholder="输入密码"
|
||||
/>
|
||||
</label>
|
||||
</>
|
||||
) : null}
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>手机号</span>
|
||||
<input
|
||||
className="platform-input"
|
||||
autoComplete="tel"
|
||||
inputMode="numeric"
|
||||
value={phone}
|
||||
onChange={(event) => setPhone(event.target.value)}
|
||||
placeholder="13800000000"
|
||||
/>
|
||||
</label>
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>密码</span>
|
||||
<input
|
||||
className="platform-input"
|
||||
autoComplete="current-password"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(event) => setPassword(event.target.value)}
|
||||
placeholder="输入密码"
|
||||
/>
|
||||
</label>
|
||||
|
||||
{error ? <ErrorBanner message={error} /> : null}
|
||||
|
||||
{passwordLoginEnabled ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={submitDisabled || !username.trim() || !password.trim()}
|
||||
disabled={submitDisabled || !phone.trim() || !password.trim()}
|
||||
className="platform-button platform-button--primary h-12 px-4 text-base disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
{loggingIn ? '登录中' : '登录'}
|
||||
{loggingIn ? '登录中' : '注册/登录'}
|
||||
</button>
|
||||
) : null}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="self-center text-sm text-[var(--platform-accent)]"
|
||||
onClick={() => setIsResetPanelOpen(true)}
|
||||
>
|
||||
忘记密码
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="self-end text-sm text-[var(--platform-accent)]"
|
||||
onClick={() => setIsResetPanelOpen(true)}
|
||||
>
|
||||
忘记密码
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{wechatLoginEnabled ? (
|
||||
<WechatButton
|
||||
@@ -232,7 +211,9 @@ export function LoginScreen({
|
||||
/>
|
||||
) : null}
|
||||
</form>
|
||||
) : (
|
||||
) : null}
|
||||
|
||||
{phoneLoginEnabled ? (
|
||||
<PhoneCodeForm
|
||||
phone={phone}
|
||||
code={code}
|
||||
@@ -243,8 +224,9 @@ export function LoginScreen({
|
||||
loggingIn={loggingIn}
|
||||
error={error}
|
||||
hint={hint}
|
||||
submitLabel="注册并登录"
|
||||
submitLabel="注册/登录"
|
||||
enabled={phoneLoginEnabled}
|
||||
showPhoneField={!passwordLoginEnabled}
|
||||
onPhoneChange={setPhone}
|
||||
onCodeChange={setCode}
|
||||
onCaptchaAnswerChange={setCaptchaAnswer}
|
||||
@@ -262,7 +244,7 @@ export function LoginScreen({
|
||||
}}
|
||||
onSubmit={() => onPhoneSubmit(phone, code)}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
{!passwordLoginEnabled && !phoneLoginEnabled && !wechatLoginEnabled ? (
|
||||
<div className="platform-subpanel rounded-2xl px-4 py-4 text-sm text-[var(--platform-text-base)]">
|
||||
@@ -276,30 +258,6 @@ export function LoginScreen({
|
||||
);
|
||||
}
|
||||
|
||||
function TabButton({
|
||||
active,
|
||||
label,
|
||||
onClick,
|
||||
}: {
|
||||
active: boolean;
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={`h-10 rounded-full text-sm font-medium transition ${
|
||||
active
|
||||
? 'bg-[var(--platform-panel-bg)] text-[var(--platform-text-strong)] shadow-sm'
|
||||
: 'text-[var(--platform-text-muted)]'
|
||||
}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function PhoneCodeForm({
|
||||
phone,
|
||||
code,
|
||||
@@ -312,6 +270,7 @@ function PhoneCodeForm({
|
||||
hint,
|
||||
submitLabel,
|
||||
enabled,
|
||||
showPhoneField,
|
||||
onPhoneChange,
|
||||
onCodeChange,
|
||||
onCaptchaAnswerChange,
|
||||
@@ -329,6 +288,7 @@ function PhoneCodeForm({
|
||||
hint: string;
|
||||
submitLabel: string;
|
||||
enabled: boolean;
|
||||
showPhoneField: boolean;
|
||||
onPhoneChange: (value: string) => void;
|
||||
onCodeChange: (value: string) => void;
|
||||
onCaptchaAnswerChange: (value: string) => void;
|
||||
@@ -347,17 +307,19 @@ function PhoneCodeForm({
|
||||
void onSubmit();
|
||||
}}
|
||||
>
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>手机号</span>
|
||||
<input
|
||||
className="platform-input"
|
||||
autoComplete="tel"
|
||||
inputMode="numeric"
|
||||
value={phone}
|
||||
onChange={(event) => onPhoneChange(event.target.value)}
|
||||
placeholder="13800000000"
|
||||
/>
|
||||
</label>
|
||||
{showPhoneField ? (
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>手机号</span>
|
||||
<input
|
||||
className="platform-input"
|
||||
autoComplete="tel"
|
||||
inputMode="numeric"
|
||||
value={phone}
|
||||
onChange={(event) => onPhoneChange(event.target.value)}
|
||||
placeholder="13800000000"
|
||||
/>
|
||||
</label>
|
||||
) : null}
|
||||
|
||||
<label className="grid gap-2 text-sm text-[var(--platform-text-base)]">
|
||||
<span>验证码</span>
|
||||
|
||||
Reference in New Issue
Block a user