Files
jiapuapp/docs/superpowers/plans/2026-07-14-g06-search-flow-consolidation.md
T
2026-07-14 17:36:43 +08:00

11 KiB
Raw Blame History

G06 搜索流程合并 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 将 G07 搜索结果收敛到 G06 的页面内三态,并保持搜索、无结果和申请入口可验证。

Architecture: pages/genealogy/g06-search-genealogies.vue 作为唯一流程拥有者,初始、加载、结果、无结果均由本地响应式状态切换;结果点选仅进入保留的 G08 路由。G07 文件和路由完全删除;公开检索是单步任务,直接在页面纸纹上放置独立的输入框与按钮位图,结果项复用现有 GenealogyCard 位图框架。

Tech Stack: uni-app、Vue 3 <script setup>、现有 mock appApi、PowerShell 静态契约、Chrome DevTools Protocol 冒烟测试、ImageGen 位图资产。

Global Constraints

  • 不改动 A01、A02、A04、A05、A06、G01、G03 已验收的可见效果。
  • 不使用 CSS 绘制检索面板、结果卡、按钮、边框或装饰面;只定位完整位图资产和真实交互控件。
  • 不执行 git addgit commitgit push、重置或 worktree 操作;保留现有未提交改动。
  • 本轮完成后路由总数必须为 55,G07 不得保留兼容入口。

Task 1: 写入并确认 G06 收敛契约(RED)

Files:

  • Create: tests/g06-search-flow-contract.ps1
  • Create: tests/g06-search-flow-runtime-smoke.js

Interfaces:

  • Consumes: G06 路由、g06-search-genealogies.vue、新面板资产和 Chrome 调试端 9222

  • Produces: 对 G06 唯一路由、四态、G08 导航、位图表面以及四条核心交互的可重复检查。

  • Step 1: 写静态失败契约

if ($paths -contains 'pages/genealogy/g07-search-result') { throw 'G07 route must be removed' }
if (Test-Path $g07File) { throw 'G07 page file must be deleted' }
foreach ($required in @('const searchState = ref("initial")', 'searchState.value = "results"', 'searchState.value = "empty"', '/pages/genealogy/g08-join-application?genealogyId=', 'g06-search-input.png', 'g06-search-button.png', 'search-hero')) {
  Assert-Contains $g06 $required "Missing G06 flow contract: $required"
}
  • Step 2: 运行静态契约,确认因 G07 和新状态/资产尚不存在而失败

Run: powershell -ExecutionPolicy Bypass -File tests/g06-search-flow-contract.ps1

Expected: FAIL,错误直接指向仍存在的 G07 或缺少的 G06 状态/资产。

  • Step 3: 写运行时失败冒烟
await openG06(send)
await waitFor(send, "Boolean(document.querySelector('.search-initial'))", 'G06 initial state did not render')
if (await valueOf(send, "Boolean(document.querySelector('.genealogy-card'))")) throw new Error('G06 initial state must not reveal a result card')
await setSearchKeyword(send, '汤')
await waitFor(send, "Boolean(document.querySelector('.genealogy-card'))", 'G06 matching search did not render a result card')
await setSearchKeyword(send, '不存在的家谱')
await waitFor(send, "Boolean(document.querySelector('.search-empty'))", 'G06 empty search state did not render')
  • Step 4: 运行冒烟,确认因初始态选择器尚不存在而失败

Run: node tests/g06-search-flow-runtime-smoke.js http://localhost:5173

Expected: FAIL with G06 initial state did not render

Task 2: 制作并验证 G06 独立检索资产

Files:

  • Create: static/assets/modules/genealogy/opaque/g06-search-input.png
  • Create: static/assets/modules/genealogy/opaque/g06-search-button.png
  • Modify: docs/design/P00_页面结构与资产清单.md

Interfaces:

  • Consumes: G03 已确认的暖象牙、古金与淡墨设计语言。

  • Produces: 720×248 的独立输入皮肤、300×132 的独立按钮皮肤;两张资产均四角不透明。

  • Step 1: 用 ImageGen 生成没有文字的输入与按钮位图

提示词必须要求:输入和按钮以独立完整位图生成;不得出现文字、输入内容、设备框、水印或透明角。

  • Step 2: 将生成结果规范为 1122×820 PNG 并检查四角 alpha
$bitmap = [System.Drawing.Bitmap]::FromFile('static/assets/modules/genealogy/opaque/g06-search-input.png')
if ($bitmap.Width -ne 720 -or $bitmap.Height -ne 248) { throw 'Unexpected G06 input size' }
if (@($bitmap.GetPixel(0,0).A, $bitmap.GetPixel(719,0).A, $bitmap.GetPixel(0,247).A, $bitmap.GetPixel(719,247).A) | Where-Object { $_ -ne 255 }) { throw 'G06 input corners must be opaque' }
  • Step 3: 登记资产的语义、尺寸、引用位置和状态

在 P00 的资产清单中写入 modules/genealogy/opaque/g06-search-input.pngg06-search-button.png 两条正式路径,标明分别由真实输入和真实搜索动作使用。

Task 3: 以最小实现合并 G07 到 G06GREEN

Files:

  • Modify: pages/genealogy/g06-search-genealogies.vue
  • Modify: pages.json
  • Delete: pages/genealogy/g07-search-result.vue

Interfaces:

  • Consumes: appApi.getPublicGenealogies() 返回的 namesurnamelocationidGenealogyCardgenealogyroleselect 接口。

  • Produces: .search-initial.search-results.search-empty 运行时节点和 G08 导航。

  • Step 1: 将 G06 默认结果清空,数据加载仅完成数据准备

const keyword = ref('')
const allResults = ref([])
const results = ref([])
const searchState = ref('initial')

onMounted(async () => {
  searchState.value = 'loading'
  allResults.value = await appApi.getPublicGenealogies()
  searchState.value = 'initial'
})
  • Step 2: 只在提交时筛选并切换结果/无结果状态
const search = () => {
  const value = keyword.value.trim()
  results.value = value
    ? allResults.value.filter((item) => `${item.name}${item.surname}${item.location}`.includes(value))
    : allResults.value
  searchState.value = results.value.length ? 'results' : 'empty'
}

const openApply = (genealogy) => uni.navigateTo({ url: `/pages/genealogy/g08-join-application?genealogyId=${genealogy.id}` })
  • Step 3: 以位图面板承载输入区,复用题签结果卡

模板包含 search-hero、独立的输入/按钮位图、真实 <input>、真实点击层、初始/加载/无结果文案和 GenealogyCard role="可申请"。相应 CSS 只负责布局、层级、文字和尺寸;.search-field.search-action 不得写 backgroundborderborder-radius

  • Step 4: 从 pages.json 删除 G07 并物理删除 G07 页面文件

删除唯一 pages/genealogy/g07-search-result 条目和 pages/genealogy/g07-search-result.vue,不添加重定向。

  • Step 5: 运行新契约和冒烟测试,确认转绿

Run: powershell -ExecutionPolicy Bypass -File tests/g06-search-flow-contract.ps1

Expected: G06-SEARCH-FLOW-CONTRACT PASS

Run: node tests/g06-search-flow-runtime-smoke.js http://localhost:5173

Expected: G06-SEARCH-FLOW-RUNTIME-SMOKE PASS

Task 4: 同步全局契约、文档与视觉证据

Files:

  • Modify: tests/full-page-visual-contract.ps1
  • Modify: tests/a03-route-removal-contract.ps1
  • Modify: docs/交接记录.md
  • Modify: docs/规划.md
  • Modify: docs/design/视觉设计交接手册.md
  • Modify: docs/design/P00_页面结构与资产清单.md
  • Modify: docs/design/2026-07-14_页面与状态合并审计.md
  • Create: docs/design/screens/runtime/2026-07-14/G06-initial-after-360x800.png
  • Create: docs/design/screens/runtime/2026-07-14/G06-results-after-360x800.png
  • Create: docs/design/screens/runtime/2026-07-14/G06-empty-after-360x800.png
  • Create: docs/design/screens/runtime/2026-07-14/G06-results-after-412x915.png

Interfaces:

  • Consumes: 删除 G07 后的 55 条 pages.json 路由和 G06 三态截图。

  • Produces: 当前路由数、G03 已通过状态和下一项 T02→T01 的准确交接记录。

  • Step 1: 将全量路由数组和计数更新为 55

tests/full-page-visual-contract.ps1 的预期数组删除 G07;两个契约都将 56 改为 55,并把说明改为已完成的三次合并。

  • Step 2: 截取并逐张审视 G06 初始、有结果、无结果与 412×915 结果状态
node scripts/capture-chrome-page.js "http://localhost:5173/#/pages/genealogy/g06-search-genealogies" ".search-page" "docs/design/screens/runtime/2026-07-14/G06-initial-after-360x800.png" 360 800

结果和无结果截图由 Chrome 调试执行真实输入后取得;检查无黑角、无裁切、面板与题签框完整,且初始态没有结果卡。

  • Step 3: 更新当前交接文档

写明 G03 已获用户继续授权、G07 已合并到 G06、当前为 55 路由,下一项为 T02→T01;历史计划不做回写。

  • Step 4: 运行相关全量静态契约、冒烟、截图检查和 Git 空白检查
Get-ChildItem tests -Filter *.ps1 | ForEach-Object { powershell -ExecutionPolicy Bypass -File $_.FullName }
node tests/g06-search-flow-runtime-smoke.js http://localhost:5173
node tests/g03-create-flow-runtime-smoke.js http://localhost:5173
node tests/g01-empty-state-runtime-smoke.js http://localhost:5173
git diff --check

Expected: 所有测试通过,git diff --check 仅可出现既有 CRLF 警告且退出码为 0。

Plan Self-Review

  • 覆盖性:四个任务分别覆盖契约、位图资产、G06/G07 收敛、文档和完成前验证。
  • 无占位项:状态名、路由、资产路径、选择器和验证命令均已明确。
  • 边界:不触及 G08 实现、其他合并项或已验收可见效果;Git 操作由用户保留。

Task 5: 用户审视后的 G06 控件层级修正

  • 复现并确认:绝对定位的面板纸纹覆盖了静态 PageHeader,且输入槽和动作槽被烘焙在同一张背景中,造成不可交互的截图感。
  • 先将“可见页头、独立输入皮肤、独立按钮皮肤”写入 tests/g06-search-flow-contract.ps1,确认契约因缺少新结构而失败。
  • 以 ImageGen 制作过无控件的面板版本并制作独立 g06-search-input.pngg06-search-button.png;视觉审视后确认大型面板仍有设计稿感,已删除该短期资产,最终只保留两张独立控件位图。
  • PageHeader 包入高层级容器;在独立输入/按钮位图上叠放真实输入与点击控件,不改 G06 状态、筛选或 G08 跳转行为。
  • 截取并审视 G06-correction-after-initial-360x800.pngG06-correction-after-results-360x800.pngG06-correction-after-empty-360x800.png 和前后对比图;运行 G06 静态契约与 Chrome 冒烟。

Task 6: 用户选定第 3 稿后的 G06 题签收尾(在用户要求停止时暂停)

  • 根据用户选择的最近 ImageGen 第 3 稿,写入/更新 G06 静态契约,要求朱砂题签、宽输入框、独立按钮和真实品牌谱印。
  • 新增 g06-search-title-strip.pngg06-search-input-wide.png,在 Vue 中用项目 brand-seal.png 覆盖题签的通用印玺;不改搜索状态、筛选和 G08 跳转。
  • 运行 G06 静态契约和 Chrome 运行冒烟,并保存最后候选的初始态运行图:docs/design/screens/runtime/2026-07-14/G06-selected-strip-final-initial-360x800.png
  • 重新截取并审视最后候选的结果态与无结果态;请求用户对 G06 三态作最终审美确认。用户已要求停止当前工作并转交到另一台电脑,禁止擅自继续。