From 8171fc59b005fdcc71d97b799adcadb33b5e62d9 Mon Sep 17 00:00:00 2001 From: kdletters Date: Sat, 25 Apr 2026 23:23:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E9=87=8D=E5=BC=80=E7=8A=B6=E6=80=81=E6=AE=8B=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md | 1 + src/components/auth/AuthGate.test.tsx | 62 +++++++++++++++++++ src/components/auth/LoginScreen.tsx | 20 ++++++ 3 files changed, 83 insertions(+) diff --git a/docs/design/PLATFORM_HOME_PUBLIC_BROWSE_AND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md b/docs/design/PLATFORM_HOME_PUBLIC_BROWSE_AND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md index 8eac1260..2f6412bb 100644 --- a/docs/design/PLATFORM_HOME_PUBLIC_BROWSE_AND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md +++ b/docs/design/PLATFORM_HOME_PUBLIC_BROWSE_AND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md @@ -112,6 +112,7 @@ - 用户主动关闭弹窗时,只关闭弹窗,不改变当前平台页面 - 不清空首页浏览状态 - 不自动跳转到其他 tab +- 登录弹窗下次重新打开时必须恢复初始表单状态:回到默认登录页签、关闭重置密码面板、清空密码 / 验证码 / 图形验证码 / 提示 / 倒计时等本次草稿状态;只允许保留“最近一次成功登录手机号”的本地回填能力。 --- diff --git a/src/components/auth/AuthGate.test.tsx b/src/components/auth/AuthGate.test.tsx index cb879e3b..5b793f01 100644 --- a/src/components/auth/AuthGate.test.tsx +++ b/src/components/auth/AuthGate.test.tsx @@ -312,6 +312,68 @@ test('auth gate shows sms send feedback in the login modal', async () => { expect(within(dialog).getByRole('button', { name: '60s' })).toBeTruthy(); }); +test('login modal resets draft state every time it is reopened', async () => { + const user = userEvent.setup(); + + authMocks.getAuthLoginOptions.mockResolvedValue({ + availableLoginMethods: ['phone', 'password'], + }); + + render( + + + , + ); + + await user.click(await screen.findByRole('button', { name: '进入作品' })); + + const firstDialog = screen.getByRole('dialog', { name: '账号入口' }); + await user.type(within(firstDialog).getByLabelText('手机号'), '13800000000'); + await user.click(within(firstDialog).getByRole('button', { name: '获取验证码' })); + + expect( + await within(firstDialog).findByText('短信请求已提交,验证码有效期约 5 分钟。'), + ).toBeTruthy(); + await user.type(within(firstDialog).getByLabelText('验证码'), '123456'); + await user.click(within(firstDialog).getByRole('tab', { name: '密码登录' })); + await user.type(within(firstDialog).getByLabelText('密码'), 'passw0rd'); + await user.click(within(firstDialog).getByRole('button', { name: '忘记密码' })); + + expect( + screen.getByRole('dialog', { name: '重置密码' }), + ).toBeTruthy(); + + await user.click( + screen.getByRole('button', { name: '关闭登录弹窗' }), + ); + + await waitFor(() => { + expect(screen.queryByRole('dialog', { name: '账号入口' })).toBeNull(); + }); + + await user.click(screen.getByRole('button', { name: '进入作品' })); + + const reopenedDialog = screen.getByRole('dialog', { name: '账号入口' }); + expect( + within(reopenedDialog) + .getByRole('tab', { name: '短信登录' }) + .getAttribute('aria-selected'), + ).toBe('true'); + expect( + (within(reopenedDialog).getByLabelText('手机号') as HTMLInputElement).value, + ).toBe(''); + expect( + (within(reopenedDialog).getByLabelText('验证码') as HTMLInputElement).value, + ).toBe(''); + expect(within(reopenedDialog).queryByLabelText('密码')).toBeNull(); + expect( + within(reopenedDialog).queryByText('短信请求已提交,验证码有效期约 5 分钟。'), + ).toBeNull(); + expect( + within(reopenedDialog).getByRole('button', { name: '获取验证码' }), + ).toBeTruthy(); +}); + test('auth gate separates sms and password login by tabs', async () => { const user = userEvent.setup(); diff --git a/src/components/auth/LoginScreen.tsx b/src/components/auth/LoginScreen.tsx index 02aa9bb0..11634992 100644 --- a/src/components/auth/LoginScreen.tsx +++ b/src/components/auth/LoginScreen.tsx @@ -75,6 +75,26 @@ export function LoginScreen({ const wechatLoginEnabled = availableLoginMethods.includes('wechat'); const [activeLoginTab, setActiveLoginTab] = useState('phone'); + useEffect(() => { + if (!isOpen) { + return; + } + + // 每次重新打开弹窗都丢弃上一次未完成的表单草稿,只保留最近成功登录手机号回填。 + setIsResetPanelOpen(false); + setPhone(getStoredLastLoginPhone()); + setPassword(''); + setCode(''); + setResetPhone(''); + setResetCode(''); + setResetPasswordValue(''); + setCaptchaAnswer(''); + setCooldownSeconds(0); + setResetCooldownSeconds(0); + setHint(''); + setActiveLoginTab(phoneLoginEnabled ? 'phone' : 'password'); + }, [isOpen, phoneLoginEnabled]); + useEffect(() => { if (activeLoginTab === 'phone' && !phoneLoginEnabled && passwordLoginEnabled) { setActiveLoginTab('password');