From d793b0e4c793bd116f1bcb8d4a9837baddb3eaec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E7=BE=BD=E7=A7=A6?= Date: Fri, 7 Aug 2026 20:46:08 +0800 Subject: [PATCH] =?UTF-8?q?Fix:=20=E5=8E=BB=E9=99=A4=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=BC=B9=E7=AA=97=E5=9B=9B=E8=A7=92=E4=B8=8D?= =?UTF-8?q?=E9=80=8F=E6=98=8E=E9=81=AE=E7=BD=A9=20(#144)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `before:` ![image.png](/attachments/fc0f1c7d-e722-46d4-8360-fd8069d6bb12) `after:` ![image.png](/attachments/3c0f0f95-c27f-4053-9ce2-55a11a56b580) --------- Co-authored-by: 段舒康 Co-authored-by: suzmii Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/144 Reviewed-by: 段舒康 Co-authored-by: 董羽秦 Co-committed-by: 董羽秦 --- docs/【项目基线】当前产品与工程约束-2026-05-15.md | 2 +- src/components/auth/AccountModal.test.tsx | 7 +++++++ src/components/auth/AccountModal.tsx | 14 +++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/docs/【项目基线】当前产品与工程约束-2026-05-15.md b/docs/【项目基线】当前产品与工程约束-2026-05-15.md index 082347839..efe687615 100644 --- a/docs/【项目基线】当前产品与工程约束-2026-05-15.md +++ b/docs/【项目基线】当前产品与工程约束-2026-05-15.md @@ -52,7 +52,7 @@ Genarrative / 陶泥儿是一个 AI 原生互动内容与小游戏平台。当 6. 小程序外壳注入到 H5 URL 的 `clientType`、`clientRuntime`、`miniProgramEnv` 是宿主上下文,H5 内部 `pushState` / 阶段导航必须跨页面保留,避免登录和充值误判为普通浏览器;首点时微信 JS bridge 可能尚未就绪,前端还需用 `MicroMessenger + miniProgram` User-Agent 作为小程序识别兜底。 7. 小程序 `web-view` 页必须启用好友分享与朋友圈分享,分享目标固定回到 `pages/web-view/index`,不把 H5 当前 URL 作为不受控启动参数传回小程序页。 8. 小程序 `web-view` 外壳运行时通过 `wx.getAccountInfoSync().miniProgram.envVersion` 自动识别版本:线上版 `release` 使用 `www.genarrative.world`,体验版 `trial` 与开发版 `develop` 使用 `dev.genarrative.world`;传给后端的 `x-mini-program-env` 分别为 `release`、`trial`、`dev`。 -9. 账号信息面板只展示 `账号信息` 标题;绑定手机号和绑定微信以紧凑模块展示当前绑定状态,已绑定手机号展示完整手机号,已绑定微信优先展示微信平台实际返回并由后端保存的 `wechatDisplayName`。小程序 `jscode2session` 不能直接返回微信昵称或个人微信号,只能稳定拿到当前小程序维度的 `openid`,并在满足微信开放平台条件时拿到 `unionid`;小程序昵称来自快捷登录后按需展示的原生 `input type="nickname"` 提交的 `displayName`。后端下发 `wechatAccount` 作为绑定账号标识,前端在没有真实昵称时展示微信账号尾号,不展示裸“已绑定”。换绑入口放在对应模块右上角,退出登录和退出全部设备固定放在面板内容最底部。 +9. 账号信息面板只展示 `账号信息` 标题;绑定手机号和绑定微信以紧凑模块展示当前绑定状态,已绑定手机号展示完整手机号,已绑定微信优先展示微信平台实际返回并由后端保存的 `wechatDisplayName`。小程序 `jscode2session` 不能直接返回微信昵称或个人微信号,只能稳定拿到当前小程序维度的 `openid`,并在满足微信开放平台条件时拿到 `unionid`;小程序昵称来自快捷登录后按需展示的原生 `input type="nickname"` 提交的 `displayName`。后端下发 `wechatAccount` 作为绑定账号标识,前端在没有真实昵称时展示微信账号尾号,不展示裸“已绑定”。换绑入口放在对应模块右上角,退出登录和退出全部设备固定放在面板内容最底部。直接打开账号信息时,外层弹窗只负责定位与可访问语义,保持无背景、无边框并允许内层阴影自然溢出;背景、边框、圆角、内容裁切和阴影统一由内层账号卡片承载,避免直角外壳在四角露出不透明底色或把圆角阴影裁成矩形。 10. H5 登录态从未登录变为已登录,或从已登录变为未登录后,必须刷新当前页面一次,确保推荐运行态、作品架、个人缓存和私有 query 都按新身份重新初始化;普通 access token 续期、账号资料更新和同一登录态内的设置变化不得触发整页刷新。 11. 同一账号允许多端同时在线。新增登录和单设备退出只影响对应 refresh session,不得提升账号级 `tokenVersion` 让其它设备的 access token 失效;只有“退出全部设备”、修改密码、重置密码等明确安全动作才吊销全端 refresh session 并提升 `tokenVersion`。 12. 手机号认证只支持中国大陆号码:验证码、密码登录、绑定、换绑和重置密码请求统一提交 `purePhoneNumber` 与可选 `countryCode`,省略国家码时默认 `86`,旧 `phone` 字段不再接受;显式国家码必须为无加号的 `86`,其他值返回“仅支持中国大陆手机号(+86)”。主站输入框保留 `autocomplete="tel"` 与浏览器默认电话号码回填能力,认证 service 把浏览器可能回填的 `+86 1xxxxxxxxxx` 或 `86 1xxxxxxxxxx` 拆成 `{ countryCode: "86", purePhoneNumber: "1xxxxxxxxxx" }` 后提交。微信小程序手机号授权必须使用微信真实返回的 `countryCode + purePhoneNumber`,不得套用普通请求的缺省国家码。后端分别验证国家码和纯号码后再生成 E.164 存储;前端校验只提供即时反馈,`inputMode="numeric"` 也只提示软键盘布局。 diff --git a/src/components/auth/AccountModal.test.tsx b/src/components/auth/AccountModal.test.tsx index 6acf6ad3b..72960bb2c 100644 --- a/src/components/auth/AccountModal.test.tsx +++ b/src/components/auth/AccountModal.test.tsx @@ -166,7 +166,14 @@ test('direct account entry does not render the settings shell as another dialog' renderAccountModal({ entryMode: 'account' }); const accountDialog = screen.getByRole('dialog', { name: '账号信息' }); + const accountBody = accountDialog.firstElementChild as HTMLElement | null; + const accountWrapper = accountBody?.firstElementChild as HTMLElement | null; expect(accountDialog).toBeTruthy(); + expect(accountDialog.style.background).toBe('none'); + expect(accountDialog.style.borderWidth).toBe('0px'); + expect(accountDialog.className).toContain('!overflow-visible'); + expect(accountBody?.className).toContain('!overflow-visible'); + expect(accountWrapper?.className).toContain('overflow-visible'); expect(screen.queryByRole('dialog', { name: '设置与账号安全' })).toBeNull(); expect(screen.queryByText('设置与账号安全')).toBeNull(); expect( diff --git a/src/components/auth/AccountModal.tsx b/src/components/auth/AccountModal.tsx index 5012da2a6..f2ba747dd 100644 --- a/src/components/auth/AccountModal.tsx +++ b/src/components/auth/AccountModal.tsx @@ -518,18 +518,26 @@ export function AccountModal({ authCardClassName={isDirectAccountMode ? '' : undefined} panelClassName={ isDirectAccountMode - ? 'relative !max-w-3xl !rounded-none !bg-transparent !shadow-none' + ? 'relative !max-w-3xl !overflow-visible !rounded-none !bg-transparent !shadow-none' : 'relative !h-[min(100%,calc(100vh-2rem))] !max-w-5xl !rounded-[28px] !p-5 sm:!p-6' } - bodyClassName="!flex !min-h-0 !flex-1 !overflow-hidden !p-0" + bodyClassName={`!flex !min-h-0 !flex-1 !p-0 ${ + isDirectAccountMode ? '!overflow-visible' : '!overflow-hidden' + }`} panelStyle={{ maxHeight: ACCOUNT_MODAL_MAX_HEIGHT, + ...(isDirectAccountMode + ? { + background: 'none', + borderWidth: 0, + } + : {}), }} >