# G01 无家谱状态合并实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 删除独立的 G02 页面路由,让“无家谱”成为 G01 在 `?state=empty` 下可复现、可验证的页面状态,同时保持 G01 默认已验收列表画面不变。 **Architecture:** `pages/genealogy/g01-my-genealogies.vue` 是“我的家谱”状态的唯一所有者:默认路由继续读取现有示例家谱数据,`state=empty` 只覆盖 `hasGenealogies` 的演示状态。G01 的空状态使用已生成的完整位图面板和现有按钮位图;G02 路由、专属实现、测试与已失效的专属交接材料删除。 **Tech Stack:** uni-app Vue 3、Vue Composition API、PowerShell 合约测试、Chrome DevTools 截图脚本、Node.js 运行时冒烟测试。 ## Global Constraints - 不修改 G01 默认“已有家谱”状态的可见效果,也不修改已验收的 A01、A02、A04、A05、A06。 - 可审计路由/视觉结构改动必须先有最小失败契约测试;行为验证必须覆盖默认与空状态。 - 空状态完整面板、按钮边框和装饰面使用位图资产,不以 CSS 伪造。 - 不执行 `git add`、`git commit`、`git push`、`git reset` 或 worktree 操作。 - 仅删除本项目此前为独立 G02 创建、且在迁移后无引用的文件;保留最终位图并改为 G01 所属名称。 --- ### Task 1: 建立 G01 空状态与路由收敛契约 **Files:** - Create: `tests/g01-empty-state-contract.ps1` - Modify: `tests/full-page-visual-contract.ps1` - Test: `tests/g01-empty-state-contract.ps1` **Interfaces:** - Consumes: `pages.json` 路由注册、`pages/genealogy/g01-my-genealogies.vue`、`static/assets/modules/genealogy/opaque/g01-empty-panel.png`。 - Produces: 证明 G01 是唯一入口、`state=empty` 是唯一空状态开关、并且 57 条已注册路由为新的页面契约的静态测试。 - [x] **Step 1: 写失败的合约测试** 在 `tests/g01-empty-state-contract.ps1` 断言: ```powershell Assert-True ($pages.paths -contains 'pages/genealogy/g01-my-genealogies') 'G01 route missing' Assert-True (-not ($pages.paths -contains 'pages/genealogy/g02-empty-genealogies')) 'G02 route must be removed' Assert-Match $g01Source 'forceEmptyState' 'G01 must own the explicit empty state' Assert-Match $g01Source 'state.*empty' 'G01 must parse state=empty' Assert-Match $g01Source 'g01-empty-panel\.png' 'G01 must use its final raster empty panel' Assert-Match $g01Source 'empty-create-action' 'G01 must expose create action in empty state' Assert-Match $g01Source 'empty-search-action' 'G01 must expose search action in empty state' Assert-NoCssSurface $g01Source 'empty-panel' Assert-NoCssSurface $g01Source 'empty-create-action' Assert-NoCssSurface $g01Source 'empty-search-action' ``` 并在 `tests/full-page-visual-contract.ps1` 中把期望页面数和完整清单收敛为 57 条,移除 G02。 - [x] **Step 2: 运行测试确认失败** Run: `powershell -ExecutionPolicy Bypass -File tests/g01-empty-state-contract.ps1` Expected: FAIL,指出 G02 仍在路由表中,且 G01 尚未拥有 `forceEmptyState` 和最终 `g01-empty-panel.png`。 - [x] **Step 3: 记录失败原因** 失败不是视觉问题:现有 `pages.json` 将 G02 作为第二个页面注册,且现有 G01 空分支没有 URL 状态开关。这证明需要迁移所有权,而不是额外保留一个“空状态页面”。 ### Task 2: 将空状态实现迁移到 G01 **Files:** - Modify: `pages/genealogy/g01-my-genealogies.vue` - Modify: `pages.json` - Move: `static/assets/modules/genealogy/opaque/g02-empty-panel-v2.png` to `static/assets/modules/genealogy/opaque/g01-empty-panel.png` - Test: `tests/g01-empty-state-contract.ps1` **Interfaces:** - Consumes: `state=empty` 路由参数和现有 G01 的 `createGenealogy()`、`applyToJoin()`。 - Produces: 默认 G01 保持有家谱;`/pages/genealogy/g01-my-genealogies?state=empty` 展示带“创建我的家谱”和“搜索并申请加入”动作的空状态。 - [x] **Step 1: 实现最小路由状态所有权** 在 G01 里引入 `forceEmptyState`,在 `onLoad` 和 `onShow` 中同步当前页面 `options.state`(H5 时从 hash 查询串读取)。只用它定义: ```js const hasGenealogies = computed(() => !forceEmptyState.value && list.value.length > 0) ``` 默认路由不携带 `state=empty`,因此继续走现有已验收列表分支。 - [x] **Step 2: 替换 G01 的旧 CSS 空状态表面** 仅替换 `v-else` 空状态内容为: ```vue ``` 按钮皮肤继续引用现有 `a01-primary-button.png` 与 `a01-secondary-button.png`。使用 `empty-create-action`、`empty-search-action` 等新类名,不能改动现有列表中 `.create-action` 的已验收样式;这两个动作分别继续调用 `createGenealogy()` 与 `applyToJoin()`。 - [x] **Step 3: 移除独立 G02 入口** 从 `pages.json` 删除 `pages/genealogy/g02-empty-genealogies`,删除 `pages/genealogy/g02-empty-genealogies.vue`,并将最终位图重命名为 `g01-empty-panel.png`。不保留 G02 兼容路由或重定向。 - [x] **Step 4: 运行静态契约确认通过** Run: `powershell -ExecutionPolicy Bypass -File tests/g01-empty-state-contract.ps1` Expected: PASS,且 `powershell -ExecutionPolicy Bypass -File tests/full-page-visual-contract.ps1` 输出 57 条路由清单通过。 ### Task 3: 验证真实页面状态与动作 **Files:** - Create: `tests/g01-empty-state-runtime-smoke.js` - Test: `tests/g01-empty-state-runtime-smoke.js` **Interfaces:** - Consumes: Chrome DevTools `http://localhost:9222` 与开发服务器 `http://localhost:5173`。 - Produces: 默认 G01 列表、空状态、创建跳转和搜索跳转的运行时证据。 - [x] **Step 1: 写运行时测试** 测试在同一浏览器中依序验证: ```js await open('/#/pages/genealogy/g01-my-genealogies?state=empty') await waitFor('.genealogy-empty-state .empty-create-action') await click('.empty-create-action') assertPath('/pages/genealogy/g03-create-genealogy') await open('/#/pages/genealogy/g01-my-genealogies?state=empty') await click('.empty-search-action') assertPath('/pages/genealogy/g06-search-genealogies') await open('/#/pages/genealogy/g01-my-genealogies') assertExists('.current-slip') assertMissing('.genealogy-empty-state') ``` - [x] **Step 2: 运行运行时测试确认通过** Run: `node tests/g01-empty-state-runtime-smoke.js http://localhost:5173` Expected: PASS,证明两个空状态动作可用,且不带参数的 G01 仍为默认列表。 ### Task 4: 截图审视、清理与交接同步 **Files:** - Modify: `docs/交接记录.md` - Modify: `docs/规划.md` - Modify: `docs/design/P00_页面结构与资产清单.md` - Modify: `docs/design/2026-07-14_页面与状态合并审计.md` - Delete: `tests/g02-empty-genealogies-contract.ps1` - Delete: `tests/g02-empty-genealogies-runtime-smoke.js` - Delete: `docs/design/G02_无家谱空状态_设计记录.md` - Delete: `docs/superpowers/specs/2026-07-14-g02-empty-genealogies-design.md` - Delete: `docs/superpowers/plans/2026-07-14-g02-empty-genealogies.md` - Delete: `docs/design/screens/runtime/2026-07-14/G02-before-360x800.png` - Delete: `docs/design/screens/runtime/2026-07-14/G02-before-412x915.png` - Delete: `docs/design/screens/runtime/2026-07-14/G02-after-360x800.png` - Delete: `docs/design/screens/runtime/2026-07-14/G02-after-412x915.png` - Delete: `docs/design/screens/runtime/2026-07-14/G01-G02-comparison-360x800.png` - Create: `docs/design/screens/runtime/2026-07-14/G01-empty-after-360x800.png` - Create: `docs/design/screens/runtime/2026-07-14/G01-empty-after-412x915.png` - Create: `docs/design/screens/runtime/2026-07-14/G01-default-after-360x800.png` - Create: `docs/design/screens/runtime/2026-07-14/G01-default-before-after-360x800.png` **Interfaces:** - Consumes: G01 的两种可达状态、迁移后的 57 路由契约、审计前的 `route-audit/G01-360x800.png`。 - Produces: 同一视口的默认态前后对比、空状态截图、无过期 G02 入口和准确的交接记录。 - [x] **Step 1: 截图并做同图对比审视** 在 360×800 截默认 G01 和 `state=empty`,在 412×915 截空状态;把迁移前 `route-audit/G01-360x800.png` 与迁移后默认图并排为一张对比图。使用图像查看确认默认态没有发生可见改动,并确认空状态不出现透明黑角、裁切或 CSS 伪造表面。 - [x] **Step 2: 清除过期 G02 资料** 在 `rg` 确认没有其余活跃引用后,删除仅属于独立 G02 的路由实现、测试、计划、设计记录和旧截图。保留路线审计里的总览截图,避免抹除先前审计证据。 - [x] **Step 3: 更新真实状态** 文档统一为:已注册路由 57 条;G01 默认列表仍已验收;G01 `state=empty` 已实现和截图验证、等待用户对新增状态的审美确认;下一项合并仍是 G04→G03,尚未开始。 - [x] **Step 4: 完成回归验证** Run: ```powershell powershell -ExecutionPolicy Bypass -File tests/g01-empty-state-contract.ps1 node tests/g01-empty-state-runtime-smoke.js http://localhost:5173 powershell -ExecutionPolicy Bypass -File tests/full-page-visual-contract.ps1 powershell -ExecutionPolicy Bypass -File tests/visual-asset-compliance.ps1 powershell -ExecutionPolicy Bypass -File tests/a01-landing-contract.ps1 powershell -ExecutionPolicy Bypass -File tests/a02-login-contract.ps1 powershell -ExecutionPolicy Bypass -File tests/a04-forgot-password-contract.ps1 powershell -ExecutionPolicy Bypass -File tests/a05-register-contract.ps1 powershell -ExecutionPolicy Bypass -File tests/a06-auth-status-contract.ps1 git diff --check ``` Expected: 全部通过;`git diff --check` 允许 CRLF 警告但无空白错误。