Appearance
场景二:晨悦·生活小程序 · 前端从 0 到 1
把场景一的同一条主路径,做成能跑的前端工程:先定目录,再定字段,再用给 AI 的 Prompt 让 AI 按块生成。
AI CODING · 场景二 · 前端
场景一证明「能点」。这里要目录各管各的、组件约定清楚、数据先用假的——别一上来让 AI 整站糊完。
大约 1~2 天主路径 用餐场景 → 列表 → 详情数据 先 Mock
本节要点
- 场景二四页各干什么、按什么顺序点
- 默认切片的字段约定(场景三接口要对齐)
- Mock 域层 Prompt + 浏览器怎么验
和场景一差在哪
| 场景一 | 场景二 | |
|---|---|---|
| 形态 | 少量静态 HTML | pages / components / domain / data |
| 证明什么 | 主路径能点 | AI 按约定改,不会把筛选、跳转糊进卡片里 |
| 预览 | 双击打开 | 开发预览(H5 或小程序工具) |
壳和切片壳仍是晨悦·生活小程序:真仓有家庭成员设置(宝宝 / 老人 / 毛孩子 / 孕期等)与主题解锁,小悦也会引导「设置家庭成员」。本课默认练「今天吃什么」:选用餐场景 → 菜品列表 → 详情。不练成员页、不练定位转盘;换成订单列表、课程目录也行——流程不变,改名字和字段即可。
本场景怎么走
按顺序打开子页,不要跳着让 AI「一次写完小程序」:
- 技术选型 — 栈选什么、目录写进可
@的备忘 - 本页下方 Mock — 类型、假数据、筛选/查找先就绪
- 页面拆解与 Prompt — 两个组件 + 首页 / 详情 Prompt
- 避坑实录 — 看 diff、纠错话术
场景一的验收没过,先别进这里。
默认主路径和字段
text
打开首页
→ 选一个用餐场景(例:一人食)
→ 看到该场景下的菜品卡片
→ 点开一张:菜名、摘要、推荐依据、小贴士字段先锁死(场景三 API 按同一套对齐,或单独写对照表):
ts
type MealSceneId = "family" | "solo" | "quick" | "soup";
type Dish = {
id: string;
title: string;
summary: string;
sceneIds: MealSceneId[];
reason: string;
tip: string;
};假数据至少:4 个用餐场景、5 条菜品。示例一条:
ts
{
id: "dish-tomato-egg",
sceneIds: ["family", "solo", "quick"],
title: "番茄炒蛋",
summary: "番茄炒出汁,加一点糖提鲜;鸡蛋先炒再合。",
reason: "家常、快手,一人食也够一盘。",
tip: "番茄先烫一下更好去皮;出锅再撒葱花。",
}用餐场景列表示意:
ts
export const MEAL_SCENES = [
{ id: "family", name: "家庭" },
{ id: "solo", name: "一人食" },
{ id: "quick", name: "快手" },
{ id: "soup", name: "汤羹" },
] as const;换切片时:把「用餐场景」改成「类目」等,枚举换掉即可,筛选函数形状不用变。
目录怎么分工
| 目录 | 负责 | 不要出现 |
|---|---|---|
pages | 当前选中谁、调筛选、跳转 | 再抄一份过滤规则 |
components | 展示 + 把点击抛给页面 | 自己 navigateTo、自己维护场景表 |
domain | 类型和纯函数(校验、筛选、查找) | 请求网络、改样式 |
data | Mock 列表 | 第二套场景 id 字符串 |
首页接线(组件卡跑通后)
页面只干三件事:记住当前用餐场景、调筛选、收到卡片 open 后再跳转。
ts
const selectedScene = ref<MealSceneId>("solo");
const visible = computed(() =>
dishesForScene(DISHES, selectedScene.value),
);
function onOpen(id: string) {
uni.navigateTo({ url: `/pages/detail/index?id=${id}` });
}模板:ScenePicker 绑当前场景;列表渲染 DishCard,@open="onOpen"。
Mock:先做这一步
不要一上来让 AI 写首页。建议顺序:
text
用餐场景与类型
→ 筛选 / 按 id 查找
→ 5 条 Mock
→ 再去做组件与页面(Prompt 页)
→ 浏览器点四条路径筛选与查找的目标形态:
ts
export function dishesForScene(
items: readonly Dish[],
sceneId: MealSceneId,
): readonly Dish[] {
return items.filter((item) => item.sceneIds.includes(sceneId));
}
export function findDish(
items: readonly Dish[],
id: string,
): Dish | undefined {
return items.find((item) => item.id === id);
}给 AI 的 Prompt · 域层 + Mock
给 AI · Prompt · 域层与假数据
text
【目标】实现 MealSceneId、Dish、mealScenes 列表、dishesForScene、findDish,以及 5 条 Mock。
【允许】domain/*、data/*、对应测试文件
【禁止】components、pages、package.json、lockfile
【验收】
- 有测试:相关用例全绿
- 无测试:打印 solo 过滤结果至少 1 条
【请你】先复述类型字段和两个函数签名;我确认后再写。组件接上之后,浏览器怎么点
- 默认场景下列表不是空的
- 换一个用餐场景,列表内容会变
- 打开「番茄炒蛋」(或你的第一条)详情字段齐全
- 故意用不存在的 id → 有空态提示,不是白屏
派活时注意
和总览里「跟 AI 怎么协作」一样,这里再钉三条:
- 一次只做一块:先 domain,再组件,再某一页
- 约定写进给 AI 的 Prompt(props / 事件),再让它写实现
- 验收用页面路径和控制台原文,不靠它口头「好了」
细节 Prompt 在 页面拆解与 Prompt;翻车话术在 避坑实录。
再进场景三之前
- [ ] 开发预览能开
- [ ] 主路径能点;错误 id 有空态
- [ ] 选择器 / 卡片约定没被放宽成「随便 string」
- [ ] 选型备忘和真实目录对得上
- [ ] 没有无关的 lockfile 大改