Review changes batch 5 of 6
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
# G01 可伸缩切换家谱弹层 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. The user explicitly forbids subagents and worktrees, so execution must remain inline in the current workspace. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 将 G01“切换当前家谱”改为紧凑、可读、带关闭图标且背景随内容九宫格伸缩的居中弹层。
|
||||
|
||||
**Architecture:** 继续使用现有完整 PNG `a01-scroll-dialog-v3.png`,由弹层根容器通过 `border-image` 九宫格渲染,固定装饰区并仅拉伸中间宣纸。标题和关闭入口固定在安全区,家谱列表按内容自然增高,到视口上限后独立滚动;不抽取全局组件。
|
||||
|
||||
**Tech Stack:** uni-app、Vue 3 `<script setup>`、SCSS、PowerShell 合同测试、Chrome DevTools Protocol 9222。
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- 只修改 G01“切换当前家谱”弹层,不修改公共 `AppDialog`、`AppButton`、其他状态或其他页面。
|
||||
- 唯一背景资产为 `static/assets/modules/auth/transparent/a01-scroll-dialog-v3.png`,源尺寸 `1860×1560`;不得覆盖、删除、重绘或拆分资产。
|
||||
- 九宫格源切片为 `300 260 360 260 fill`,显示边宽为 `110rpx 48rpx 132rpx 48rpx`。
|
||||
- 弹层宽度 `670rpx`、最小高度 `600rpx`、最大高度 `calc(100vh - 120rpx)`;内容区内边距为 `120rpx 58rpx 140rpx`。
|
||||
- 关闭入口复用 `g01-dialog-close.png`,热区 `80rpx × 80rpx`,定位 `top: 78rpx; right: 34rpx`,可访问名称为“关闭”。
|
||||
- 复用 9222 上唯一的 `localhost:5173` 项目标签页,不新开浏览器或第二个项目标签页。
|
||||
- 不使用多代理、worktree;不执行 `git add`、`commit`、`push`、`reset` 或 `checkout`;不删除或清理现有文件。
|
||||
- H5 截图仅为内部候选;Android/HBuilderX 未验证;未经用户明确“通过”不得标记或冻结 G01。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 建立可伸缩切换弹层视觉合同
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/g01-visual-contract.ps1`
|
||||
- Test: `tests/g01-visual-contract.ps1`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: G01 源文件字符串 `$page` 和切换弹层现有类名。
|
||||
- Produces: 九宫格、动态高度、安全区、滚动列表、关闭图标和返回键的单一合同。
|
||||
|
||||
- [ ] **Step 1: 添加失败合同**
|
||||
|
||||
在现有 switcher 断言附近加入:
|
||||
|
||||
```powershell
|
||||
if ($page -match 'class="genealogy-switcher__skin"') {
|
||||
throw 'G-01 switcher must not render the complete background as a fixed aspectFit image.'
|
||||
}
|
||||
if ($page -notmatch '(?s)\.genealogy-switcher\s*\{[^}]*min-height:\s*600rpx;[^}]*max-height:\s*calc\(100vh\s*-\s*120rpx\);[^}]*border-image-source:\s*url\("/static/assets/modules/auth/transparent/a01-scroll-dialog-v3\.png"\);[^}]*border-image-slice:\s*300\s+260\s+360\s+260\s+fill;[^}]*border-image-width:\s*110rpx\s+48rpx\s+132rpx\s+48rpx;') {
|
||||
throw 'G-01 switcher does not use the approved stretchable complete background.'
|
||||
}
|
||||
if ($page -notmatch '(?s)\.genealogy-switcher__content\s*\{[^}]*min-height:\s*600rpx;[^}]*max-height:\s*calc\(100vh\s*-\s*120rpx\);[^}]*padding:\s*120rpx\s+58rpx\s+140rpx;') {
|
||||
throw 'G-01 switcher content does not keep the approved decoration safe area.'
|
||||
}
|
||||
if ($page -notmatch 'class="genealogy-switcher__list"[^>]*scroll-y') {
|
||||
throw 'G-01 switcher does not provide an independent scroll list.'
|
||||
}
|
||||
if ($page -notmatch '(?s)class="genealogy-switcher__close"[^>]*aria-label="关闭".*?g01-dialog-close\.png') {
|
||||
throw 'G-01 switcher does not use the custom accessible close control.'
|
||||
}
|
||||
if ($page -match '<view class="dialog-close" @click="closeSwitcher">关闭</view>') {
|
||||
throw 'G-01 switcher still exposes the obsolete bottom close copy.'
|
||||
}
|
||||
if ($page -notmatch '(?s)onBackPress\(\(\)\s*=>\s*\{\s*if\s*\(switcherVisible\.value\)\s*\{\s*closeSwitcher\(\);\s*return\s*true;\s*\}\s*if\s*\(addDialogVisible\.value\)') {
|
||||
throw 'G-01 switcher does not consume Android back before the add dialog and page navigation.'
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行合同并确认 RED**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-visual-contract.ps1
|
||||
```
|
||||
|
||||
Expected: FAIL,首先输出 `G-01 switcher must not render the complete background as a fixed aspectFit image.`。
|
||||
|
||||
### Task 2: 最小实现动态背景、紧凑内容和关闭交互
|
||||
|
||||
**Files:**
|
||||
- Modify: `pages/genealogy/g01-my-genealogies.vue:256-276`
|
||||
- Modify: `pages/genealogy/g01-my-genealogies.vue:389-395`
|
||||
- Modify: `pages/genealogy/g01-my-genealogies.vue:967-981`
|
||||
- Test: `tests/g01-visual-contract.ps1`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `availableGenealogies`、`selectedGenealogyId`、`selectGenealogy(item)`、`closeSwitcher()`。
|
||||
- Produces: `.genealogy-switcher__list` 独立滚动区和 `.genealogy-switcher__close` 自定义关闭控件。
|
||||
|
||||
- [ ] **Step 1: 替换切换弹层模板**
|
||||
|
||||
将当前弹层内部结构替换为:
|
||||
|
||||
```vue
|
||||
<view v-if="switcherVisible" class="genealogy-switcher-layer" @click="closeSwitcher">
|
||||
<view class="genealogy-switcher" role="dialog" aria-modal="true" aria-label="切换当前家谱" @click.stop>
|
||||
<view class="genealogy-switcher__content">
|
||||
<text class="dialog-title">切换当前家谱</text>
|
||||
<view class="genealogy-switcher__close" role="button" aria-label="关闭" hover-class="action-hover" @click="closeSwitcher">
|
||||
<image class="genealogy-switcher__close-icon" src="/static/assets/modules/genealogy/transparent/g01-dialog-close.png" mode="aspectFit" />
|
||||
</view>
|
||||
<scroll-view class="genealogy-switcher__list" scroll-y>
|
||||
<view
|
||||
v-for="item in availableGenealogies"
|
||||
:key="item.id"
|
||||
class="switcher-item"
|
||||
:class="{ 'switcher-item--active': item.id === selectedGenealogyId }"
|
||||
@click="selectGenealogy(item)"
|
||||
>
|
||||
<view>
|
||||
<text class="switcher-item__name">{{ item.name }}</text>
|
||||
<text class="switcher-item__meta">{{ item.location }} · {{ item.memberCount }} 位成员</text>
|
||||
</view>
|
||||
<text class="switcher-item__state">{{ item.id === selectedGenealogyId ? '当前' : '选择' }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 调整 Android 返回键优先级**
|
||||
|
||||
将处理器改为:
|
||||
|
||||
```js
|
||||
onBackPress(() => {
|
||||
if (switcherVisible.value) {
|
||||
closeSwitcher()
|
||||
return true
|
||||
}
|
||||
if (addDialogVisible.value) {
|
||||
closeAddDialog()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 写入最小页面级样式**
|
||||
|
||||
使用以下结构替换旧 switcher 样式:
|
||||
|
||||
```scss
|
||||
.genealogy-switcher-layer { position: fixed; z-index: 40; inset: 0; display: flex; align-items: center; justify-content: center; box-sizing: border-box; padding: 60rpx 40rpx; background: rgba(34, 20, 12, 0.58); }
|
||||
.genealogy-switcher { position: relative; width: 670rpx; max-width: 100%; min-height: 600rpx; max-height: calc(100vh - 120rpx); box-sizing: border-box; border: 1px solid transparent; border-image-source: url("/static/assets/modules/auth/transparent/a01-scroll-dialog-v3.png"); border-image-slice: 300 260 360 260 fill; border-image-width: 110rpx 48rpx 132rpx 48rpx; border-image-repeat: stretch; }
|
||||
.genealogy-switcher__content { position: relative; z-index: 1; display: flex; min-height: 600rpx; max-height: calc(100vh - 120rpx); flex-direction: column; align-items: center; box-sizing: border-box; padding: 120rpx 58rpx 140rpx; }
|
||||
.genealogy-switcher__close { position: absolute; z-index: 3; top: 78rpx; right: 34rpx; display: flex; width: 80rpx; height: 80rpx; align-items: center; justify-content: center; }
|
||||
.genealogy-switcher__close-icon { width: 80rpx; height: 80rpx; }
|
||||
.genealogy-switcher__list { width: 100%; min-height: 0; max-height: calc(100vh - 500rpx); margin-top: 24rpx; overflow-y: auto; }
|
||||
.switcher-item { display: flex; width: 100%; min-height: 112rpx; align-items: center; justify-content: space-between; box-sizing: border-box; padding: 18rpx 16rpx; border: 1rpx solid transparent; border-bottom-color: rgba(181, 138, 75, 0.42); }
|
||||
.switcher-item__name,
|
||||
.switcher-item__meta { display: block; }
|
||||
.switcher-item__name { color: $ink; font-family: "STKaiti", "KaiTi", serif; font-size: 32rpx; font-weight: 700; }
|
||||
.switcher-item__meta { margin-top: 6rpx; color: #62584c; font-size: 24rpx; }
|
||||
.switcher-item__state { color: $brand-red; font-size: 25rpx; font-weight: 600; }
|
||||
.switcher-item--active { border-color: rgba(159, 23, 15, 0.22); background: rgba(159, 23, 15, 0.055); }
|
||||
.switcher-item--active .switcher-item__name { color: $brand-red; }
|
||||
```
|
||||
|
||||
不得修改公共组件或任何图片资产。
|
||||
|
||||
- [ ] **Step 4: 运行聚焦合同并确认 GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-visual-contract.ps1
|
||||
```
|
||||
|
||||
Expected: `PASS G-01 visual contract`。
|
||||
|
||||
- [ ] **Step 5: 运行相邻 G01 合同**
|
||||
|
||||
Run each command independently:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-empty-state-contract.ps1
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-loading-state-contract.ps1
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-error-state-contract.ps1
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected: 三个状态合同均输出 `PASS`;`git diff --check` 退出码为 0,允许仅出现工作区既有 LF/CRLF 警告。
|
||||
|
||||
### Task 3: 在唯一 Chrome 标签页验证四档、伸缩和交互
|
||||
|
||||
**Files:**
|
||||
- Modify: `design-qa.md`
|
||||
- Create: `docs/design/screens/runtime/2026-07-19/g01-approval/06-switch-dialog-stretchable-412x915.png`
|
||||
- Create: `docs/design/screens/runtime/2026-07-19/g01-approval/06-switch-dialog-stretchable-320x568.png`
|
||||
- Create: `docs/design/screens/runtime/2026-07-19/g01-approval/06-switch-dialog-stretchable-six-items-412x915.png`
|
||||
- Create: `docs/design/screens/runtime/2026-07-19/g01-approval/06-switch-dialog-before-vs-stretchable.png`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: 9222 上唯一的 `localhost:5173` 页面和当前 G01 列表态。
|
||||
- Produces: 四档两项状态、六项自然增高、十二项封顶滚动及最终审批状态的运行证据。
|
||||
|
||||
- [ ] **Step 1: 确认唯一项目标签页并新鲜打开弹层**
|
||||
|
||||
读取 `http://127.0.0.1:9222/json/list`,严格确认只有一个 `type: page` 且 URL 以 `http://localhost:5173` 开头的项目页。刷新同一页面,点击 `.current-slip`,等待 `.genealogy-switcher` 可见。
|
||||
|
||||
Expected: 项目标签页数量为 1,切换弹层打开,没有添加弹层或临时克隆。
|
||||
|
||||
- [ ] **Step 2: 验证四档两项状态**
|
||||
|
||||
在同一标签页依次设置 `320×568`、`360×640`、`360×800`、`412×915`。
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
dialog min-height = 600rpx 对应像素值
|
||||
title 不与顶部边框或祥云重叠
|
||||
close control 完整可见
|
||||
itemCount = 2
|
||||
列表不滚动
|
||||
末项下方纯内容空白 <= 72rpx 对应像素值
|
||||
horizontalOverflow = false
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 验证六项自然增高**
|
||||
|
||||
只在浏览器运行时向 `.genealogy-switcher__list` 临时克隆四项,并标记 `data-cdp-clone="1"`。
|
||||
|
||||
Expected: 弹层高度大于两项状态、低于最大高度;背景中间宣纸伸长,顶部祥云和底部山水尺寸不变;列表无需滚动即可看全六项。
|
||||
|
||||
- [ ] **Step 4: 验证十二项封顶滚动**
|
||||
|
||||
清除六项克隆后临时补足十二项。
|
||||
|
||||
Expected: 弹层高度等于最大安全高度;标题和关闭图标固定;列表 `scrollHeight > clientHeight`、初始 `scrollTop = 0`,滚到底后末项可见;后方页面不滚动。
|
||||
|
||||
- [ ] **Step 5: 验证关闭和选择交互**
|
||||
|
||||
依次验证:弹层内部点击保持打开;关闭图标关闭;遮罩关闭;Android 返回处理器合同;点击第二项更新当前家谱并关闭。每次通过 `.current-slip` 在同一标签页重新打开。
|
||||
|
||||
Expected: 不出现原生 Toast、Loading、Modal 或 ActionSheet;控制台无异常,无 4xx/5xx 资源响应。
|
||||
|
||||
- [ ] **Step 6: 清理运行时克隆并恢复审批状态**
|
||||
|
||||
移除所有 `[data-cdp-clone]`,将视口恢复为 `412×915`,恢复两条真实数据并保持切换弹层打开。
|
||||
|
||||
Expected: 项目标签页仍为 1;添加弹层关闭;切换弹层打开;两项、无克隆、无横向溢出。
|
||||
|
||||
- [ ] **Step 7: 生成对比并更新设计质检**
|
||||
|
||||
把审查前截图 `audit-switch-dialog/01-switch-dialog-412x915.png` 与新 412×915 截图合成同尺寸横向对比;在 `design-qa.md` 记录标题安全区、空白量、九宫格装饰尺寸、文本可读性、关闭入口、四档、压力滚动、交互、控制台和证据限制。
|
||||
|
||||
Expected: 若 H5 内部候选不存在可执行 P0/P1/P2,则当前小节 `final result: passed`;同时明确用户尚未通过、Android/HBuilderX 未验证。
|
||||
|
||||
- [ ] **Step 8: 最终新鲜验证**
|
||||
|
||||
重新运行四个 G01 合同与 `git diff --check`,再读取浏览器最终状态。
|
||||
|
||||
Expected: 所有合同退出码为 0;同一项目标签页为 `412×915`、两项、切换弹层打开、无临时克隆、无横向溢出。
|
||||
|
||||
Reference in New Issue
Block a user