feat(reports): drop the report centre intro; docs for self edit and account menu (S3+S4)

「我的报告」 starts at 报告记录: the supporting paragraph and the overview
line are gone. CHANGELOG, DESIGN, the real-device checklist and PROGRESS
for TASK-self-edit-avatar-menu-20260928.

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-29 00:50:22 +08:00
co-authored by Claude Opus 5.5
parent c15def0c50
commit cfed06822f
8 changed files with 155 additions and 47 deletions
+7
View File
@@ -1,5 +1,12 @@
# 印度占星 Skill 更新日志
## 2026-09-28 — 星盘档案能改自己的资料、每页点头像都弹账户菜单、我的报告去掉顶部说明(待验收)
- 星盘档案里「本人」也有「编辑」了:和家人同一张表,能改称呼、出生日期与时间、出生地、岁差和性别;本人仍然不能删除。此前全站找不到改自己出生资料的地方(BUG-1081)。改完后首页、星盘页、星历按新资料重读。
- 星盘、星历、我的报告、星盘档案这几页,点左下角头像不再直接回首页,而是弹出和首页一样的账户菜单。切换主题当场生效;点「个人资料」「通用设置」「账户与点数」「退出登录」会回到首页并直接打开对应的窗口,刷新或返回不会再弹一次。
- 「我的报告」顶部那段「有填报到分钟的出生时间即可生成……」说明和「共 N 份 · 已完成 N 份」一行去掉,页面直接从「报告记录」开始。
- Skill 版本不 bump(Skill 文本未改)。不改数据库结构。
## 2026-09-28 — 「那一刻的天空」第三轮:只放图、印出生日期时刻城市、过场放慢、兑换弹窗改时机(待验收)
- 星盘页点「那一刻的天空」:去掉灰色面板和标题栏,压暗的页面上只放这张图,按屏幕大小完整显示;图下一个「保存图片」,右上角一个小 ×,点图外或按 Esc 也能关。
@@ -0,0 +1,106 @@
# PROGRESS · 星盘档案本人编辑、各页头像菜单、我的报告去说明(2026-09-28)
任务书:`docs/tasks/TASK-self-edit-avatar-menu-20260928.md`。产品授权直接执行(Claude 子代理)。
- 基线:`origin/staging` = `adbb2054`(birth-sky-polish 已推 staging 后开工,串行)
- 分支 / 工作树:`codex/self-edit-avatar-menu-20260928` / `.worktrees/self-edit-avatar-menu-20260928`(三个本地提交,**未推送**)
- 环境:Node v22.14.0(`/exec-daemon/node`);系统 `python3`;无 Docker;无头 Chrome(本机 `/dev/shm` 只有 64MB,需 `--disable-dev-shm-usage`)
- BUG 编号:开工时最大 BUG-1080;本单 BUG-1081
## 结论
| 项 | 结果 | 提交 |
| --- | --- | --- |
| S1 本人可在星盘档案编辑(BUG-1081) | 完成 | 1 |
| S2 各页头像弹账户菜单 | 完成 | 2 |
| S3 我的报告去掉顶部说明区 | 完成 | 3 |
| S4 文档(DESIGN、VOICE、CHANGELOG、BUG_HISTORY、真机清单、索引、本文件) | 完成(DESIGN / VOICE 随 S1、S2 各自提交,见偏离 1) | 1–3 |
| 让步 | 未砍:只读模式余额照常显示;弹窗在首页 `hydrated && account` 后打开 | — |
## S1 · 本人可编辑(BUG-1081)
- `lib/self-profile-save.ts`:`selfProfilePatchBody`(原 `persistProfile` 的载荷,带 `birth_time_source`,**不带** `gender`)、`saveSelfProfile`(`PATCH /api/account`,返回应用服务端出生时间真值后的资料与 `chartBirth.fingerprint`)、`saveSelfGender`(单字段 `{ gender }`)。
- 首页 `use-profile-onboarding.ts` 的 `persistProfile` 改用 `saveSelfProfile`(行为不变)。无 UI 调用的 `saveProfile` 删除;它独用的 hook 参数 `setBirthTimeConsultationConsent`、`setRectificationError` 从 hook 类型与 `page.tsx` 调用处一并移除(`page.tsx` 里这两个 state 仍被别处使用)。
- `people-page.tsx`:本人详情底部「本人不能删除」下面加「编辑」;编辑视图与他人同一张 `ChartProfileForm`,标题「编辑我的资料」、说明「称呼和出生资料。」,无删除区。`saveSelf`:出生资料 `saveSelfProfile(draft)`,性别变了再 `saveSelfGender`;然后 `pinChartSnapshotIdentity`(星盘缓存按新指纹失效)、`clearHomeWarmSnapshot`(首页暖快照与今日卡)、`invalidateEphemerisPage`、布局 provider `setAccount`(资料与 `chartBirth.fingerprint`)、`invalidateSubjectCatalog` 后重读列表。失败时表单里显示服务端文案,没有就「保存失败,请重试」。
- 编辑他人后原来只 `invalidateSubjectCatalog` + 重读(已核实);本人多出的几项是因为本人资料还活在布局 provider、首页暖快照和星盘 / 星历缓存里。
- 删掉详情「性别」下的小字「在「设置 → 个人资料」里改」和它的 CSS 规则 `.people-archive-fact-note`。
- `.people-archive-foot` 加 `gap`、`justify-items: center`(灰字与按钮上下排)。
## S2 · 各页头像弹账户菜单
- `lib/account-dialog-intent.ts`:`/?account=profile|general|billing|logout` 的生成与解析,其他值一律忽略。
- `app-sidebar.tsx`:页脚在两种模式都是同一个 `Menu.Root`(全文件只有一个)。首页由 `controls` 控制开合,四项 `Menu.Item` 就地开弹窗;其他页菜单自持开合状态(`useState`,在 `AppSidebar` 里,不在 `Home()`),四项是 `Menu.LinkItem` + `AppLink` 到 `/?account=<dialog>`,点了收起手机抽屉。主题菜单不变、就地生效。余额「N 点」来自布局 provider 的账户,只读模式照常显示。账户还没读到时页脚是同尺寸的静态块(无链接、无转圈);未登录仍是「去登录」。
- `people-home-links.tsx` 新增 `AccountDialogDeepLink`:挂载时读一次 `?account=`、立刻 `replaceState` 去掉(非法值也去掉),`ready` 后调用 `openAccountDialog`(billing 带 `source: "account-menu"`,与首页菜单一致),之后不再触发。`page.tsx` 只多一行接线(import 合在同一行)。
- `page.tsx`:1364 → 1363 行;`Home()` 的 `useState` / `useRef` 数不变(未新增)。
## S3 · 我的报告
- 删 `.report-center-hero` 整段(说明段 + 统计行)与只给它用的 `latestReady`(`useMemo` import 随之移除);`hasGenerating` 仍给轮询用,保留。`globals.css` 删 `.report-center-hero*`、`.report-center-meta` 与移动端那条规则。生成按钮的 `title` 不动。
## 截图(本地宿主页,虚构资料,交付构建的编译 CSS)
- `/tmp/claude-1000/-workspace-Jyotisha/fb88e01e-1ced-4bcc-92fe-44c5bdcc878e/scratchpad/selfedit/people-menu-1280x800.png`(/people 本人详情,底部「本人不能删除」+「编辑」;侧栏账户菜单展开)
- 同目录 `people-menu-390x844.png`(手机抽屉里展开账户菜单)
- 两张图 CDP 读回:菜单四个弹窗项的 href 依次为 `/?account=profile|general|billing|logout`,无横向滚动。宿主页用 esbuild 打包真实组件,`next/navigation`、`next/link` 用本地 shim(未提交)。
## 验证
| 项 | 基线 `adbb2054` | 交付(第 3 个提交) |
| --- | --- | --- |
| `tsc --noEmit` | 0 错 | 0 错 |
| `npm run lint` | 0 error / 127 warning(polish 验收记录) | 0 error / 126 warning |
| `npm test` | tests 4322 · pass 4267 · fail 24 · cancelled 0 · skipped 31 | tests 4334 · pass 4279 · fail 24 · cancelled 0 · skipped 31 |
| 失败清单 | 24 条(Docker / PostgreSQL / 部署套件) | 与基线逐条同名 |
| 测试名对比(`frontend/AGENTS.md` 方法) | — | 消失 1(改名,见下表)、新增 13 |
| `python3 -m pytest tests/test_repo_privacy_markers.py` | — | 63 passed |
| `rm -rf .next && next build` | `/` ○ Static | `/` ○ Static;路由表与基线逐行相同 |
| `page.tsx` 行数 / `Home()` state·ref 数 | 1364 / — | 1363 / 不变 |
未跑 Python 快速门:本单没有改 `scripts/**` 或 `tests/**`(Python)。
### 首屏 gzip(`index.html` 引用的 `/_next/static/*.js|css` 逐个 gzip -9 求和;基线在临时 detached 工作树同机同脚本干净构建)
| | 基线 `adbb2054` | 交付 | 变化 |
| --- | ---: | ---: | ---: |
| JS | 650,972 B | 651,520 B | +548 B(+0.08%) |
| CSS | 66,126 B | 66,031 B | −95 B(−0.14%) |
JS 增量是首页 bundle 里的 `AccountDialogDeepLink`、`account-dialog-intent` 与侧栏只读菜单分支;CSS 减少是删掉的报告中心说明区与 `.people-archive-fact-note`。
## 改动的既有断言(原值 / 新值 / 原因,测试文件里同样写了注释)
| 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `sidebar-contract` · read-only when `/` is not mounting it | 只读页脚是 `<AppLink className="profile-trigger" href="/">` | 不再有页脚链接;全文件一个 `Menu.Root`,两种模式都渲染;只读弹窗项是 `AppLink` 到 `accountDialogHref(dialog)` | S2 产品决定 |
| `home-warm-return-lifecycle` · warm return to bare / … | `followLink("林遥,打开账户")` | 断言页脚不再是该链接;用等价站内跳转 `followHref("/")`(记下目标再路由,与 `AppLink` 同步骤) | S2;测试守的是「暖回裸 `/` 落空白首页」 |
| `new-chat-from-people-lifecycle` · stashed rectification … not reopened | 等并点只读页脚链接回 `/` | 等页脚菜单按钮出现、断言无该链接,`followHref("/")` 回 `/` | 同上 |
| `new-chat-from-people-lifecycle` 测试工具 `button(label)` | 取第一个文本含 label 的按钮 | 跳过 `.profile-trigger`(页脚菜单按钮也含本人名字) | S2 后页脚是按钮;不改断言,只避免点错元素 |
| `profile-gender-ui` · detail card(**改名**:`…本人 points to 设置 → 个人资料` → `…本人 edits it in the same form as everyone`) | 本人 `<dd>未填<small …>在「设置 → 个人资料」里改</small></dd>`,本页无本人性别单选 | 本人 `<dd>未填</dd>`;详情卡无单选,本人编辑视图有 | BUG-1081 |
| `profile-gender-ui` · CSS 类清单 | 含 `people-archive-fact-note` | 去掉(类与规则已删) | BUG-1081 |
| `settings-mvp-contract` · chart library owns self-profile editing | `onSubmit={(event) => void saveOther(event)}` | `editingSelf ? saveSelf(event) : saveOther(event)`,且 `await saveSelfProfile(draft)` | BUG-1081 |
| `people-archive-regressions` · people delete … | `title={selectedId ? "编辑人物" : "添加一个人"}` | 前面多一档 `editingSelf ? "编辑我的资料"` | BUG-1081 |
| `consultation-entrypoint` · profile and place saves do not auto-start … | 切出 `saveProfile` 断言不评估 | 断言首页无 `saveProfile`;切出 `/people` 的 `saveSelf` 断言不评估 | `saveProfile` 删除 |
| `profile-onboarding-birth-sky-reveal` · only own onboarding place save triggers | 切出 `saveProfile` 断言不含 `onOwnBirthPlaceSaved` | 断言首页无 `saveProfile`(people-page 不触发由下方原循环锁住) | 同上 |
| `birth-time-consultation-consent` · source-aware consultation options | `match(page, /birthTimeConsultationOptionsCopy\(savedProfile\)/)` | `doesNotMatch`;录入表单那条断言不动 | 这句只在已删的 `saveProfile` 保存提示里 |
| `birth-time-guided-review-fixes` · terminal CJK copy … | `match` 「出生资料已保存。${…(savedProfile)}」 | `doesNotMatch`;其余断言不动 | 同上 |
| `personal-report-entry` · global report copy … | 报告中心源码四条 `match`(分钟即可生成 / 需要具体分钟 / 与某一次对话无关 / 后台继续处理) | 四条 `doesNotMatch`,另断言无 `report-center-hero` / `report-center-meta` / 报告概览;按钮 `title` 断言不动 | S3 |
测试工具改动(非断言):`tests/home-surface.ts` 的首页源码清单加 `src/lib/self-profile-save.ts`(`persistProfile` 的载荷与 `applyPersistedBirthTime` 行搬到这里,`profile-persistence` 的原断言继续命中);两份生命周期测试新增 `followHref` 帮手。
## 偏离任务书
1. **DESIGN / VOICE 随各自的 S1、S2 提交**,不全压在 S3+S4:AGENTS §7.5 要求改 UI 的提交同时更新 DESIGN。S4 提交里是 S3 的 DESIGN、CHANGELOG、真机清单、索引与本文件。
2. **首页 `saveProfile` 连带删掉两个 hook 参数**(`setBirthTimeConsultationConsent`、`setRectificationError`),它们只被 `saveProfile` 用;否则会留下未使用的参数。
3. **本人保存成功后不再显示「出生资料已保存。…」提示**:那句只在已无 UI 的 `saveProfile` 里;星盘档案保存后直接回到已更新的详情。若产品想要一句确认,另开单(详情卡现有的 notice 是错误样式,不宜复用)。
4. **本人编辑视图说明写「称呼和出生资料。」**,没写他人那句「填报的出生时间保存后不能再改」——本人资料走账户接口,可以再改。
## 另发现(不在本单范围,未改)
- **封面城市取不到**:库里中国地点标签以「中国 · 」开头(`lib/geoapify-location-service.ts` 生成 `中国 · 省 · 市 · 区`),而 polish 单的 `lib/birth-sky/caption.ts` `birthSkyCity` 要求第一段是省级名,遇到「中国」直接返回 null。所以中国出生地的封面实际只会印到时刻、不带城市。该代码已在 staging(`adbb2054`)。
- 账户接口在 `birth_time_status = confirmed` 时,声明字段变化不会重置状态(`resolveAccountBirthTimeApplicationPatch` 直接返回 `{}`),这是既有语义,本单未动;本人在星盘档案改时间后若原来是 confirmed,排盘仍按 confirmed 的时间。建议产品确认是否符合预期。
## 环境缺口
- 无登录态与真机:本人编辑的真实保存、跳首页开弹窗、手机抽屉行为只在单测、源码合同与本地宿主页截图上验证;真机清单 `docs/testing/self-edit-avatar-menu-20260928.md`(17 条)。
- 无 Docker:24 条 DB / 部署套件失败与基线逐条同名。
- 未推送、未部署。
+1 -1
View File
@@ -251,7 +251,7 @@
| `TASK-birth-sky-cover-20260928.md` | `PROGRESS-birth-sky-cover-20260928.md` | **「那一刻的天空」封面**:出生那一刻头顶的真实天空做成 3:4 封面(产品从 A 年轮 / B 一笔画 / C 天空三版样稿中选 C,样稿 `assets/birth-sky-cover-sample-20260928.html`);星盘页按钮 + 保存图片、报告封面(须对得上报告出生资料)、首次建盘揭幕;不印出生资料、句库只描述天空、无新依赖 | 已验收(Claude 2026-09-28),随分支五个提交推 staging;T5 由追加单解除 | 新功能,不开 BUG |
| `TASK-birth-sky-followup-20260928.md` | `PROGRESS-birth-sky-cover-20260928.md`(追加单) | **天空封面追加**:报告封面按生成时出生资料指纹绑定(方案 A,旧报告永不显示);首次建盘揭幕改群星汇聚过场(无按钮、3 秒预算、可点跳过、减弱动态只淡入淡出) | 已验收(Claude 2026-09-28),已推 staging | 新功能,不开 BUG |
| `TASK-birth-sky-polish-20260928.md` | `PROGRESS-birth-sky-polish-20260928.md` | **天空封面第三轮**:星盘页弹层只留图;封面印「日期 时刻 · 城市」(推翻「不印出生资料」);过场放慢到约 6.5 秒;兑换弹窗改到首条付费消息被拒(402)时再弹;BUG-1080 过场被兑换弹窗挡住 | 已实现待验收(分支 `codex/birth-sky-pacing-20260928`,未推送);BUG-1080 investigating(Chrome 下「弹窗盖住过场」已排除,修复不依赖根因) | BUG-1080 |
| `TASK-self-edit-avatar-menu-20260928.md` | `PROGRESS-self-edit-avatar-menu-20260928.md` | **本人可编辑 + 各页头像菜单 + 报告页去说明**:`/people` 本人可编辑出生资料(BUG-1081,`ab6c55f8` 漏掉);次级页头像弹同一账户菜单、弹窗项跳 `/?account=`;我的报告删顶部说明与统计 | 待领取(须等 birth-sky-polish 推 staging 后串行) | BUG-1081 起 |
| `TASK-self-edit-avatar-menu-20260928.md` | `PROGRESS-self-edit-avatar-menu-20260928.md` | **本人可编辑 + 各页头像菜单 + 报告页去说明**:`/people` 本人可编辑出生资料(BUG-1081,`ab6c55f8` 漏掉);次级页头像弹同一账户菜单、弹窗项跳 `/?account=`;我的报告删顶部说明与统计 | 已实现待验收(分支 `codex/self-edit-avatar-menu-20260928`,未推送) | BUG-1081 |
| `TASK-serif-headings-20260928.md` | `PROGRESS-serif-headings-20260928.md` | **全站标题改用自托管宋体、正文保持黑体**:产品推翻 BUG-737「CJK 不用衬线」结论(保留「声明的字体必须可加载」「不落系统宋体」两条);Noto Serif SC SemiBold 按通用规范汉字表 6500 字 unicode-range 切片自托管(改名 Jyotisha Serif SC),swap 不 preload;首页宋体流量 ≤300 KB;先于天空封面单 | 已实现待验收(分支 `codex/serif-headings-20260928`,未推送) | 不开新 BUG;BUG-737 追加说明 |
| `TASK-cend-ui-claude-alignment-20260916.md` | `PROGRESS-cend-ui-r1/r2/r3-20260916.md` | **C 端界面向 claude.ai 产品界面对齐(三轮串行 R1→R2→R3,都动 `globals.css`,不得并行)**:根因是 `frontend/CLAUDE_DESIGN.md` 扒的是 **claude.com 营销官网**,它自己在 Known Gaps 里写明 claude.ai 产品界面不在范围内,而 `DESIGN.md:3` 把它当成了产品界面的实现契约。**R1**:`--font-display` 里 Tiempos Headline / StyreneB **从未加载**(无 `@font-face`、`public/` 无字体、`layout.tsx` 只 vendor 了 Inter),中文标题全站落到 **宋体 / SimSun**,波及 20 处含助手回答的 h2/h3(BUG-737);亮色强调色 `#85432f` 与暗色 `#d78064` 不同源,产品拍板亮色换 **Claude coral `#cc785c`**,**易漏点**是 `globals.css:16` 的 `--color-ring` 硬编码在 `@theme inline` 里不跟随 `:root`,另有第四个 `:root` 亮色块(`:4358`)必须同步(BUG-738);`.composer-footer` 常驻 44px + 顶栏 68px + `--composer-reserve` 148px,每屏固定吃掉 216px,模型选择器移进输入框内部、删掉底栏、顶栏收到 46px 并删「分析对象」副标题。**R2**:空状态是营销落地页(hero 卡 + 两张 132px 入口大卡 + 3 列 156px 主题卡),输入框被压在 **800px 以上**内容之下,重排成「问候 + 居中输入框 + 两枚入口 pill + 一排 chip」。**R3**:侧栏两个 `<details>` 拍平成一条「最近」、星盘的两个入口(侧栏分组 + 账户菜单)收敛到一处、删掉逐条助手头像。**决策记录 D3 推翻 DESIGN.md「报告强调色与应用同源」一句**(报告刻意保留深棕)。原型图 https://claude.ai/code/artifact/da275da6-2954-4f50-99aa-32bb8694d38b(三套画面 + 明暗,页面标题就是建议字体栈的实际渲染)。环境缺口:无登录态无 Chrome,四项真机观感留 `docs/testing/`。BUG 段 737–738 | 待领取 | — |
| `TASK-cend-surfaces-claude-alignment-20260916.md` | `PROGRESS-cend-shell-20260916.md`、`PROGRESS-cend-report-20260916.md`、`PROGRESS-cend-rectification-20260916.md`、`PROGRESS-cend-chart-eph-20260916.md` | **次级页面对齐(上一单的续篇,R4→R5/R6,R7、R8 可并行)**:星盘 `/chart`、星历 `/ephemeris`、报告 `/reports` **各是脱离 app 外壳的独立全屏页**,顶部只有一个「返回对话」链接、侧栏整个消失,且三家各写了一套一模一样的 `*-shell`/`*-topbar`/`*-hero` 骨架——与上一单 E5 同根因(营销站 band 结构被套到产品界面)。**R4** 抽只读导航外壳 `AppNavRail`(只用现成的 `GET /api/sessions` + `GET /api/account`,会话行走 `sessionHref` 跳 `/?c=<uuid>`;**刻意不带**重命名/删除/收藏/归档——那套连着 `Home()` 的乐观更新与回滚,搬过来会撞 useState 增长门禁)。**R5** 星盘五 tab 下划线化 + 参数合表 + 行星表横向滚动;星历日期导航改 `‹ 日期 ›`。**R6** 报告中心卡片网格改行式列表;阅读页加常驻目录。**R7** 生时校正把可信区间从盘面板标题行提成常驻条(窄屏 `.is-compact` 下盘面板是 overlay,现在默认看不到区间),五个 `technique-audit` 折叠块收成两段。**R8** 设置内容区收窄(880px 弹窗里表单铺了 690px)、套餐卡三修饰符收敛成两态。**已解锁**:原挡路的设置单已于 `111b4a84`(BUG-698)合入。**两条不得回退**:BUG-698 的 `@supports (height: 1dvh)` 写法(重复声明回退会被 Lightning CSS 折叠)、BUG-616/617 的报告盘面 grid 实现。默认不占 BUG 号 | **R4–R8 全部已实现并验收合入** | R4:抽出 `AppNavRail`(只读,两个 GET,零写操作)+ `SecondaryShell`,三个次级页并入 app 外壳并删掉各自的 shell/topbar/hero;四个路由渲染标记**完全不变**(`/` `/chart` `/ephemeris` 仍 Static);CSS gzip −0.25%。`/reports/[reportId]` 留给 R6 与目录一起做。两处自身健壮性问题被测试抓到:`usePathname()` 可为 null、`fetch` 可能不存在。差点弄丢 BUG-717 的 eyebrow 文案(已放回)。R8:表单分区收窄到 440px(列表分区不变)、套餐卡三修饰符收敛成互斥的 `is-current` / `is-recommended`,`--highlighted` 删除改为滚动定位;手机端 `order:-1` 改挂 `[data-plan-alias]`(版位不是状态)。测试 3350→3354(净增 4),失败清单与基线逐条一致;`/` 仍 Static;我的干净构建实测 CSS gzip −3 字节。**遗留待产品拍板**:`?plan=` 深链现在完全没有视觉指向,只有滚动位置。R6:报告中心卡片网格改行式列表、阅读页并入外壳并把目录挪到右侧常驻。**任务书 E10 过期**——目录在 `cfcd369d` 就已存在,本轮是挪位置定稿而非从零加。挂外壳带出一个真实打印风险已处理:`.chat-app`/`.chat-panel` 是 `height:100%;overflow:hidden`,裸 `window.print()` 会把九节报告裁成一页,阅读页因此多挂一条只在挂载期生效的 print 样式解锁外壳。「生成中的分节进度」做不了——`REPORT_LIST_COLUMNS` 不返回节数,按 VOICE.md 不许前端编。R7:区间常驻条与盘面折叠收敛。**任务书 E9 也不准确**——对话区顶部早有常驻条 `RectificationTimeline` 且窄屏可见,真正只在盘面标题行的是**代表分钟**;因此没另造第二条,在既有条上补齐代表分钟与已答题数(与盘面同一次 `workingRectificationTime()` 调用)。折叠块实际是 **8 个**不是 5 个。**触发让步顺序第 5 条**:收窄进度未做——服务端无该字段,且 `candidate_range` 会放宽(BUG-572),前端相减会把一次放宽报成收窄,已写进 `BLOCKED.md`。顺带修掉一个**静默失效的旧断言**(`slice(indexOf(A), indexOf(B))` 在 B 改名后变成几乎整份文件,四条 `doesNotMatch` 假通过)|
@@ -0,0 +1,29 @@
# 真机清单 · 星盘档案本人编辑、各页头像菜单、我的报告去说明(2026-09-28)
任务书:`docs/tasks/TASK-self-edit-avatar-menu-20260928.md`。自动化只覆盖了单元测试、源码合同与本地无头 Chrome 样张;下面这些需要登录态在 staging 真机上走一遍。只用自己的测试账号,不要截取真实出生资料发到任何地方。
## 星盘档案 · 本人可编辑(BUG-1081)
1. 打开「星盘档案」,点「本人」那一行:详情底部是灰字「本人不能删除」,下面有「编辑」。
2. 点「编辑」:标题「编辑我的资料」,表单里有称呼、出生日期与时间、出生地、岁差、性别;底部没有「删除这个人」。
3. 把出生时间改动几分钟(或改出生地),点「保存」:回到详情,填报时间 / 出生地已是新值。
4. 从侧栏回首页,再打开「星盘」:星盘按新时间重排(上升或行星宫位跟着变)。
5. 回到「星盘档案」再把时间改回原值并保存,确认同样生效。
6. 只改性别(女 / 男 / 不填)并保存:详情「性别」一行跟着变;出生资料不受影响。
7. 故意清空出生地再保存:「保存」按钮不可点(资料不完整时不提交)。
8. 家人的「编辑」与「删除这个人」照旧可用。
## 各页头像弹账户菜单
9. 在「星盘」「星历」「我的报告」「星盘档案」四页各点一次左下角头像:都弹出账户菜单(头像、名字、邮箱、个人资料、通用设置、账户与点数、主题、退出登录),不会直接跳走。
10. 在任一次级页用菜单里的主题切换浅色 / 深色:当场生效,页面不跳。
11. 在「星盘」页点「账户与点数」:回到首页,点数窗口自动打开;关掉后刷新页面,不会再弹。
12. 在「我的报告」点「个人资料」、在「星历」点「通用设置」:各自回首页并打开对应窗口。
13. 在「星盘档案」点「退出登录」:回首页弹出退出确认。
14. 手机上(侧栏抽屉打开时)点头像再点「账户与点数」:抽屉收起,回首页打开点数窗口。
15. 侧栏折叠时(桌面)点头像:菜单在右侧弹出。
## 我的报告
16. 打开「我的报告」:顶部没有「有填报到分钟的出生时间即可生成……」那段说明,也没有「共 N 份 · 已完成 N 份」一行,直接是「报告记录」。
17. 右上角「生成完整报告」照常可用。
+2 -2
View File
@@ -561,7 +561,7 @@ one skeleton, none of them carrying the sidebar.
### Personal report centre
- **Structure:** inside the app shell, not a page of its own. The name 「我的报告」 sits in the 46px header with 「生成完整报告」 as the header's one action; the body is supporting copy, the overview line, then the **row list** of reports.
- **Structure:** inside the app shell, not a page of its own. The name 「我的报告」 sits in the 46px header with 「生成完整报告」 as the header's one action; the body starts straight at 「报告记录」 and the **row list** of reports. The supporting paragraph (「有填报到分钟的出生时间即可生成……」) and the 「共 N 份 · 已完成 N 份」 overview line above it were removed on 2026-09-28 (TASK-self-edit-avatar-menu-20260928 S3, product: 「这里的提示去掉」); the minute requirement still lives in the 生成 button's hover title.
It used to be a standalone full-screen route with a `report-center-shell` root, a `report-center-topbar` holding one 「返回对话」 link, and a `report-center-hero` with a page-sized h1 — the sidebar vanished the moment you opened it, and the only way back was that link.
- **Row list, not a card grid:** `.report-center-list` is one column of `.report-center-row`, hairline-separated by a 1px grid gap over a `--color-border` ground so each boundary is a single rule rather than two touching borders. A card grid costs one scan per card; past five or six reports the reader is looking for state, and a single column puts every status chip on the same x. D12.
- **Row anatomy:** status chip, then the title at `--type-title-md`/500, then the meta line (creation time · depth · themes) at `--type-caption` with `tabular-nums`, then — for a ready report — its stored card summary, or for a failed one the failure reason. Actions sit right-aligned on the same row and wrap under the body at the global 767px cut.
@@ -697,7 +697,7 @@ page. Three parts now, in reading order:
- **Pane menu states:** default is transparent with secondary ink; hover is a 55% wash of `--color-canvas-muted` keeping secondary ink; current is the solid muted surface with primary ink. No accent bar, no trailing navigation chevron, and no weight change — hierarchy here comes from ink rank and surface, matching “Hierarchy inside the nav comes from ink rank, not hue”. The sidebar's 2px `--sidebar-ring` on the active session is deliberately **not** changed to match; the two surfaces read differently on purpose until that is revisited.
- **Content width:** the 880px frame now gives the content pane a deliberate inset instead of leaving controls against the divider. Form panes (个人资料, 通用设置) cap their children at 560px and stay left aligned (`.settings-dialog-content--form > *`); list panes (星盘资料, 账户与点数) stay full-bleed within the inset so tables and card grids keep their columns. The cap sits on the children of the scroll container only — never on `.settings-modal` or `.account-settings-shell` — so it cannot make the frame resize between panes (BUG-554 / BUG-698).
- **Personal profile:** one row of avatar editing (56px preview, eight palettes, 换一个形象) plus nickname and login email. Below them sits **性别(选填)** (2026-09-27, TASK-consult-gender-optional): three 44px choices 女 / 男 / 不填 in one row (the birth-time range chip look: `--color-border`, selected `--color-action` border + `--color-action-soft`), then one caption line 「用于婚恋解读里判断夫星 / 妻星,不填也能用。」. A choice saves at once (like the avatar palette) and shows 「已保存。」; the choices are disabled while saving, no spinner. This is the only place the owner sets it; onboarding never asks. The header uses the product-level “设置” eyebrow above the current pane title; there is no duplicate 管理星盘资料 button.
- **Chart archive (`/people`):** a static secondary page beside 星盘 / 星历 / 我的报告. Self is the first row and cannot be deleted. Each other row is a name plus birth facts, with no relationship field. Detail shows the reported time and the chart time separately, then place and ayanamsa. Shortcuts are 和 TA 对话, 看星盘, 生成报告, and 和我合盘. Adding a sixth person is disabled with 「最多保存 5 个人的星盘」. Delete confirms with the session and report counts before the server removes them together. There is no 「设为默认」 and no 「当前默认」 badge.
- **Chart archive (`/people`):** a static secondary page beside 星盘 / 星历 / 我的报告. Self is the first row and cannot be deleted, but is edited here like everyone else (2026-09-28, BUG-1081). Each other row is a name plus birth facts, with no relationship field. Detail shows the reported time and the chart time separately, then place and ayanamsa. Shortcuts are 和 TA 对话, 看星盘, 生成报告, and 和我合盘. Adding a sixth person is disabled with 「最多保存 5 个人的星盘」. Delete confirms with the session and report counts before the server removes them together. There is no 「设为默认」 and no 「当前默认」 badge.
- **Subject switcher:** the same control sits beside the title on chat, chart, ephemeris, reports, and the archive. It is not in the sidebar header. Choosing someone in a chat that already has messages switches the current person and opens an empty chat. An empty chat rebinds in place. The list shows at most five people.
- **States:** open, pane switch, list / self / other / add, saving, success, and error.
+1 -25
View File
@@ -3738,8 +3738,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
.payment-qr-badge { position: absolute; top: 50%; left: 50%; display: grid; width: 44px; height: 44px; padding: 4px; transform: translate(-50%, -50%); border: 4px solid #fff; border-radius: 12px; background: #fff; box-shadow: 0 2px 10px rgb(0 0 0 / 18%); }
.payment-qr-badge svg { display: block; width: 100%; height: 100%; }
/* Global report centre — quiet archive, independent from chat sessions. */.report-center-hero,
.report-center-section{
/* Global report centre — quiet archive, independent from chat sessions. */.report-center-section{
width: min(900px, 100%);
margin-inline: auto;
}.report-center-section-heading button:focus-visible,
@@ -3750,28 +3749,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
}.report-center-section-heading button svg,
.personal-report-back svg,
.personal-report-action-end svg{ width: 16px; height: 16px; }
.report-center-hero {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: end;
gap: var(--space-8);
padding: var(--space-10) 0 var(--space-8);
}
.report-center-hero > div { max-width: 760px; }
.report-center-hero > div > p:not(.report-center-meta) {
max-width: 660px;
margin: var(--space-4) 0 0;
color: var(--color-ink-secondary);
font-size: var(--type-body-md);
line-height: 1.65;
text-wrap: pretty;
}
.report-center-meta {
margin: var(--space-4) 0 0;
color: var(--color-ink-tertiary);
font-size: var(--type-caption);
line-height: 1.4;
}
.report-center-section-heading {
display: flex;
align-items: center;
@@ -3951,7 +3928,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
.report-center-message p { margin: 0; color: var(--color-ink-secondary); font-size: var(--type-body-sm); }
@media (max-width: 767px) {
.report-center-hero { grid-template-columns: 1fr; align-items: start; gap: var(--space-6); padding-block: var(--space-8) var(--space-6); }
.report-center-row { grid-template-columns: 1fr; gap: var(--space-3); }
.report-center-row-actions { justify-content: flex-start; justify-self: start; }
.report-center-failure { justify-self: start; }
@@ -3,7 +3,7 @@
import { AppLink } from "@/components/app-link";
import { Clock3, FileText, RefreshCw } from "lucide-react";
import { InlineSpinner } from "@/components/inline-spinner";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { SecondaryPageShell } from "@/components/secondary-page-shell";
import { readCurrentSubjectScope, useCurrentSubjectScope, useCurrentSubjectReady } from "@/lib/current-subject";
@@ -127,11 +127,6 @@ export function PersonalReportCenter() {
onPoll: refresh,
});
const latestReady = useMemo(
() => state.reports.find((report) => report.status === "ready") ?? null,
[state.reports],
);
const removeReport = useCallback((id: string) => {
deletedIds.current.add(id);
invalidateReportsPage();
@@ -161,15 +156,6 @@ export function PersonalReportCenter() {
actions={<GeneratePersonalReportButton onCreated={() => void load()} />}
>
<div className="report-center-body">
<section className="report-center-hero">
<div>
<p>有填报到分钟的出生时间即可生成;未校正会标明为方向性参考。只有日期和时段时,完整本命报告需要具体分钟,生时校正可选。与某一次对话无关。创建后会在后台继续处理,你无需停留等待。</p>
<p className="report-center-meta" aria-label="报告概览">
共 {state.reports.length} 份 · 已完成 {state.reports.filter((report) => report.status === "ready").length} 份 · {hasGenerating ? "有报告生成中" : latestReady ? "最新报告可查看" : "尚待生成"}
</p>
</div>
</section>
<section className="report-center-section">
<div className="report-center-section-heading">
<h2>报告记录</h2>
+8 -4
View File
@@ -185,10 +185,14 @@ test("no birth data or chat text is sent from the entry component", () => {
test("global report copy uses the canonical profile, allows an unrectified minute, and makes background work explicit", () => {
assert.match(componentSource, /authenticated user's canonical profile/);
assert.match(reportCenterSource, /有填报到分钟的出生时间即可生成/);
assert.match(reportCenterSource, /完整本命报告需要具体分钟/);
assert.match(reportCenterSource, /与某一次对话无关/);
assert.match(reportCenterSource, /后台继续处理/);
// 原值: 报告中心顶部说明段必须含「有填报到分钟的出生时间即可生成」「完整本命报告需要具体分钟」「与某一次对话无关」「后台继续处理」四句(四条 match)
// 新值: 四句都不再出现(doesNotMatch),顶部说明区与统计行整块删除;生成按钮的 title 仍说明分钟要求(下方断言不动)
// 原因: TASK-self-edit-avatar-menu-20260928 S3——产品要求「我的报告」去掉顶部提示,页面从「报告记录」列表开始
assert.doesNotMatch(reportCenterSource, /有填报到分钟的出生时间即可生成/);
assert.doesNotMatch(reportCenterSource, /完整本命报告需要具体分钟/);
assert.doesNotMatch(reportCenterSource, /与某一次对话无关/);
assert.doesNotMatch(reportCenterSource, /后台继续处理/);
assert.doesNotMatch(reportCenterSource, /report-center-hero|report-center-meta|报告概览/);
assert.match(componentSource, /根据已保存的具体出生分钟生成完整报告/);
assert.doesNotMatch(reportCenterSource, /基于你已确认的出生资料生成/);
assert.doesNotMatch(componentSource, /根据已确认的个人出生资料生成完整报告/);