Files
jiapuapp/docs/superpowers/plans/2026-07-14-g01-empty-state-consolidation.md
T
2026-07-14 17:36:43 +08:00

199 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
<view v-else class="genealogy-empty-state">
<view class="empty-panel">
<image class="empty-panel-skin" src="/static/assets/modules/genealogy/opaque/g01-empty-panel.png" mode="aspectFill" />
<view class="empty-panel-content">
<!-- 印章标题说明分隔纹创建与搜索动作 -->
</view>
</view>
</view>
```
按钮皮肤继续引用现有 `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 警告但无空白错误。