feat(reports): 我的报告 enters on a static shell and joins the prefetch; 过往的报告 pages 10 at a time with 加载更多 (BUG-1123, BUG-1124)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-09-30 13:45:44 +08:00
co-authored by Claude Opus 5.5
parent 90b1b6fba9
commit 9a616107c2
14 changed files with 470 additions and 33 deletions
+27
View File
@@ -14963,3 +14963,30 @@
- 相关记录:BUG-1100(气泡引入)
- 修复版本:分支 `codex/notice-loading-polish-20260930`
## BUG-1123 | 点「我的报告」要等很久才进页
- 状态:resolved(代码 + 回归测试;待部署,真机体感待产品复核)
- 首次发现 / 最近更新:2026-09-30 / 2026-09-30
- 影响面:`frontend/src/app/(app)/reports/page.tsx`、`frontend/src/components/personal-report/personal-report-center.tsx`、`frontend/src/lib/secondary-page-data.ts`
- 现象:产品反馈「点击我的报告 跳转页面的时间很长」。
- 触发条件:从任一页面点侧栏「我的报告」。
- 根因:三段串行等待叠加,且用来掩盖等待的预取被丢弃。① 页面 `force-dynamic` 且无 `loading.tsx`,客户端跳转必须先等一轮服务端 RSC 渲染才切页(`/reports` 并不读 cookies,是纯客户端外壳;BUG-716 已把 `/chart` 改成静态外壳,`/reports` 当时没跟上,还被 `stale-client-recovery.test.ts` 钉住)。② 进页挂载时 `invalidateReportsPage()` 重置缓存,侧栏悬停 / 按下时已发出的 `GET /api/reports` 结果被作废,再发第二次同样的请求。③ 列表接口本身(登录校验 → 列表 → 失败段落)排在后面。
- 修复:去掉 `force-dynamic`,`/reports` 成为静态外壳;进页不再作废缓存:有缓存直接显示并后台重读,无缓存则加入正在进行的预取请求(同一 inflight)。删除行时仍作废缓存,旧 GET 不能让已删行复活。
- 验证:`report-list-paging-20260930.test.tsx`「entering 我的报告 joins the sidebar prefetch: one GET, not two」——预取后挂载只发 1 次 GET(修前 2 次);`report-row-delete.test.tsx` 删除后旧 GET 不复活仍通过;`stale-client-recovery.test.ts` 断言改为不再 force-dynamic(三栏注释)。未在真实 staging 计时,体感待产品复核。
- 防复发:次级页(chart / ephemeris / people / reports)一律静态外壳 + 客户端取数;进页 effect 不得 reset 共享缓存,只能 join 或后台重读。
- 相关记录:BUG-716、BUG-1104
- 修复版本:分支 `codex/reports-list-paging-20260930`
## BUG-1124 | 「过往的报告」只显示最新 20 份,更早的无法访问
- 状态:resolved(代码 + 回归测试;待部署)
- 首次发现 / 最近更新:2026-09-30 / 2026-09-30
- 影响面:`frontend/src/app/api/reports/route.ts`(GET)、`frontend/src/lib/report-cursor.ts`(新)、`personal-report-center.tsx`
- 现象:产品反馈「过往报告列表应该加一个分页」;核查发现接口写死 `.limit(20)` 且无游标,第 21 份起在列表里永远看不到。
- 根因:列表接口初版只按 `created_at desc` 取前 20 行,没有分页参数;前端一次性渲染全部返回行。
- 修复:`GET /api/reports?subject=&limit=10&before=<created_at,id>` 键集分页,按 `(created_at desc, id desc)` 排序、取 `limit + 1` 判断是否还有更多,返回 `{ reports, nextCursor }`;非法游标 400。不带 `limit` 视为首页 10 份(原为 20)。前端 10 份一批 +「加载更多」(产品选定);3 秒轮询与刷新只重读首页并合并到已展开的列表,不丢已加载的更早页;删除本地移除;换人物重置。`.or(created_at.lt…,and(…))` 与双 `.order` 的写法和 `/api/sessions` 游标同一套,自托管兼容层已在该接口上线使用。
- 验证:`report-list-paging-20260930.test.tsx` 7 条(游标编解码与 Date 行、接口源码合同、合并规则、客户端 URL 与 before、加载更多追加 / 加载中 / 到底隐藏、静态外壳与样式);前端全量 4,478 条,失败 24 条与基线逐条相同,无测试名消失。未跑 `test:db`(本轮不动表;游标查询写法与已上线的会话分页相同)。
- 防复发:列表接口不得用写死的上限代替分页;新列表按 `session-cursor` / `report-cursor` 的键集模式。
- 相关记录:BUG-1123
- 修复版本:分支 `codex/reports-list-paging-20260930`