# 顾客小程序原型:flows.md > 机制差异提示(2026-09-23):以下为旧H5快照的可执行动线。[一周无忧计划](../../../architecture/05-domain/WEEKLY-CARE-PLAN.md)要求逐日主动确认;自动配送、固定20:00截单和自动原路退款仍属旧演示行为,不能当新机制已确认政策。场景与实现同步待后续工作。 > 模块:`customer-miniapp` > 当前真相:本文件维护最新 H5 Concept Demo 的完整动线集合,不创建 per-REQ/per-round 副本。 > 关联原型:`index.html`、`h5-concept-demo.html` 与 `source/dingwei-meat-market/`。 > 关联场景:`scenario-model.json` / `cases.json` / `scenario-coverage.json` / `fixture-contract.json`。 > 说明:以下路径是设计审查和未来浏览器 E2E 的共同脚本;当前源码没有接入真实 API,也没有声称已经有产品 E2E 证据。 > 说明:当前 Runtime 没有绑定 REQ;场景矩阵中的 `REQ-DESIGN-INPUT/FR-*` 只是设计输入载体,不是锁定需求。 ## 1. 模块范围与路径目录 | Flow ID | 路径 ID | 用户目标 / 场景 | 类型 | 起点 | 终点 | Story / CASE | 原型区域 | source_refs | Spec | |:---|:---|:---|:---|:---|:---|:---|:---|:---|:---| | F-001 | `PATH-MARKET-BROWSE` / `PATH-MARKET-SOLDOUT` | 找到肉品、查看 Meat ID、处理售罄 | happy / error | `market` | `basket` / 可恢复售罄 | S-001 / CASE-MARKET-* | 肉市与导购 | `source:src/views/Market.tsx` | 未来 `web/e2e/customer-miniapp/F-001.spec.ts` | | F-002 | `PATH-PLAN-DRAFT` / `PATH-PLAN-EMPTY` | 安排一周餐次并生成采购内容 | happy / empty | `plan` | `basket` / 可解释空态 | S-002 / CASE-PLAN-* | 一周计划 | `source:src/views/Plan.tsx` | 未来 `web/e2e/customer-miniapp/F-002.spec.ts` | | F-003 | `PATH-BASKET-CHECKOUT` / `PATH-BASKET-EMPTY` / `PATH-PAYMENT-SUCCESS` / `PATH-PAYMENT-FAILED` | 核对肉篮、配送、模拟支付 | happy / empty / error | 悬浮肉篮或计划采购 | `order` / 保留 `checkout` | S-003 / CASE-BASKET-*、CASE-CHECKOUT-* | 肉篮与结算 | `source:src/views/Basket.tsx`; `source:src/views/Checkout.tsx` | 未来 `web/e2e/customer-miniapp/F-003.spec.ts` | | F-004 | `PATH-DELIVERY-CONFIRM` / `PATH-DELIVERY-CUTOFF` | 确认配送波次或体验退款边界 | happy / boundary | 首页配送卡或订单 | 波次确认 / 退款状态 | S-004 / CASE-DELIVERY-* | 订单与配送 | `source:src/services/delivery.ts` | 未来 `web/e2e/customer-miniapp/F-004.spec.ts` | | F-005 | `PATH-SUBSCRIPTION-ACTIVE` / `PATH-SUBSCRIPTION-INACTIVE` | 保存家庭设置并了解订阅 | happy / empty | `mine` | `plan`(下周)或解释页 | S-006 / CASE-SUBSCRIPTION-* | 我的与长期服务 | `source:src/views/Mine.tsx` | 未来 `web/e2e/customer-miniapp/F-005.spec.ts` | | F-006 | `PATH-TRACE-VIEW` / `PATH-TRACE-RETRY` | 查看档案并恢复关键失败状态 | happy / retry | 商品、订单或体验设置 | Meat ID / 原入口 | S-005 / CASE-TRACE-* | 状态与边界 | `source:src/views/Demo.tsx`; `source:src/views/Product.tsx` | 未来 `web/e2e/customer-miniapp/F-006.spec.ts` | ## 2. 共享前置与测试数据 | ID | 类型 | 内容 | 适用路径 | |:---|:---|:---|:---| | `PRE-DEMO-CUSTOMER` | 身份 | 建立合成顾客;不连接真实账号;固定演示时间从 2026-09-07 开始 | 全部路径 | | `DATA-MARKET` | 商品 | 使用 `src/data/mock.ts` 中的本地商品、菜谱、图片和标准重量/切法 | F-001、F-003、F-006 | | `DATA-PLAN-DRAFT` | 计划 | 固定 2 人家庭、午餐/晚餐餐次和可替换菜谱;计划与订单分离 | F-002、F-005 | | `DATA-BASKET` | 肉篮 | 预置至少一项 market/plan 来源商品;未支付、未创建订单 | F-003 | | `DATA-DELIVERY` | 订单 | 预置两波配送,固定北京时区 20:00 截单与各波 itemIds | F-004 | | `DATA-FAULT` | 状态 | 通过 `DemoPage` 切换 loading、network、sold-out、batch-sold、payment-failed、meat-id-error 等演示故障 | F-001、F-003、F-006 | > 仅业务入口本身是深链时才允许 URL 直跳;正常路径从声明的上游页面点击进入。未来 E2E 必须使用隔离 fixture,不得手改 localStorage 绕过页面导航。 ## 3. 路径定义 ### F-001 / PATH-MARKET-BROWSE:从肉市选择标准规格 | 项 | 内容 | |:---|:---| | 触发 | 顾客进入肉市,想为下一顿买一份肉 | | 角色 | `anonymous-shopper` | | 前置 | `PRE-DEMO-CUSTOMER`、`DATA-MARKET`,商品可浏览 | | 关联故事 | S-001 | | 关联 CASE | `CASE-MARKET-ALLOW` | | 覆盖分支 | `BR-MARKET-ALLOW` | | 入口 | `market` 页面上的搜索、分类、今日鲜切或菜谱卡 | | 允许 URL 直跳 | no | | 预期终点 | 选择重量/切法/份数后加入肉篮;可打开 Meat ID | | 原型和合同映射 | `h5-concept-demo.html` 肉市与导购;`source/src/views/Market.tsx`、`Product.tsx` | | 步骤 ID | 用户动作 | 目标控件 / 稳定标签 | 输入或选择 | 期望可见结果 | 原型区域 | |:---|:---|:---|:---|:---|:---| | `F-001-001` | 点击 | `肉市` | N/A | 进入 `market`,看到今日鲜切和底部导航 | `market` | | `F-001-002` | 点击 | `搜索商品、部位、菜名或场景` | N/A | 进入 `search`,搜索/分类状态可见 | `search` | | `F-001-003` | 点击 | 商品名或商品图 | `pork-shoulder` | 进入 `product`,看到 Meat ID、标准重量和切法 | `product` | | `F-001-004` | 点击 | 重量/切法选择 | `500g` / `切丝` | 当前规格、份数和金额更新 | `product` | | `F-001-005` | 点击 | `加入肉篮` | N/A | 肉篮数量更新,仍可继续浏览 | `product` / 肉篮悬浮入口 | | `F-001-006` | 点击 | `肉品身份证` | N/A | `meat-id` 显示批次档案和时间线 | `meat-id` | **路径完成断言** - 商品事实、标准重量、切法和肉篮数量可见。 - Meat ID 是独立档案查看,不暗示已经支付或已经履约。 - 未触发真实订单、支付或对外消息。 ### PATH-MARKET-SOLDOUT:售罄后保持可恢复 商品或当前批次售罄时,进入同一 `product` 页面,显示售罄原因并禁用加入动作;顾客可以返回搜索/肉市查看其他商品。覆盖 `BR-MARKET-REJECT`,不得改变肉篮数量。 **E2E 转录 note**:未来 Playwright 使用 `data-test=tab-market`、`data-test=market-search`、`data-test=product-card-pork-shoulder`、`data-test=product-add`、`data-test=meat-id-entry`;当前源码以可访问名称和 route 组件作为观察锚点,尚未提交这些 hook。 ### F-002 / PATH-PLAN-DRAFT:安排一周餐桌并生成肉篮 | 项 | 内容 | |:---|:---| | 触发 | 顾客不想逐个选商品,想按家庭安排一周餐次 | | 角色 | `household-planner` | | 前置 | `PRE-DEMO-CUSTOMER`、`DATA-PLAN-DRAFT` | | 关联故事 | S-002 | | 关联 CASE | `CASE-PLAN-ALLOW` | | 覆盖分支 | `BR-PLAN-ALLOW` | | 入口 | 底部 `计划` Tab | | 允许 URL 直跳 | no | | 预期终点 | 计划状态清楚,选择菜谱/推荐后生成肉篮 | | 原型和合同映射 | `h5-concept-demo.html` 一周计划;`source/src/views/Plan.tsx` | | 步骤 ID | 用户动作 | 目标控件 / 稳定标签 | 输入或选择 | 期望可见结果 | 原型区域 | |:---|:---|:---|:---|:---|:---| | `F-002-001` | 点击 | `计划` | N/A | 显示一周餐轨、已安排/待安排状态 | `plan` | | `F-002-002` | 点击 | 日期与 `午餐`/`晚餐` | `周二 / 午餐` | 只展开选中日期和时段 | `plan` | | `F-002-003` | 点击 | `安排一顿` 或 `帮我推荐` | N/A | 进入 `add-meal` 或 `recommendations` | `add-meal` / `recommendations` | | `F-002-004` | 点击 | 推荐卡 / `为什么这样推荐` | N/A | 看到理由、家庭条件和替换入口 | `why` | | `F-002-005` | 点击 | `确认餐次` | N/A | 计划写入当前示例状态,返回餐轨 | `plan` | | `F-002-006` | 点击 | `Balance` / `生成肉篮` | N/A | 看到肉类采购估算并进入 `basket` | `balance` / `basket` | **路径完成断言** - 餐次、菜谱、重量和来源可见;不同餐次不会互相覆盖。 - 生成肉篮是采购草稿,不是已支付订单。 - 计划测试可验证同日午晚餐、多菜和重复生成的保持规则。 ### PATH-PLAN-EMPTY:空计划恢复 计划为空时显示“本周还没有安排”和“安排第一顿”,并提供回肉市/回首页动作;不填充假商品、不生成肉篮。覆盖 `BR-PLAN-REJECT`。 **E2E 转录 note**:未来使用 `data-test=tab-plan`、`data-test=meal-day-2`、`data-test=meal-period-lunch`、`data-test=plan-add-meal`、`data-test=plan-recommendations`、`data-test=plan-generate-basket`;当前以可见中文标签和 `Plan.tsx` 组件为设计锚点。 ### F-003 / PATH-BASKET-CHECKOUT:核对肉篮并完成模拟支付 | 项 | 内容 | |:---|:---| | 触发 | 顾客从肉市或计划进入肉篮 | | 角色 | `anonymous-shopper` / `household-planner` | | 前置 | `PRE-DEMO-CUSTOMER`、`DATA-BASKET`,地址和配送时段为示例值 | | 关联故事 | S-003 | | 关联 CASE | `CASE-BASKET-ALLOW`、`CASE-CHECKOUT-ALLOW` | | 覆盖分支 | `BR-BASKET-ALLOW`、`BR-CHECKOUT-ALLOW` | | 入口 | 悬浮肉篮或桌面“我的肉篮” | | 允许 URL 直跳 | no | | 预期终点 | 模拟支付成功后显示订单快照和配送信息 | | 原型和合同映射 | `h5-concept-demo.html` 肉篮与结算;`Basket.tsx`、`Checkout.tsx`、`Orders.tsx` | | 步骤 ID | 用户动作 | 目标控件 / 稳定标签 | 输入或选择 | 期望可见结果 | 原型区域 | |:---|:---|:---|:---|:---|:---| | `F-003-001` | 点击 | `打开肉篮` | N/A | 显示来源、日期、餐次、数量和肉篮合计 | `basket` | | `F-003-002` | 点击 | 商品编辑 | `500g` / `薄片` / `2份` | 商品草稿更新,合计重新计算 | `basket` | | `F-003-003` | 点击 | `去预约` / `进入结算` | N/A | 进入 `checkout`,显示地址、配送波次、商品和金额 | `checkout` | | `F-003-004` | 点击 | 地址或配送时段 | 示例地址 / `17:00–19:00` | 当前选择可见;不可用时提示恢复 | `checkout` | | `F-003-005` | 点击 | `确认并支付` | N/A | 进入模拟支付处理,不直接伪造成功 | `checkout` | | `F-003-006` | 点击 | `查看订单` | N/A | `success`/`order` 显示订单号、配送时段和状态 | `success` / `order` | ### PATH-BASKET-EMPTY:空肉篮恢复 肉篮为空时显示可解释空态,并回到肉市或计划;覆盖 `BR-BASKET-REJECT`。 ### PATH-PAYMENT-SUCCESS:模拟支付成功 有效结算上下文进入模拟支付,成功后显示订单号和预约状态;不得把结果解释为真实扣款。 ### PATH-PAYMENT-FAILED:支付失败恢复 通过概念体验设置进入 `payment-failed`,结算页显示失败原因和重试;肉篮与地址/配送上下文不清空,覆盖 `BR-CHECKOUT-REJECT`。 **E2E 转录 note**:未来使用 `data-test=basket-orb`、`data-test=basket-item`、`data-test=basket-edit`、`data-test=checkout-entry`、`data-test=checkout-address`、`data-test=checkout-slot`、`data-test=checkout-submit`、`data-test=order-detail`;支付成功必须断言可见状态,不断言真实资金。 ### F-004 / PATH-DELIVERY-CONFIRM:独立确认配送波次 | 项 | 内容 | |:---|:---| | 触发 | 顾客看到首页配送卡或打开预约订单 | | 角色 | `scheduled-delivery-customer` | | 前置 | `PRE-DEMO-CUSTOMER`、`DATA-DELIVERY`;演示时钟在北京时间 19:55 附近 | | 关联故事 | S-004 | | 关联 CASE | `CASE-DELIVERY-ALLOW` | | 覆盖分支 | `BR-DELIVERY-ALLOW` | | 入口 | `market` 首页配送卡或 `order` | | 允许 URL 直跳 | no | | 预期终点 | 选中配送波次变为已确认;自动配送跨过截单仍保留 | | 原型和合同映射 | `h5-concept-demo.html` 订单与配送;`delivery.ts`、`delivery.test.mjs` | | 步骤 ID | 用户动作 | 目标控件 / 稳定标签 | 输入或选择 | 期望可见结果 | 原型区域 | |:---|:---|:---|:---|:---|:---| | `F-004-001` | 点击 | `配送确认体验` | N/A | 首页展示当前配送波次、商品、地址和截止时间 | `market` | | `F-004-002` | 点击 | `确认这次配送` | 选中波次 A | 只更新波次 A 的确认时间/来源 | 配送卡 | | `F-004-003` | 点击 | 波次切换 | 波次 B | 波次 B 独立显示,不继承 A 的确认状态 | 配送 tabs | | `F-004-004` | 点击 | `自动配送` | N/A | 订单显示自动模式和后续截止行为 | `demo` / `order` | | `F-004-005` | 点击 | `订单详情` | N/A | 看到配送明细和状态 | `order` | ### PATH-DELIVERY-CUTOFF:截单后停送退款 将演示时钟推进到北京时间 20:00 后,未确认波次不能补确认,进入停送/退款处理中;约 5 秒后示例状态变为已退款;已确认或自动配送波次不被错误退款。覆盖 `BR-DELIVERY-REJECT`。 **E2E 转录 note**:未来使用 `data-test=delivery-card`、`data-test=delivery-wave`、`data-test=delivery-confirm`、`data-test=delivery-auto`、`data-test=delivery-refund-status`;时间边界应使用固定 clock fixture,不使用真实等待。 ### F-005 / PATH-SUBSCRIPTION-ACTIVE:维护家庭并体验订阅 | 项 | 内容 | |:---|:---| | 触发 | 顾客想调整家庭习惯或了解下周建议 | | 角色 | `household-planner` | | 前置 | `PRE-DEMO-CUSTOMER`,可读 `mine` 页面和示例家庭 | | 关联故事 | S-006 | | 关联 CASE | `CASE-SUBSCRIPTION-ALLOW` | | 覆盖分支 | `BR-SUBSCRIPTION-ALLOW` | | 入口 | `mine` → 家庭卡/订阅卡 | | 允许 URL 直跳 | no | | 预期终点 | 家庭设置可保存;订阅体验生成下周示例建议并进入 `plan` | | 原型和合同映射 | `h5-concept-demo.html` 我的与长期服务;`Mine.tsx` | | 步骤 ID | 用户动作 | 目标控件 / 稳定标签 | 输入或选择 | 期望可见结果 | 原型区域 | |:---|:---|:---|:---|:---|:---| | `F-005-001` | 点击 | `我的` | N/A | 显示家庭、订单、订阅和服务入口 | `mine` | | `F-005-002` | 点击 | `我的家庭` | N/A | 编辑人数、餐数、目标和偏好 | `family` | | `F-005-003` | 点击 | `保存家庭设置` | 示例家庭值 | 返回 `mine`,计划可读取新设置 | `family` | | `F-005-004` | 点击 | `了解鼎味订阅` | N/A | 显示订阅价值、边界和免费能力 | `subscription` | | `F-005-005` | 点击 | `体验订阅 · 看看下周建议` | N/A | 显示已开启状态并导航到下周计划 | `subscription` / `plan` | ### PATH-SUBSCRIPTION-INACTIVE:未开启订阅 订阅未开启时展示说明和唯一的体验入口;不显示已扣费、自动续费或真实会员权益。结束体验后已有计划保留,覆盖 `BR-SUBSCRIPTION-REJECT`。 **E2E 转录 note**:未来使用 `data-test=tab-mine`、`data-test=family-entry`、`data-test=family-save`、`data-test=subscription-entry`、`data-test=subscription-activate`、`data-test=subscription-end`。 ### F-006 / PATH-TRACE-VIEW:Meat ID 与状态恢复 | 项 | 内容 | |:---|:---| | 触发 | 顾客想查看来处,或评审人员主动切换异常状态 | | 角色 | `service-reviewer` | | 前置 | `PRE-DEMO-CUSTOMER`、`DATA-MARKET`、`DATA-FAULT` | | 关联故事 | S-005 | | 关联 CASE | `CASE-TRACE-ALLOW` | | 覆盖分支 | `BR-TRACE-ALLOW` | | 入口 | 商品/订单/我的页 Meat ID 入口或 `demo` | | 允许 URL 直跳 | no | | 预期终点 | 档案完整可读,或失败后通过原入口重试 | | 原型和合同映射 | `h5-concept-demo.html` 状态与边界;`Demo.tsx`、`Product.tsx` | | 步骤 ID | 用户动作 | 目标控件 / 稳定标签 | 输入或选择 | 期望可见结果 | 原型区域 | |:---|:---|:---|:---|:---|:---| | `F-006-001` | 点击 | `概念体验设置` | N/A | 打开状态场景列表 | `demo` | | `F-006-002` | 点击 | `页面加载中` | N/A | 显示 loading 骨架和等待反馈 | `state` | | `F-006-003` | 点击 | `Meat ID 加载失败` | N/A | `meat-id` 显示失败原因和重试动作 | `meat-id` | | `F-006-004` | 点击 | `重新加载 Meat ID` | N/A | 关闭故障模拟并显示档案或回到肉市 | `meat-id` | | `F-006-005` | 点击 | `关闭异常模拟` | N/A | 恢复正常演示状态,不改订单/肉篮事实 | `demo` | ### PATH-TRACE-RETRY:Meat ID 失败恢复 网络中断、图片失败、Meat ID 失败、售罄和空集合必须显示各自原因/恢复动作;不得以同一个成功态覆盖。覆盖 `BR-TRACE-REJECT`,并与 F-001/F-003 的故障路径回归。 **E2E 转录 note**:未来使用 `data-test=demo-entry`、`data-test=state-loading`、`data-test=state-meat-id-error`、`data-test=state-retry`、`data-test=demo-close-fault`;状态切换必须通过可见控件完成。 ## 4. 模块交互覆盖核对 | 原型区域 / 控件 | 用户意图 | 覆盖路径 | 状态 / N/A 理由 | |:---|:---|:---|:---| | 全局 / `肉市`、`计划`、`我的` Tab | 切换主模块 | F-001、F-002、F-005 | covered | | 全局 / `打开肉篮` 悬浮入口 | 查看采购内容 | F-003 | covered | | 全局 / 更多菜单 | 打开肉篮、概念体验、回肉市 | F-003、F-006 | covered | | 肉市 / 地址行 | 查看或更换配送地址 | F-003、F-005 | covered | | 肉市 / 搜索、分类、场景 chips | 找商品/菜谱/部位 | F-001 | covered | | 肉市 / 配送卡、波次切换 | 确认配送 | F-004 | covered | | 商品 / 重量、切法、份数、加入、收藏 | 形成肉篮草稿 | F-001、F-003 | covered | | 商品 / Meat ID | 查看来源档案 | F-001、F-006 | covered | | 菜谱 / 按这道菜买肉、安排进计划 | 进入采购或计划 | F-001、F-002 | covered | | 计划 / 日期、午餐/晚餐、安排一顿、推荐、理由、Balance | 编排餐轨 | F-002 | covered | | 肉篮 / 编辑、删除、去预约 | 调整采购并进入结算 | F-003 | covered | | 结算 / 地址、时段、确认并支付 | 发起模拟预约 | F-003 | covered; no real payment | | 订单 / 查看、取消预约、售后 | 查看履约模型 | F-003、F-004 | covered as demo | | 我的 / 家庭、地址、订阅、历史、收藏、权益 | 管理服务入口 | F-005、F-006 | covered | | 概念体验 / 状态场景、恢复初始、关闭异常 | 评审边界和恢复 | F-006 及各流程异常分支 | covered | ## 5. E2E 执行规则 - [ ] 每条 required 路径在真实产品实现阶段都有独立步骤级证据;当前只完成设计脚本和源码测试,不宣称浏览器 E2E 已完成。 - [ ] 每个 browser-required CASE 绑定至少一条 PATH,且未来 module spec 同时引用 CASE ID 与完整 PATH ID。 - [x] `scenario-coverage.json` 中 required allow/reject branch coverage = 100%,正/负比例满足 ordinary profile。 - [ ] 每条 negative PATH 逐项断言 visible、terminal_state、persisted_effects、forbidden_side_effects、rejection、expected_state 和 recovery;CASE oracle 已先行写明。 - [ ] E2E 从每条路径声明的入口开始,不用未声明 URL 直跳、API 调用、手改状态或隐藏浏览器状态。 - [ ] 每个步骤后的可见结果都要断言;支付、退款和配送边界要保留固定时钟、console/network 摘要或等价证据。 - [x] 当前模块交互覆盖表列出所有声明的主要交互控件;未来实现新增控件必须更新本文件。 - [ ] 实现与当前源码、HTML 页面证据、路径或 CASE oracle 不一致时,记录为 S7 finding,不在 E2E 中自行改变路径标准。