fix: 「我的」页无法滚动 —— 缺滚动容器;顺带修矮屏登录页

用户反馈「我的页面点击进入后无法滑动」。

## 根因:AccountPage 根本没有滚动容器

窄屏外壳是 `h-full flex flex-col overflow-hidden`,页面本身是
`flex-1 min-w-0 flex flex-col`,中间缺一层 `overflow-y-auto` ——
内容超出的部分**直接被裁**,滚不到也点不到。

实测 390px 下内容(资料 + 权限 + 改密码 + 密钥 + 退出)需 860px、容器只有
795px,「退出登录」按钮连同下面 65px 一起消失;1280x800 的桌面上同样看不到。

其余六个页面级组件(AdminUsersPage / MailView / ComposePage / ThreadView /
ContactPanel / MailList)都有这一层,只有它漏了 —— 上一轮把退出登录搬进这页
之后内容变高,问题才显形。

## 顺带:登录页与初始化页在矮屏滚不到底

卡片高约 371px,而 `h-full flex items-center` 在内容超高时让它上下**同时**溢出,
溢出到顶部那段是滚不到的(`scrollTop` 最小是 0)—— 实测 568x280(横屏手机,
或软键盘弹出后的可视高度)下「登录」按钮完全在视口外,光加 `overflow-y-auto`
也够不着。

改用卡片自己的 `my-auto` 而不是容器的 `items-center`:auto margin 在空间不足时
自动退化为 0,矮屏变成正常的顶对齐可滚布局,高屏仍然垂直居中
(390x844 与 1280x800 实测 centered=true,568x280 下滚到底能看到按钮)。

## 两侧都加了检查

- 结构断言:七个页面级组件都必须含 `overflow-y-auto`;
  登录/初始化页必须有 `my-auto` 且不用 `h-full ... items-center`
- 实测脚本新增 `scrollHealth()`:每页都有滚动容器,且没有内容被
  `overflow-hidden` 的父级裁掉

判据刻意是「**有**滚动容器」而不是「当前正在滚动」—— 内容暂时不够高时后者
为假,但页面是健康的;真正的 bug 是根本没有那一层。

## 验证

窄屏实测 18 项 + 宽屏回归 5 项全通过;结构断言从 28 条扩到 37 条。
生产已部署。
This commit is contained in:
2026-09-03 07:39:52 +08:00
parent 342282b92c
commit 514f443e54
8 changed files with 282 additions and 133 deletions

View File

@ -1374,11 +1374,28 @@ MVP 计划(Phase 1-6)已全部落地并在 systemd 部署态实测通过。
窄屏改为每级 10px、上限 5 级
- [x] 对话树补返回出口:原先只有「关闭」,而两者语义不同 ——
返回退出整个详情栏,关闭只收起树留在这封邮件上
- [x] **`AccountPage` 根本没有滚动容器**(用户反馈「我的页进去后无法滑动」)。
窄屏外壳是 `h-full flex flex-col overflow-hidden`、页面是
`flex-1 flex flex-col`,中间没有一层 `overflow-y-auto` ——
内容超出的部分**直接被裁**,滚不到也点不到。
实测 390px 下内容需 860px、容器 795px,「退出登录」连同下面 65px 一起消失;
1280x800 的桌面上同样看不到。其余六个页面级组件都有这一层,只有它漏了
- [x] 登录页与初始化页在**矮屏**(横屏手机、软键盘弹出后)滚不到底:
卡片高约 371px,而 `h-full flex items-center` 在内容超高时让它上下**同时**
溢出,溢出到顶部那段滚不到(`scrollTop` 最小是 0)。实测 568x280 下
「登录」按钮完全在视口外。改用卡片自己的 `my-auto` —— auto margin 在
空间不足时自动退化为 0,于是矮屏变成正常的顶对齐可滚布局,
而高屏仍然垂直居中(390x844 与 1280x800 实测 centered=true)
验证:`web/test/manual/`(`npm run test:narrow` / `test:wide`)
窄屏 13 项 + 宽屏 5 项全通过;结构性断言从 20 条扩到 28 条,
窄屏 18 项 + 宽屏 5 项全通过;结构性断言从 20 条扩到 37 条,
把每一条修复都钉住。
滚动那一项两边都加了检查:结构断言查「七个页面级组件都含 overflow-y-auto」,
实测脚本的 `scrollHealth()` 查「每页都有滚动容器且没有内容被 overflow-hidden
的父级裁掉」。判据刻意是「**有**滚动容器」而不是「当前正在滚动」——
内容暂时不够高时后者为假,但页面是健康的。
那套脚本刻意留在仓库里而不是用完就删:结构性断言守不住「按钮实际多大、
点下去命中谁」,而这次最严重的 bug 恰好只有 `elementFromPoint` 能发现。
它不进 `npm test` —— 要一个跑着的浏览器加一个活的 Gateway。
@ -1389,8 +1406,8 @@ MVP 计划(Phase 1-6)已全部落地并在 systemd 部署态实测通过。
- 前端有 Markdown XSS 与窄屏结构性回归,但没有**渲染组件跑断言**的测试
- 深色主题未做
- 窄屏已用 playwright 在 390/320px 实测过(7.10.1),但那套脚本是临时的、
没有进 CI;日常回归仍只有读源码的结构性断言
- 窄屏实测脚本已入库(`web/test/manual/`),但没进 CI ——
要一个 headless 环境加一个测试用 Gateway 实例
- 登录限速与新建会话限速已改为 DB 事务(rate_limits 表),多实例部署不再各自计数
- SQLite 抄送查询走 `json_each` 全表展开,无索引;单机量级下够用,
百万级邮件时需要加物化列或换回 PostgreSQL