Review changes batch 5 of 6
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
# G01 添加家谱底部弹层实施计划
|
||||
|
||||
> **状态:已废止。** 用户否决了完整卷轴背景方向;不得继续执行本文。当前唯一实施计划为 `docs/superpowers/plans/2026-07-19-g01-add-genealogy-paper-sheet.md`。
|
||||
|
||||
> **执行要求:** 使用 `superpowers:executing-plans` 在当前会话内联执行;禁止多代理、worktree、`git add`、`commit`、`push`、`reset` 和 `checkout`。
|
||||
|
||||
**目标:** 将 G01 当前居中大卷轴“添加家谱”弹窗改成紧凑、可明确关闭的自定义底部弹层,并保持三个现有跳转行为不变。
|
||||
|
||||
**架构:** 只在 `g01-my-genealogies.vue` 内拆分添加弹层与切换弹层的模板选择器和样式责任;添加弹层底部对齐并使用自己的关闭入口,切换弹层继续沿用居中卷轴。先用现有 PowerShell 视觉契约锁定结构、文案、布局和返回键行为,再做最小实现。
|
||||
|
||||
**技术栈:** uni-app、Vue 3 `<script setup>`、SCSS、PowerShell 契约测试、Chrome DevTools Protocol 9222。
|
||||
|
||||
## 全局约束
|
||||
|
||||
- 只返工 G01“添加家谱”弹层,不修改切换家谱弹层、其他 G01 状态或其他页面。
|
||||
- 不对接接口;三个入口继续调用 `applyToJoin`、`joinByInvite`、`createGenealogy`。
|
||||
- 继续使用项目自定义组件和现有真实 PNG 资产,不使用原生 UniApp 弹窗、Toast、Loading 或 ActionSheet。
|
||||
- 只复用当前 9222 Chrome 窗口和唯一项目标签页,不打开第二个浏览器或第二个项目标签页。
|
||||
- 不覆盖、删除或清理现有修改、未跟踪文件、测试、文档、截图、母版和候选资产。
|
||||
- 不执行任何 Git 暂存、提交、推送、重置或检出命令。
|
||||
- H5 截图只作为内部候选证据;Android/HBuilderX 仍标记为未验证。
|
||||
- 没有用户明确“通过”,不得将 G01 标记为 `[x]` 或冻结。
|
||||
|
||||
---
|
||||
|
||||
### 任务 1:锁定底部弹层的结构、文案与视觉契约
|
||||
|
||||
**文件:**
|
||||
|
||||
- 修改:`tests/g01-visual-contract.ps1`
|
||||
- 修改:`pages/genealogy/g01-my-genealogies.vue` 的添加弹层模板与弹层样式
|
||||
|
||||
**接口:**
|
||||
|
||||
- 消费:`addDialogVisible`、`closeAddDialog()`、`applyToJoin()`、`joinByInvite()`、`createGenealogy()`、现有 `AppButton`。
|
||||
- 产出:`.add-dialog-layer`、`.add-dialog`、`.add-dialog__heading`、`.add-dialog__close`、`.add-dialog__content`;切换弹层选择器和表现保持不变。
|
||||
|
||||
- [ ] **步骤 1:先加入会失败的结构与样式契约**
|
||||
|
||||
在 `tests/g01-visual-contract.ps1` 读取 `$page` 后增加:
|
||||
|
||||
```powershell
|
||||
foreach ($token in @('class="add-dialog__heading"', 'class="add-dialog__close"', '>关闭</view>', 'label="继续创建家谱"')) {
|
||||
if ($page -notmatch [regex]::Escape($token)) { throw "G-01 add sheet is missing $token" }
|
||||
}
|
||||
if ($page -match [regex]::Escape('label="确认没有现有家谱,继续创建"')) {
|
||||
throw 'G-01 add sheet still puts guidance copy inside the create button.'
|
||||
}
|
||||
if ($page -notmatch '(?s)\.add-dialog-layer\s*\{[^}]*align-items:\s*flex-end;[^}]*background:\s*rgba\(34,\s*20,\s*12,\s*0\.68\);') {
|
||||
throw 'G-01 add sheet is not a bottom-aligned layer with the approved mask.'
|
||||
}
|
||||
if ($page -notmatch '(?s)\.add-dialog\s*\{[^}]*max-width:\s*650rpx;[^}]*min-height:\s*545rpx;') {
|
||||
throw 'G-01 add sheet does not use the compact approved proportions.'
|
||||
}
|
||||
if ($page -notmatch '(?s)\.add-dialog__close\s*\{[^}]*min-height:\s*72rpx;') {
|
||||
throw 'G-01 add sheet close control does not reserve the approved hit area.'
|
||||
}
|
||||
if ($page -notmatch '(?s)\.genealogy-switcher-layer\s*\{[^}]*align-items:\s*center;[^}]*padding:\s*40rpx;') {
|
||||
throw 'G-01 switcher must remain a centered dialog.'
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行契约并确认按预期失败**
|
||||
|
||||
运行:
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-visual-contract.ps1
|
||||
```
|
||||
|
||||
预期:`FAIL`,第一条失败信息为缺少 `class="add-dialog__heading"`;失败原因必须是新结构尚未实现,而不是脚本语法或文件编码错误。
|
||||
|
||||
- [ ] **步骤 3:最小修改添加弹层模板**
|
||||
|
||||
将添加弹层模板改为以下结构;切换家谱模板不动:
|
||||
|
||||
```vue
|
||||
<view v-if="addDialogVisible" class="add-dialog-layer" @click="closeAddDialog">
|
||||
<view class="add-dialog" @click.stop>
|
||||
<image class="add-dialog__skin" src="/static/assets/modules/auth/transparent/a01-scroll-dialog-v3.png" mode="aspectFit" />
|
||||
<view class="add-dialog__content">
|
||||
<view class="add-dialog__heading">
|
||||
<text class="dialog-title">添加家谱</text>
|
||||
<text class="dialog-copy">建议先搜索已有家谱,避免重复创建</text>
|
||||
</view>
|
||||
<view class="add-dialog__close" hover-class="action-hover" @click="closeAddDialog">关闭</view>
|
||||
<AppButton block label="搜索家谱" @click="applyToJoin" />
|
||||
<AppButton block type="secondary" label="邀请码加入" @click="joinByInvite" />
|
||||
<AppButton block type="secondary" label="继续创建家谱" @click="createGenealogy" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:拆分添加弹层和切换弹层样式**
|
||||
|
||||
用以下责任边界替换当前合并规则;保留现有 `.switcher-item` 及其后续规则:
|
||||
|
||||
```scss
|
||||
.add-dialog-layer { position: fixed; z-index: 40; inset: 0; display: flex; align-items: flex-end; justify-content: center; box-sizing: border-box; padding: 0 20rpx; background: rgba(34, 20, 12, 0.68); }
|
||||
.add-dialog { position: relative; width: 100%; max-width: 650rpx; min-height: 545rpx; max-height: calc(100vh - 24rpx); }
|
||||
.add-dialog__skin { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
|
||||
.add-dialog__content { position: relative; z-index: 1; display: flex; min-height: 545rpx; max-height: calc(100vh - 24rpx); flex-direction: column; align-items: stretch; box-sizing: border-box; padding: 48rpx 58rpx calc(36rpx + env(safe-area-inset-bottom)); overflow-y: auto; }
|
||||
.add-dialog__heading { padding-right: 104rpx; }
|
||||
.add-dialog .dialog-title,
|
||||
.add-dialog .dialog-copy { display: block; text-align: left; }
|
||||
.add-dialog .dialog-title { padding-left: 54rpx; }
|
||||
.add-dialog__close { position: absolute; z-index: 2; top: 38rpx; right: 120rpx; display: flex; min-width: 88rpx; min-height: 72rpx; align-items: center; justify-content: center; color: $ink-muted; font-size: 26rpx; }
|
||||
.add-dialog .app-button { min-height: 92rpx; }
|
||||
.add-dialog__content > .app-button:first-of-type { margin-top: 24rpx; }
|
||||
.add-dialog__content > .app-button + .app-button { margin-top: 6rpx; }
|
||||
|
||||
.genealogy-switcher-layer { position: fixed; z-index: 40; inset: 0; display: flex; align-items: center; justify-content: center; box-sizing: border-box; padding: 40rpx; background: rgba(34, 20, 12, 0.58); }
|
||||
.genealogy-switcher { position: relative; width: 100%; max-width: 670rpx; min-height: 720rpx; }
|
||||
.genealogy-switcher__skin { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.genealogy-switcher__content { position: relative; z-index: 1; display: flex; min-height: 720rpx; flex-direction: column; align-items: center; box-sizing: border-box; padding: 78rpx 58rpx 50rpx; }
|
||||
.dialog-title { color: $brand-red; font-family: "STKaiti", "KaiTi", serif; font-size: 42rpx; font-weight: 700; letter-spacing: 4rpx; }
|
||||
.dialog-copy { margin-top: 12rpx; color: $ink-muted; font-size: 25rpx; line-height: 1.5; }
|
||||
.dialog-close { display: flex; min-height: 72rpx; align-items: center; justify-content: center; margin-top: auto; color: $ink-muted; font-size: 24rpx; }
|
||||
```
|
||||
|
||||
- [ ] **步骤 5:运行契约并确认通过**
|
||||
|
||||
运行同一步骤 2。预期输出:
|
||||
|
||||
```text
|
||||
PASS G-01 visual contract
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 任务 2:让 Android 返回键优先关闭添加弹层
|
||||
|
||||
**文件:**
|
||||
|
||||
- 修改:`tests/g01-visual-contract.ps1`
|
||||
- 修改:`pages/genealogy/g01-my-genealogies.vue` 的 uni-app 生命周期导入和返回键处理
|
||||
|
||||
**接口:**
|
||||
|
||||
- 消费:`addDialogVisible: Ref<boolean>`、`closeAddDialog(): void`。
|
||||
- 产出:`onBackPress` 回调;弹层打开时返回 `true` 并关闭,未打开时不拦截页面返回。
|
||||
|
||||
- [ ] **步骤 1:先加入会失败的返回键契约**
|
||||
|
||||
在 `tests/g01-visual-contract.ps1` 增加:
|
||||
|
||||
```powershell
|
||||
if ($page -notmatch 'import\s*\{[^}]*onBackPress[^}]*\}\s*from\s*"@dcloudio/uni-app"') {
|
||||
throw 'G-01 add sheet does not import onBackPress.'
|
||||
}
|
||||
if ($page -notmatch '(?s)onBackPress\(\(\)\s*=>\s*\{\s*if\s*\(!addDialogVisible\.value\)\s*return\s*false;\s*closeAddDialog\(\);\s*return\s*true;\s*\}\);') {
|
||||
throw 'G-01 add sheet does not consume Android back before page navigation.'
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行契约并确认按预期失败**
|
||||
|
||||
运行视觉契约。预期:`FAIL: G-01 add sheet does not import onBackPress.`
|
||||
|
||||
- [ ] **步骤 3:加入最小返回键处理**
|
||||
|
||||
将导入改为:
|
||||
|
||||
```js
|
||||
import { onBackPress, onLoad, onShow } from "@dcloudio/uni-app";
|
||||
```
|
||||
|
||||
在 `closeAddDialog` 定义之后加入:
|
||||
|
||||
```js
|
||||
onBackPress(() => {
|
||||
if (!addDialogVisible.value) return false;
|
||||
closeAddDialog();
|
||||
return true;
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:运行契约并确认通过**
|
||||
|
||||
预期输出:`PASS G-01 visual contract`。
|
||||
|
||||
---
|
||||
|
||||
### 任务 3:聚焦验证并在唯一标签页恢复审批状态
|
||||
|
||||
**文件:**
|
||||
|
||||
- 验证:`pages/genealogy/g01-my-genealogies.vue`
|
||||
- 读取:`tests/g01-empty-state-contract.ps1`
|
||||
- 读取:`tests/g01-visual-contract.ps1`
|
||||
- 生成候选截图:`docs/design/screens/runtime/2026-07-19/g01-approval/05-add-dialog-bottom-sheet-412x915.png`
|
||||
|
||||
**接口:**
|
||||
|
||||
- 消费:5173 H5 服务、9222 唯一 Chrome 项目标签页、当前 G01 默认列表态。
|
||||
- 产出:412×915 当前添加弹层的候选证据;不改变验收规划勾选状态。
|
||||
|
||||
- [ ] **步骤 1:运行最小相关静态检查**
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-visual-contract.ps1
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File tests/g01-empty-state-contract.ps1
|
||||
git diff --check -- pages/genealogy/g01-my-genealogies.vue tests/g01-visual-contract.ps1 docs/superpowers/specs/2026-07-19-g01-add-genealogy-bottom-sheet-design.md docs/superpowers/plans/2026-07-19-g01-add-genealogy-bottom-sheet.md
|
||||
```
|
||||
|
||||
预期:两个测试均输出 `PASS`,`git diff --check` 无输出且退出码为 0。不修改测试阈值来换取通过。
|
||||
|
||||
- [ ] **步骤 2:确认服务、标签页和视口约束**
|
||||
|
||||
只读检查 5173、9222 和 `http://127.0.0.1:9222/json/list`。预期:5173 可访问;9222 只有一个 `localhost:5173` 项目页;不得启动第二个 Chrome。
|
||||
|
||||
- [ ] **步骤 3:在同一标签页刷新现有 G01 代码并打开添加弹层**
|
||||
|
||||
保持 G01 默认列表态,将视口设为 412×915;若热更新已生效则不导航,关闭旧弹层后点击现有 `.create-action` 重新打开。等待 `.add-dialog-layer`、`.add-dialog__close` 和三个 `.app-button` 同时出现。
|
||||
|
||||
- [ ] **步骤 4:检查运行时几何和交互**
|
||||
|
||||
通过当前 CDP 连接仅检查同一个“添加家谱”状态,先检查 320×568,再恢复并检查 412×915:
|
||||
|
||||
- `.add-dialog` 底边与当前视口底边重合,允许 1px 取整误差;
|
||||
- 弹层没有横向溢出,且高度小于视口高度的 50%;
|
||||
- `.add-dialog__close` 完全位于弹层可视区域内;
|
||||
- 三个按钮同时可见,第三个文本为“继续创建家谱”;
|
||||
- 点击弹层内部不关闭;点击“关闭”会关闭;再次打开后点击遮罩会关闭;
|
||||
- 关闭和重新打开不改变 G01 独立列表的滚动位置;
|
||||
- 最后恢复 412×915,并让添加家谱弹层保持打开。
|
||||
|
||||
- [ ] **步骤 5:截取并检查候选证据**
|
||||
|
||||
使用当前标签页的 `Page.captureScreenshot` 保存指定 PNG,打开原图检查:没有错误页、加载中、裁切、横向溢出、标题压线、关闭入口消失或大块无效留白。若不满足,只返工当前弹层。
|
||||
|
||||
- [ ] **步骤 6:交回用户审批**
|
||||
|
||||
只报告当前添加弹层的变更和真实验证结果,明确 Android/HBuilderX 尚未验证;等待用户明确“通过”,不得切换到“切换家谱弹层”,不得更新 G01 为 `[x]`。
|
||||
Reference in New Issue
Block a user