# Responsive Foundation Phase 1 Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 建立全项目响应式基础契约,并让 AppDialog、AppButton 与 ModulePage 使用统一九宫格素材档案和内容驱动高度。 **Architecture:** `styles/adaptive-frame-profiles.scss` 是九宫格切片的唯一所有者;组件只调用具名 mixin。`project-responsive-layout-contract.ps1` 根据覆盖清单扫描已迁移文件,根据唯一白名单放行结构性固定尺寸;第一阶段覆盖三个公共内容组件,后续阶段只增加覆盖范围。 **Tech Stack:** uni-app、Vue 3、SCSS、PowerShell、MuMu Android ## Global Constraints - 内容容器不得使用固定高度表达内容容量。 - 可变内容背景不得使用 `100% 100%` 整图拉伸。 - 固定高度和固定装饰例外只能由 `tests/responsive-layout-allowlist.json` 所有。 - 第一阶段覆盖 `AppDialog.vue`、`AppButton.vue`、`ModulePage.vue`;已覆盖文件不得退出。 - AppDialog 短内容自然收紧、长内容自然增高、超过视口才滚动。 - 不修改业务逻辑、路由、文案和数据状态。 - 不执行 Git 操作,不启用多代理。 --- ### Task 1: 唯一九宫格素材档案 **Files:** - Create: `styles/adaptive-frame-profiles.scss` - Create: `tests/adaptive-frame-profiles-contract.ps1` **Interfaces:** - Produces: `adaptive-auth-dialog`、`adaptive-scroll-button($type)`、`adaptive-module-content`、`adaptive-module-field` 四个 SCSS mixin。 - [ ] **Step 1: 写入失败合同** 合同要求档案存在并包含: ```powershell foreach ($token in @( '@mixin adaptive-auth-dialog', '@mixin adaptive-scroll-button($type)', '@mixin adaptive-module-content', '@mixin adaptive-module-field', 'a01-scroll-dialog-v3.png', 'border-image-slice: 260 240 360 240 fill;', 'border-image-slice: 56 300 fill;', 'border-image-slice: 105 150;', 'border-image-slice: 70 100 fill;' )) ``` Run: `powershell -NoProfile -ExecutionPolicy Bypass -File tests/adaptive-frame-profiles-contract.ps1` Expected: FAIL,素材档案不存在。 - [ ] **Step 2: 创建素材档案** `adaptive-auth-dialog` 使用: ```scss border-width: 48rpx 34rpx 72rpx; border-image-slice: 260 240 360 240 fill; border-image-width: 48rpx 34rpx 72rpx; ``` `adaptive-scroll-button` 使用现有主/次卷轴素材、`10rpx 26rpx` 边框和 `56 300 fill` 切片。 `adaptive-module-content` 使用动态 `var(--module-content-asset)`、`18rpx 20rpx` 边框和 `105 150` 切片。 `adaptive-module-field` 使用动态 `var(--module-field-asset)`、`12rpx 16rpx` 边框和 `70 100 fill` 切片。 所有 mixin 使用透明实体边框、`border-image-repeat: stretch` 和 `box-sizing: border-box`。 - [ ] **Step 3: 验证档案合同** Expected: `ADAPTIVE-FRAME-PROFILES-CONTRACT PASS`。 ### Task 2: 全局扫描合同、覆盖清单与例外白名单 **Files:** - Create: `tests/project-responsive-layout-contract.ps1` - Create: `tests/responsive-layout-coverage.json` - Create: `tests/responsive-layout-allowlist.json` **Interfaces:** - Consumes: 覆盖文件列表与按文件/选择器/属性登记的例外。 - Produces: 已迁移文件中固定内容高度、可变背景整图拉伸和重复九宫格切片的失败门禁。 - [ ] **Step 1: 创建第一阶段覆盖清单** ```json { "covered": [ "components/AppButton.vue", "components/AppDialog.vue", "components/ModulePage.vue" ] } ``` - [ ] **Step 2: 创建唯一白名单** 第一阶段只允许 `ModulePage.vue` 的 `.module-lead` 使用固定分隔线背景;不允许 AppDialog、AppButton 或 ModulePage 内容表面使用固定内容高度/整图拉伸。 - [ ] **Step 3: 创建扫描合同并确认失败** 合同解析覆盖文件的样式块,遇到以下情况失败: ```text height: <数字>rpx(不含 min-height/max-height) background: ... 100% 100% 页面或组件直接出现 border-image-slice(素材档案本身除外) ``` 白名单按规范化文件路径、选择器和属性精确匹配。覆盖清单中的路径不存在也失败。 Run: `powershell -NoProfile -ExecutionPolicy Bypass -File tests/project-responsive-layout-contract.ps1` Expected: FAIL,指出 AppDialog 固定 `520rpx` 或 ModulePage 内容表面整图拉伸。 ### Task 3: AppDialog 与 AppButton 消费统一档案 **Files:** - Modify: `components/AppDialog.vue` - Modify: `components/AppButton.vue` - Modify: `tests/app-dialog-responsive-content-contract.ps1` - Modify: `tests/app-button-compact-contract.ps1` **Interfaces:** - Consumes: Task 1 的 `adaptive-auth-dialog` 与 `adaptive-scroll-button`。 - Produces: 内容驱动的全局弹窗和默认关闭的紧凑按钮。 - [ ] **Step 1: 更新失败合同** AppDialog 合同禁止 `min-height: 520rpx`、旧 `background ... contain` 和 `margin-top: auto`,要求: ```text @include adaptive-auth-dialog; max-height: calc(var(--app-viewport-height, 100vh) - 160rpx) margin-top: 26rpx ``` AppButton 合同要求调用 `adaptive-scroll-button(primary|secondary)`,不再在组件内重复切片值。 - [ ] **Step 2: 运行合同并确认失败** Expected: AppDialog 因固定高度失败,AppButton 因本地切片重复失败。 - [ ] **Step 3: 修改 AppDialog** 在 scoped style 开头导入档案。`.app-dialog` 删除固定最小高度和旧背景,调用 `adaptive-auth-dialog`。`.app-dialog__content` 删除固定最小高度,使用: ```scss max-height: calc(var(--app-viewport-height, 100vh) - 160rpx); padding: 16rpx 20rpx 12rpx; overflow-y: auto; ``` 操作区改为 `margin-top: 26rpx`,不再使用 `auto`。 - [ ] **Step 4: 修改 AppButton** 导入档案;主/次紧凑类分别调用 `@include adaptive-scroll-button(primary)` 和 `secondary`;删除组件内重复边框切片声明。 - [ ] **Step 5: 运行共享组件合同** Run AppDialog、AppButton、共享无障碍、共享文档流和全局响应式合同,Expected: 全部 `PASS`。 ### Task 4: ModulePage 内容表面迁移 **Files:** - Modify: `components/ModulePage.vue` - Modify: `tests/module-page-visual-contract.ps1` - Test: `tests/module-series-responsive-runtime-smoke.js` **Interfaces:** - Consumes: Task 1 的 module-content 与 module-field mixin。 - Produces: F/R/N/M 通用页面的内容驱动卡片和表单表面。 - [ ] **Step 1: 更新失败合同** 要求 ModulePage 导入档案,字段组调用 `adaptive-module-field`,内容组调用 `adaptive-module-content`;禁止内容表面 `100% 100%`。 - [ ] **Step 2: 运行合同并确认失败** Expected: FAIL,指出旧 `var(--module-*-asset) center / 100% 100%`。 - [ ] **Step 3: 修改 ModulePage** - `.form-row, .settings-row` 调用 `adaptive-module-field`。 - `.list-card, .detail-card, .timeline-row, .status-card` 调用 `adaptive-module-content`。 - `.module-lead` 自己承担 flex 居中,删除子文本的 `height: 100%`。 - 保留现有 `min-height` 作为最低视觉基线,内容可继续增高。 - [ ] **Step 4: 验证 ModulePage** 运行视觉合同、响应式 runtime smoke 与全局响应式合同;若 H5 服务未运行,只记录 runtime 环境阻塞,不用浏览器代替 MuMu。 ### Task 5: MuMu 三档基础验证 **Files:** - Verify: `components/AppDialog.vue` - Verify: `components/AppButton.vue` - Verify: `components/ModulePage.vue` - Save screenshots: `tmp/responsive-foundation-*.png` **Interfaces:** - Produces: G10 通过/拒绝弹窗和一个 ModulePage 页面在三档 Android 逻辑视口的原生证据。 - [ ] **Step 1: 运行全部聚焦合同** 必须包含素材档案、全局响应式、AppDialog、AppButton、ModulePage、共享无障碍和共享文档流合同。 - [ ] **Step 2: MuMu 验证 G10** 在 `360×640dp`、`360×800dp`、`412×915dp` 依次检查: ```text 通过确认:无固定大空白。 拒绝确认:输入框和按钮不压边。 拒绝错误:错误文字出现后仍可达按钮。 ``` - [ ] **Step 3: MuMu 验证 ModulePage** 选择一个 ready 和一个 error 状态,确认内容卡随文字增高、边角不拉伸、按钮可达。 - [ ] **Step 4: 恢复 MuMu 原始尺寸** 每档验证后恢复用户当前 `720×1280` 物理尺寸和原密度,并把 G10 恢复到默认列表。