Appearance
1.3 页面与组件拆解
AI CODING · STAGE 1 · COMPONENT CONTRACT
先写 props、events 和页面责任,再整理 AI 任务卡。此时不创建 component、domain 或 data 文件。
时间 40–60 分钟组件 2输出 待执行任务卡
契约先于实现
StagePicker · stages / modelValueupdate:modelValue(StageId)RecommendationCard · itemopen(recommendationId)
冻结两个组件的契约
text
StagePicker
输入:stages、modelValue
输出:update:modelValue(StageId)
RecommendationCard
输入:item
输出:open(recommendationId)StagePicker 不读取推荐数据。用户选择阶段后,它只把新的 StageId 发给父页面。
RecommendationCard 不决定 URL。用户打开卡片时,它只发出 recommendationId。同一张卡片以后放到收藏页或搜索页时,不需要改导航逻辑。
把契约写成 TypeScript 后,应接近下面这样:
ts
// StagePicker.vue
import type { Stage, StageId } from "../domain/stages";
defineProps<{
stages: readonly Stage[];
modelValue: StageId;
}>();
const emit = defineEmits<{
"update:modelValue": [value: StageId];
}>();ts
// RecommendationCard.vue
import type { Recommendation } from "../domain/recommendations";
const { item } = defineProps<{ item: Recommendation }>();
const emit = defineEmits<{ open: [id: string] }>();这两段只冻结编译期契约,不规定 CSS、文案或 DOM 层级。AI 可以调整展示实现,不能把 StageId 降成 string,也不能把 open 改成 component 内部导航。
页面保留状态和导航
首页负责三件事:
- 保存当前
StageId。 - 调用 domain 的筛选函数。
- 收到
open(recommendationId)后导航到详情页。
首页不声明阶段数组,不手写筛选规则。详情页按 URL 中的 ID 调用 domain 查找函数。
1.4 创建 domain 和 data 后再接 component。现在直接让 AI 写首页,它很可能把阶段常量、筛选和导航一起塞进 component,后面的 diff 很难拆。
看见这种 Diff 就停
diff
<script setup lang="ts">
+const stages = [
+ { id: "pregnancy", name: "孕期" },
+ { id: "future-stage", name: "未约定阶段" },
+]
+const visible = computed(() =>
+ recommendations.filter((item) => item.stageIds.includes(selected.value)),
+)
+function open(id: string) {
+ uni.navigateTo({ url: `/pages/detail/index?id=${id}` })
+}
</script>这里同时出现了三类问题:component 新建阶段真源、component 执行筛选、component 决定 URL。不要继续补类型或兼容代码;把阶段和筛选移回 domain,把导航移回 page。
保存这张任务卡
把任务卡保存到本阶段工作记录。1.4 完成 domain 和 data 后再执行。
text
Task
为阶段 1 首页拆出阶段选择和推荐卡片两个组件。
Allowed files
- 创建 apps/web/src/components/StagePicker.vue
- 创建 apps/web/src/components/RecommendationCard.vue
- 修改 apps/web/src/pages/index/index.vue
Do not modify
- apps/web/src/domain/stages.ts
- apps/web/src/domain/recommendations.ts
- apps/web/src/data/recommendations.ts
- package.json、lockfile、build config
- 任何 Mock 数据结构
Contract
- StagePicker 接收 stages、modelValue
- StagePicker 发出 update:modelValue(StageId)
- RecommendationCard 接收 item
- RecommendationCard 发出 open(recommendationId)
- 首页负责状态、筛选和导航
Validation
- npm run test:web,预期 11 passed
- npm run build:web,预期 exit 0
- H5 四条路径由工程师人工检查
Return
- 修改文件清单
- test 与 build 的实际输出
- diff 摘要
- 未执行的人工检查
先复述 allowed files、do not modify、props/events 和 validation。
我确认后再修改。AI 复述时,允许范围应正好是两个 component 和首页。它若要求同时修改 domain 或 data,任务还没有拆干净。
详情页单独发一张卡
text
Task
补齐阶段 1 推荐详情页。
Allowed files
- 创建 apps/web/src/pages/detail/index.vue
- 修改 apps/web/src/pages.json
Do not modify
- apps/web/src/domain/
- apps/web/src/data/
- apps/web/src/components/
- package.json、lockfile、build config
Query contract
- 从 onLoad(query) 读取 query.id
- query.id 不是 string 时按空 ID 处理
- 使用 findRecommendation(RECOMMENDATIONS, id)
- 不在页面复制 Mock 数据
Behavior
- 合法 ID 显示标题、摘要、推荐依据和注意事项
- 非法 ID 显示“没有找到这条推荐”
Validation
- npm run build:web,预期 exit 0
- npm run dev:web 后人工检查“南瓜泥入门”和不存在 ID
Return
- 修改文件
- build 的实际输出
- diff 摘要
- 未执行的人工检查
先复述 allowed files、do not modify、query contract 和 validation。
确认后再修改。component task 与 detail task 分开执行。第一组出错时只检查 component 和首页;第二组出错时只检查 route registration、query 和 detail lookup。
执行任务时看 Diff
1.4 运行任务卡后,直接打开这三个文件的 diff:
bash
git diff -- apps/web/src/components/StagePicker.vue \
apps/web/src/components/RecommendationCard.vue \
apps/web/src/pages/index/index.vue按顺序检查:
StagePicker.vue是否只接收stages、modelValue。RecommendationCard.vue是否只接收item。- events 是否分别为
update:modelValue和open。 - 首页是否接收 events,并调用 domain 完成筛选与导航。
- 三个文件里是否复制了阶段 ID、阶段数组或推荐规则。
npm run test:web 只覆盖 domain 回归,npm run build:web 只说明可以编译。component event、route param 和页面查询要靠四条 H5 路径确认。
实现结果不符合契约时
| 现象 | 处理 |
|---|---|
| AI 修改了 domain 或 data | 从当前任务移出这些改动,回到 allowed files |
| props / events 类型不匹配 | 对照固定契约修 component;不要在页面加兼容分支 |
| 列表或导航不对 | 查首页是否接收 event 并调用既定 domain 函数 |
| component 出现阶段数组 | 删除重复常量,继续从 domain/stages.ts 引用 |
任务卡和 Review 清单准备好后,进入 1.4 用 Mock 数据跑通首屏。