---
url: /courses/web-frontend-framework/commerce-project-delivery/index.md
---
# 第8章：微商城综合项目与交付

前七章分别练过响应式、组件、路由、UI 组件库、接口请求、Pinia 和工程交付。本章不再增加新的 Vue 语法，也不把这些 API 从头念一遍，而是学习怎样把已有知识整理成一份能实施、能验收、能答辩的项目方案。

本章以“校园微商城前台 + 商品管理端”为分析对象，重点学习范围、用户旅程、架构、需求卡、接口契约、协作、异常测试和验收证据。页面开发继续复用前七章知识，本章不再重复完整页面实现。

::: tip 学习说明
本章聚焦项目分析与验收方法，章末安排综合项目任务。
:::

::: tip 项目目标
交付一个可运行、可演示、可复盘的 Vue 3 项目：前台完成商品浏览、详情、购物车与订单确认；管理端完成登录入口、商品列表与编辑。提交项目仓库、运行文档、测试记录和 5 分钟演示。
:::

::: tip 本章学习资源
本章配套资源位于 `resources/ch08/`：`classroom-demo/` 用于观察业务闭环与验收路径，`after-class-starter/` 是章末综合项目的起始工程。学习时应理解分析方法和验收依据，不照抄完整页面代码。
:::

::: tip 🎯 学习梯度指引（分层通关）

* **核心必学（保底通关 · 跑通核心双闭环）**：掌握 8.1、8.2（最小可交付范围与前后台主线）、8.3（项目目录职责与需求卡核心要素）、8.4（Axios 统一 API 模块调用本地 Mock）、8.5（前台购买闭环与管理端 CRUD 闭环）、8.6（可复现 README 编写与 `npm run build` 构建验证）。能够独立交付一个主线跑通、技术分层清晰、无打包报错的微商城项目。
* **进阶选学（🌟 自主拓展 · 健壮性工程防护与高阶表达）**：8.4（领域数据归一化与类型防御）、8.5（全链路异常容错、提交防重锁与版本化持久化自愈）、8.6（Git 规范化提交、Network/Console 排错证据链、5 分钟答辩演练）。供学有余力或有进阶工程需求的学生自主探索，不作为基础达标强制考核。
  :::

## 8.1 本章任务清单与开工顺序

本章先把“要做什么、为什么做、怎样证明做完了”写清楚，再进入独立开发。任务清单明确每个阶段的分析产物和验收依据。

| 任务 | 分析时具体做什么 | 完成后应该看到 | 当堂练习产物 |
| --- | --- | --- | --- |
| 固定范围与用户旅程 | 区分前台、管理端的必做功能和可选扩展，再按步骤写出用户完成目标的过程 | 一眼看出项目先做哪条闭环，不会一开始就堆很多页面 | 一份“登录 → 新增商品”的文字版管理端旅程 |
| 说明架构与需求卡 | 标注路由、页面、组件、API、Store 的职责，把大需求拆成五字段任务卡 | 每个需求都有输入、正常结果、异常状态和验收证据 | 一张“订单确认”需求卡 |
| 统一接口契约 | 写清 Method、Path、输入、成功结果、错误结果和数据归一化位置 | Mock 字段变化时，知道应该在哪一层处理 | 一条价格字段类型变化的边界验证记录 |
| 规划协作与异常测试 | 明确小组角色、检查点和 Git 节奏，列出正常与失败场景 | 每次合并都有可运行检查点，每种失败都有测试记录 | 两条异常场景测试记录 |
| 准备验收与答辩 | 整理运行、功能、异常、工程和表达五类证据 | 验收者只看 README 也能复现，5 分钟内能说明成果和边界 | 一份失败状态演示提纲和两道答辩口述 |

### 开工顺序

:::: steps

1. 写出前台主线：步骤 1 商品列表，步骤 2 商品详情，步骤 3 购物车，步骤 4 订单确认，步骤 5 结果页。
2. 写出管理端主线：步骤 1 登录，步骤 2 后台布局，步骤 3 商品列表，步骤 4 新增/编辑，步骤 5 删除。
3. 给每个步骤标注由路由、接口、组件还是 Store 承担。
4. 先列正常结果，再补加载、空数据、失败、无效参数和权限失效。
5. 按 README 在新目录复现安装、启动和构建，记录实际证据。
6. 准备 5 分钟演示：项目目标、正常路径、失败路径、工程边界和问题复盘。
   ::::

::: tip 完成后应该是什么样
最终不是只得到几张页面截图，而是得到一套能指导开发的分析产物：范围表、两份文字版用户旅程、项目架构、需求卡、接口契约、异常测试记录、README、验收证据和答辩提纲。
:::

## 8.2 知识点一：最小可交付范围与用户旅程

**学习目标**

掌握最小可交付范围和用户旅程的分析方法，能够先按步骤写出一条完整业务闭环，再决定哪些功能以后扩展。

**语法/概念**

“最小可交付范围”不是降低项目质量，而是先保证最重要的业务路径能够完整走通。简单来说，先让用户真正完成一件事，再考虑轮播、头像、动画等扩展内容。

本项目先把功能分成三层：

| 范围 | 前台 | 管理端 | 处理原则 |
| --- | --- | --- | --- |
| 必须完成 | 商品列表、筛选、详情、购物车、订单确认和结果反馈 | 登录入口、后台布局、商品列表、新增、编辑和删除 | 综合项目验收前必须走通 |
| 必须处理的异常 | 加载、空数据、失败、无效商品 id、未知地址 | 未登录、加载、空数据、失败、表单错误、删除取消 | 每种情况都要告诉用户下一步 |
| 可选扩展 | 消息页、个人中心、轮播、更多分类 | 订单管理、图片上传、真实权限矩阵 | 基础闭环验收后再做 |

::: warning 先完成闭环，再扩展页面
可选扩展应在基础闭环稳定后再做。一个能从商品列表走到订单确认、能处理失败并有运行文档的项目，比六个只有静态外观的页面更有价值。
:::

“用户旅程”就是按用户做事的先后顺序，把每一步写出来。每一步不只写页面名，还要标出主要由哪一类技术承担。

| 旅程中的问题 | 要写清楚的内容 |
| --- | --- |
| 用户从哪里开始 | 入口 URL 或按钮 |
| 用户做了什么 | 点击、输入、筛选、提交等动作 |
| 系统怎样响应 | 跳转页面、调用接口、更新 Store 或显示组件 |
| 成功后去哪 | 下一页或新的页面状态 |
| 失败后怎么办 | 错误提示、保留输入、重试或返回入口 |

播放业务闭环，逐步指出每一步主要由路由、接口、组件还是 Store 承担。

```mermaid
flowchart LR
  A[商品列表] -->|动态路由 id| B[商品详情]
  B -->|addItem| C[Pinia 购物车]
  C --> D[订单确认表单]
  D -->|校验通过| E[订单接口]
  E -->|成功| F[结果页]
  E -->|失败| D
```

失败回到订单确认页时必须保留用户仍可修改的输入，并给出重试入口。

::: tip 思考问题
如果商品列表、详情和购物车都有了，但订单提交失败后表单被清空，这条用户旅程算不算完整？为什么？
:::

**课堂演示**

**步骤 1：先圈出前台必须完成的范围。**

从范围表中只保留“列表、详情、购物车、订单确认、结果反馈”，暂时划掉轮播、个人中心和真实支付。

完成后应看到：项目第一轮只有一条清楚的购买闭环，不会同时出现十几个待开发页面。

**步骤 2：按用户动作写前台旅程。**

从“打开商品列表”开始，依次写“筛选商品、进入详情、加入购物车、确认订单、看到结果”，并在每个步骤后标注动态路由、Axios API、Pinia 或表单组件。

完成后应看到：每一个用户动作旁边都有主要技术承担者，不再只写一排页面名称。

**步骤 3：给旅程补失败回路。**

在“提交订单”后增加“失败 → 保留表单 → 显示原因 → 重新提交”，并说明失败时不能清空购物车。

完成后应看到：失败不是旅程终点，用户有明确的下一步。

**步骤 4：用一句话检查闭环。**

从起点顺着箭头完整说明：“用户能从商品列表开始，完成订单；如果失败，能保留资料并重试。”

完成后应看到：一条可以口头说明、也可以实际验收的业务主线。

**当堂练习**

* **【必做任务（基础通关）】**：按“步骤 1、步骤 2、步骤 3”写出“管理端：登录 → 后台商品列表 → 打开新增弹窗并保存”的核心用户旅程（3 步链路），并在每步后标注主要由路由、组件还是接口承担。
* **【选做挑战（🌟 自主拓展）】**：为该旅程补充“未登录访问被路由守卫拦截重定向”与“新增表单校验失败留在弹窗”2 个异常分支，并写出一句新增成功后表格能看到新记录的验收判定。

## 8.3 知识点二：项目架构与需求卡

**学习目标**

掌握项目目录职责和需求卡五字段，能够把“做一个商城”拆成可以分工、可以验收的小任务。

**语法/概念**

项目架构不是为了让目录显得专业，而是为了回答“这件事应该放在哪里”。路由管地址和进入条件，页面管一整页状态，组件管可复用界面，API 管请求，Store 管跨页面共享状态。

::: file-tree title="微商城综合项目结构" icon="colored"

* campus-market/
  * src/
    * api/
      * http.js # Axios 实例
      * products.js # 商品接口
      * orders.js # 订单接口
      * session.js # 登录接口
    * components/
      * product/ # 商品卡片、表格、表单
      * cart/ # 购物车条目与汇总
      * common/ # 空状态、错误状态等通用组件
    * layouts/
      * ShopLayout.vue # 前台布局
      * AdminLayout.vue # 管理端布局
    * router/
      * index.js # 前台、后台与守卫
    * stores/
      * cart.js # 购物车
      * session.js # 最小会话摘要
    * views/
      * shop/ # 列表、详情、购物车、确认、结果
      * admin/ # 登录、工作台、商品管理
    * App.vue
    * main.js
  * .env.example # 公开配置示例
  * package.json
  * package-lock.json
  * README.md
    :::

本结构只表达职责，不要求每组文件数量完全相同。合并或拆分时，要在 README 中说明边界理由。

| 目录或文件 | 职责说明 | 不应该承担的事 |
| --- | --- | --- |
| `router/` | 决定地址对应哪个页面、能不能进入 | 不保存购物车条目 |
| `views/` | 把一页需要的组件和状态组织起来 | 不到处拼完整接口地址 |
| `components/` | 做可复用的小块界面 | 不擅自修改父页面数据 |
| `api/` | 统一请求地址、参数和错误传播 | 不决定按钮放在哪里 |
| `stores/` | 保存多个页面都要读写的业务状态 | 不保存只属于一个弹窗的临时草稿 |

**骨架如何落地**

1. 最终项目使用独立工程，名称和主题可自行确定，不与前七章的章节练习混在一起；
2. 先确认 `main.js` 只负责注册 Router、Pinia 和项目已经选择的 UI 组件库；
3. 再按目录职责建立最小文件，不提前创建用不到的页面；
4. 建立任务板，至少包含商品列表、商品详情、购物车、订单确认、登录、商品管理、Mock 接口和异常状态；
5. 每张任务卡都写入口文件、负责人、正常结果、异常结果和验收证据。

需求卡的作用，是把“做一个页面”改成“完成一种可验证的用户行为”。每张任务卡包含五部分：

| 字段 | 示例 |
| --- | --- |
| 用户目标 | 我想按关键词找到商品 |
| 输入 | URL query `keyword` |
| 正常结果 | 显示匹配商品与总数 |
| 异常状态 | 加载、空数据、接口失败 |
| 验收证据 | 可分享 URL、Network 记录、页面截图 |

**任务 A：商品列表**

* 筛选条件进入 URL query；
* 页面加载时读取 query 并请求；
* 快速搜索不允许旧响应覆盖新结果；
* 空结果与错误结果文案不同。

**任务 B：商品详情**

* `/products/:id` 可直接刷新；
* 无效 id 显示未找到；
* 加入购物车后顶部数量同步；
* 返回列表保留筛选条件。

**任务 C：订单确认**

* 表单字段有标签与校验；
* 提交中禁用重复提交；
* 失败保留草稿；
* 成功后按规则清理购物车并进入结果页。

**任务 D：后台商品管理**

* 表格四态完整；
* 编辑使用草稿，取消不污染列表；
* 删除明确影响范围并确认；
* 无权访问时不发出敏感接口请求。

::: tip 思考问题
“完成商品管理页”为什么不是一张合格的需求卡？还缺少哪几个可验收字段？
:::

**课堂演示**

**步骤 1：把一个大需求放进正确目录。**

以“按关键词查商品”为例：路由保存关键词，商品列表页面组织状态，搜索框组件上报输入，`products.js` 发送请求。

完成后应看到：同一项功能虽然经过多个目录，但每层只负责一项明确职责。

**步骤 2：填写一张商品搜索需求卡。**

依次填写用户目标、输入、正常结果、异常状态和验收证据，不使用“差不多完成”“页面好看”等无法检查的说法。

完成后应看到：验收者只看任务卡，也知道怎样操作和怎样判断通过。

**步骤 3：把需求卡拆给小组。**

页面负责人处理页面四态，数据负责人核对 API，组件负责人处理搜索输入，交付负责人收集 URL、Network 和截图。

完成后应看到：小组成员不再同时修改同一个文件，而是围绕同一验收目标协作。

**步骤 4：检查任务板是否能开工。**

逐项检查任务卡是否有入口文件、负责人、异常状态和验收证据；缺一项就先补齐。

完成后应看到：任务从“想法”变成可以领取、开发和验收的工作项。

**当堂练习**

* **【必做任务（基础通关）】**：为“前台订单确认”填写核心 3 要素需求卡（明确用户目标、输入来源、提交成功后的页面跳转与购物车清空结果）。
* **【选做挑战（🌟 自主拓展）】**：补齐完整 5 要素需求卡，增加“异常状态”（收货人表单未填完整被拦截提示、提交过程中禁用按钮防重复点击）与“验收证据”（可查验的订单号生成与 Network 接口调用记录）。

## 8.4 知识点三：接口契约与 Mock 边界

**学习目标**

掌握接口契约和数据归一化边界，能够在开发页面前统一请求规则，并把 Mock 与页面职责分开。

**语法/概念**

接口契约就是前端和数据来源之间的“约定单”。至少写清 Method、Path、query、body、成功结果和错误结果六个要素。没有契约时，每个页面都会按自己的猜法处理数据，字段一变就到处出错。

项目至少定义以下接口，不把响应结构散落在组件中：

| 领域 | Method | Path | 成功结果 |
| --- | --- | --- | --- |
| 商品列表 | `GET` | `/products` | `{ items, total }` |
| 商品详情 | `GET` | `/products/:id` | `{ product }` |
| 新增商品 | `POST` | `/products` | `{ product }` |
| 修改商品 | `PUT` | `/products/:id` | `{ product }` |
| 删除商品 | `DELETE` | `/products/:id` | `{ success }` |
| 提交订单 | `POST` | `/orders` | `{ orderId }` |
| 登录 | `POST` | `/session` | `{ user, accessToken }` |

Mock 只负责模拟接口行为，例如返回商品、延迟、空数组或错误。页面仍然必须经过 API 模块调用业务函数，不能把一份假数据分别复制到列表页、详情页和管理页。

“领域归一化”就是在数据刚进入前端时，把不稳定的外部格式转成项目内部统一格式。例如价格统一为数字、id 统一为字符串。这样页面只认稳定格式，不需要每个模板自己补救。

| 层 | 应该知道什么 | 不应该知道什么 |
| --- | --- | --- |
| Axios 实例 | 基础地址、超时、响应与错误传播 | 商品卡片怎样显示 |
| API 模块 | 商品、订单、登录等业务接口 | 页面加载动画放在哪里 |
| 领域转换 | 字段类型和默认值 | 当前路由地址 |
| 页面 | 业务函数返回的稳定数据和页面四态 | 完整 URL、Mock 内部实现 |

::: tip 思考问题
哪些模块应该知道 Axios，哪些模块只应该知道商品或订单业务函数？如果 `price` 从数字变成字符串，最先应该在哪一层处理？
:::

**课堂演示**

**步骤 1：给“商品列表”补全六要素。**

在契约表中补充：query 为关键词和分页信息，body 为无，成功结果为 `{ items, total }`，错误结果至少包含状态码和可显示消息。

完成后应看到：契约不只是一条 URL，而是一份能被前端、Mock 和验收共同使用的说明。

**步骤 2：查看领域边界的最小示例。**

下面只保留这一处完整开发代码，用来说明 API 模块隔离 HTTP 细节、领域函数统一字段格式。其余页面开发继续复用前七章知识完成。

### 契约示例：建立项目契约

这一部分不直接给出整套项目答案。先建立“领域类型—API 模块—页面四态”的最小契约，再由小组独立完成页面。负责隔离 HTTP 细节的目录命名为 **api**。

问题：哪些模块应该知道 Axios，哪些模块只应该知道商品或订单业务函数？

完成后应看到：请求函数只负责商品接口，`normalizeProduct` 只负责把外部字段变成页面可稳定使用的格式。

**步骤 3：用契约表检查 Mock。**

在 Network 面板中核对商品列表请求的方法、路径、状态码和响应结构，再与契约表逐项比较。

完成后应看到：接口是否符合约定有实际证据，不再依靠“页面看起来能用”来判断。

**步骤 4：说明字段变化应该兜在哪里。**

把一条 Mock 商品的价格临时改成字符串，并沿数据流观察：Mock 返回原始值，领域转换统一为数字，页面仍按数字显示。

完成后应看到：字段格式变化只需要在边界处理，不需要同时修改多个页面。

::: tip 🌟 进阶选学：前端领域数据归一化与类型防御

* **为什么需要归一化**：在真实前后端联调中，服务端返回的金额可能有时是数字 `29.9`，有时是字符串 `"29.90"`，或者库存缺省为 `null`。如果在 Vue 模板中直接写 `price.toFixed(2)`，遇到字符串或 `null` 就会直接报错白屏。
* **数据防腐层（Anti-Corruption Layer）**：在 API 层和 UI 组件之间引入 `normalizeProduct` 函数，专门负责把外部不稳定数据洗净并赋默认兜底值（如 `Number(raw.price || 0)`）。一旦接口字段微调，只需修改领域函数，而无需在全工程十几个组件模板中逐个打补丁。
  :::

**当堂练习**

* **【必做任务（基础通关）】**：在 `src/domain/product.js` 中使用 `Number(raw.price || 0)` 编写归一化转换函数；临时把 Mock 中一件商品的 `price` 改成字符串 `"99.9"`，验证商品列表和详情页仍能正常计算总价，页面不崩溃。
* **【选做挑战（🌟 自主拓展）】**：为领域对象补充多字段健壮性校验（如 `stock` 缺省兜底为 0、`name` 缺省兜底为空字符串），并在接口契约表中指认 Method、Path 与状态码六要素。

## 8.5 知识点四：小组协作、Git 节奏与异常路径

**学习目标**

掌握角色分工、可运行检查点和异常测试记录方法，能够让小组协作过程可追踪，并用证据验证失败路径。

**语法/概念**

小组协作不是把页面平均分给几个人后各写各的。更稳的做法是围绕同一张需求卡分职责，每完成一小段就形成一个可以运行的检查点。

建议角色可以轮换，但职责必须明确：

| 角色 | 当前阶段责任 | 不应做什么 |
| --- | --- | --- |
| 页面负责人 | 路由页面与四态 | 绕过 API 层直接写地址 |
| 组件负责人 | 组件接口与表单 | 擅自把所有状态放 Store |
| 数据负责人 | Axios、契约、Mock | 在组件中吞掉错误 |
| 交付负责人 | README、验收、演示 | 最后一天才整理提交 |

每完成一个任务卡就形成一次可运行检查点：

1. 拉取/同步最新代码；
2. 完成一个任务卡；
3. 本地自测正常与异常路径；
4. 检查 diff；
5. 提交并写简短说明；
6. 更新任务板状态。

::: danger 合并前先保存工作
出现冲突时不要用覆盖整个文件的方式“快速解决”。先确认双方改动目标，保留可恢复分支或提交，再逐块合并并重新运行。
:::

异常测试不能只写“试过了”。一条有效记录至少要有场景、操作、预期和实际结果；如果未通过，再补证据、原因和修复。

| 测试场景 | 操作 | 预期 |
| --- | --- | --- |
| 空商品列表 | Mock 返回空数组 | 显示空状态和可行动入口 |
| 商品接口 500 | 切换错误响应 | 显示错误、保留筛选、可重试 |
| 慢请求 | 延迟 2 秒 | 显示加载，按钮防重复 |
| 无效详情 id | 访问不存在 id | 显示未找到并可返回 |
| 登录失效 | 受保护请求返回 401 | 清理会话摘要并引导登录 |
| 表单失败 | 订单接口拒绝 | 保留草稿，不清空购物车 |
| 深层刷新 | 刷新详情或后台页 | 服务端回退配置正确 |
| 构建检查 | `npm run build` | 无未解释错误，生成 `dist/` |

遇到“购物车角标不更新”时，可以按这条顺序取证：

1. 商品详情按钮是否真的触发了事件；
2. Store action 是否把商品加入 `items`；
3. 顶部组件是否读取同一个 Store；
4. 模板是否读取了响应式的 `count`；
5. Console 和 Vue Devtools 是否有警告。

这个顺序不是固定答案，它表达的是“从用户动作开始，顺着数据流一层一层查”，不要看见问题就同时改五个文件。

::: tip 思考问题
如果一个异常测试失败了，但小组只留下“修好了”三个字，后续维护者能不能判断原因并防止复发？还缺哪些证据？
:::

**课堂演示**

**步骤 1：给一张需求卡分配角色。**

以“商品接口失败后可重试”为例，页面负责人处理错误状态，数据负责人准备失败 Mock，交付负责人记录操作、预期和实际结果。

完成后应看到：同一目标下每个人的责任和交付物都很清楚。

**步骤 2：建立第一个可运行检查点。**

先验证正常商品列表，再切换 500 错误；两种状态都通过后才标记任务完成。

完成后应看到：一次检查点包含正常和异常两类证据，不是只要代码合并就算完成。

**步骤 3：填写一条异常测试记录。**

记录“停掉 Mock → 刷新商品列表 → 预期显示错误和重试 → 实际显示错误和重试”，并附一张页面截图或 Console/Network 证据。

完成后应看到：其他验收者可以按相同操作复现这条测试。

**步骤 4：演示排错顺序。**

面对购物车角标不更新，依次检查按钮事件、Store action、是否为同一个 Store、响应式读取和控制台，不先修改代码。

完成后应看到：排错记录是一条证据链，不是凭感觉反复尝试。

**当堂练习**

* **【必做任务（基础通关）】**：针对“商品接口 500 失败”或“空商品列表”任选 1 个异常场景，写出清晰的【操作步骤 → 预期看到的友好界面提示 → 实际观察到的现象】，确认页面没有白屏崩溃。
* **【选做挑战（🌟 自主拓展）】**：完成 2 个不同维度的异常测试记录（如 1 个接口失败重试 + 1 个慢网络防重提交锁），并在测试记录中附上控制台 Console 警告或 Network 面板状态码截图证据；如果未通过，分析下一排查步骤。

## 8.6 知识点五：验收证据与答辩

**学习目标**

掌握项目验收证据和答辩组织方法，能够准备 README、测试记录、演示顺序和问题复盘。

**语法/概念**

“我做完了”不是证据。综合项目至少要准备运行、功能、异常、工程和表达五类证据，老师才能判断项目是否真的可运行、可复现、可解释。

播放下面的验收流程。每个小组为五类证据指定文件、截图或现场操作。

**运行证据**

* 环境要求与安装命令；
* 开发启动与生产构建；
* `.env.example`；
* 无真实密钥。

**功能证据**

* 前台核心闭环；
* 管理端核心闭环；
* URL 可刷新；
* 跨页面状态一致。

**异常证据**

* 加载、空数据、失败、重试；
* 无效参数与 404；
* 表单错误；
* 会话失效。

**工程证据**

* 目录职责；
* API 与页面边界；
* 状态归属；
* 有意义的 Git 历史。

**表达证据**

* 5 分钟演示；
* 一份文字版模块职责说明；
* 一个真实问题复盘；
* 能回答“为什么这样设计”。

README 是复现入口，不是项目介绍口号。至少写清以下内容：

| README 小节 | 必须说明 |
| --- | --- |
| 项目说明 | 校园微商城服务什么用户、基础范围是什么 |
| 环境 | Node.js 与 npm 的版本要求 |
| 安装与启动 | 安装依赖、先启动本地 Mock、再启动前端 |
| 构建与预览 | 怎样执行生产构建和本地预览 |
| 演示路径 | 前台和管理端分别从哪个 URL 开始 |
| 环境变量 | 需要复制哪些公开配置，不填写真实秘密 |
| 已知边界 | 只使用本地 Mock，不包含真实支付和生产后端 |

只看 README 的交叉验收流程：

1. 把项目交给没有参与开发的验收者；
2. 对方不询问作者，只按 README 安装和启动；
3. 对方走一条前台路径、一条管理端路径和一次失败路径；
4. 对方执行构建并记录遇到的问题；
5. 作者根据记录修正文档，再由对方复验。

{{guided-demo:vue-project-acceptance-walkthrough}}

::: tip 思考问题
页面在作者电脑上能运行，但验收者按 README 无法启动，这个项目是否完成了“构建与交付”？应该补哪一类证据？
:::

**课堂演示**

**步骤 1：按五类证据建立验收清单。**

为每一类证据指定一种现场操作或文件，例如运行证据查看构建结果，异常证据现场停掉 Mock，工程证据查看目录和提交历史。

完成后应看到：每一项要求都能对应到具体证据，不依赖口头承诺。

**步骤 2：只看 README 复现项目。**

两个小组交换项目，由验收者只按 README 完成安装、启动、进入前台与管理端以及执行构建。

完成后应看到：README 缺少的步骤会直接暴露出来，并能留下可修正的问题记录。

**步骤 3：按五分钟顺序演示。**

### 演示与答辩结构

5 分钟演示建议：

1. **30 秒**：项目目标与用户；
2. **2 分钟**：前台和管理端核心路径；
3. **1 分钟**：主动演示一个失败状态；
4. **1 分钟**：解释组件、路由、API 与 Pinia 边界；
5. **30 秒**：展示 Git、README 与问题复盘。

完成后应看到：演示先展示结果，再用必要的工程证据解释结果，不会在五分钟内逐个打开代码文件。

**步骤 4：用答辩问题检查是否真正理解。**

答辩抽问示例：

* 购物车为什么进 Pinia，编辑弹窗为什么不进？
* 商品详情刷新后如何恢复？
* 接口失败为什么不能直接当成空数组？
* 删除事件为什么传 id 而不是下标？
* `VITE_` 环境变量为什么不能存 secret？
* 为什么第一章不直接创建微商城？
* 什么时候应该使用 Store，什么时候应该让状态留在页面？
* 前端路由守卫能不能代替后端权限？
* 如果刷新深层路由 404，应从浏览器、Vite 还是服务器回退配置开始查？

每个回答都要指向一条项目证据。完成后应明确：答辩重点是“能运行、能修改、能解释”，不是背诵 API 名称。

**当堂练习**

* **【必做任务（基础通关）】**：从答辩抽问中任选 1 题（如“购物车为什么进 Pinia，编辑弹窗为什么不进？”或“删除事件为什么传 id 而不是下标？”），结合项目实际代码用 2~3 句话说明理由，指出对应的技术文件。
* **【选做挑战（🌟 自主拓展）】**：设计一份 1 分钟“主动演示失败状态与优雅恢复”的答辩脚本提纲（涵盖前置准备、触发操作、故障现象展示、重试恢复动作与排错截图证据链），并回答 2 道答辩抽问。

{{reflection-checkpoint:vue-commerce-project-delivery-checkpoint}}

## 8.7 本章小测

{{assessment:vue-commerce-project-delivery-check}}

## 8.8 最终提交清单

| 提交物 | 必须包含 |
| --- | --- |
| 项目仓库 | 源码、lock 文件、合理提交历史 |
| 运行文档 | 环境、安装、启动、构建、变量、已知问题 |
| 测试记录 | 正常路径与至少 4 个异常场景 |
| 演示材料 | 核心流程截图或短录屏 |
| 问题复盘 | 现象、证据、原因、修复、预防 |
| 个人说明 | 本人负责内容与关键提交 |

### 最终能力证据表

| 能力 | 证据 |
| --- | --- |
| Vue 响应式 | 输入、勾选或数量变化后页面自动更新 |
| 组件通信 | Props 下发、Emits 上报，子组件不直接改父数据 |
| 路由 | 地址栏能表达页面，受保护地址有守卫 |
| UI | 表格、表单、校验、空状态和窄屏可操作 |
| Axios | 页面能区分加载、成功、空数据和失败 |
| Pinia | 购物车跨页面共享，刷新后按设计恢复 |
| 交付 | README 能让新目录完成安装、启动、构建 |

### 交付前检查

* 工作区只包含准备提交的源码、配置、Mock 种子和文档；
* 不提交 `node_modules/`、`dist/`、`.env` 或账号信息；
* 文本差异中没有冲突标记、临时调试内容和无关格式改动；
* `npm run build` 成功；
* `npm run preview` 能打开生产构建；
* 验收者只看 README 可以完成复现。

## 8.9 课后任务：校园微商城综合项目

### 任务目标

这是课程综合项目，需要综合前七章全部知识独立完成。本章重点学习分析与验收方法。

使用 `resources/ch08/after-class-starter/` 独立建立最终项目，可以沿用课堂练习的思路和代码片段，但不能把完整参考项目直接作为个人提交。

完成一个只使用本地 Mock 的校园微商城，包括面向普通用户的前台和面向管理人员的管理端。项目需要能够在新目录复现、演示正常业务路径，并对常见失败给出可操作反馈。

### 基础通关要求（全员必做）

1. **前台核心业务主线**：完成商品列表（支持基础关键词或分类筛选）、动态路由商品详情、加入购物车（Pinia 跨组件共享状态）、订单确认表单（基础非空校验）与模拟结果反馈页；
2. **管理端核心业务主线**：完成模拟登录入口、后台嵌套布局（AdminLayout）、Element Plus 商品表格展示、空状态显示与删除二次确认反馈、新增商品弹窗及基础校验；
3. **架构分层与契约清晰**：使用 Vue Router 管理页面出入口与登录守卫；使用独立 Axios API 模块访问本地 Mock，严禁在页面组件中随意拼写接口地址；
4. **规范工程交付与构建**：项目包含规范的 README 说明（明确运行环境、双终端启动顺序、演示路径与已知边界），并在终端执行 `npm run build` 成功输出 `dist/` 目录，无打包错误。

### 进阶拓展任务（自主选做 · 🌟 自主拓展）

1. **全链路异常容错与健壮性防护**：
   * 页面完整处理加载中骨架/提交防重锁、有数据、空数据引导、接口 500 可重试机制；
   * 包含无效商品 ID 友好提示与未知路由 404 兜底页面；
   * 购物车本地存储实现带有版本标识的安全持久化（`localStorage` + `try...catch` 损坏数据自愈）。
2. **领域数据归一化与类型防御**：
   * 在前端领域层编写 `normalizeProduct` 转换函数，防御后端 Mock 返回的脏数据（如字符串价格转数值、缺失库存兜底为 0）。
3. **工程排错证据链与 5 分钟答辩演练**：
   * 整理 2~4 条带 Network/Console 截图证据的异常测试排错记录；
   * 准备 5 分钟现场演示答辩脚本提纲（包含正常业务路径、主动演示一个失败状态、架构分工说明与故障修复复盘）。

### 必须使用的知识

* Vue Router：动态路由、嵌套路由、404 和登录守卫；
* Axios API 模块与本地 Mock：页面不直接拼完整接口地址；
* Pinia 购物车：跨页面共享商品、数量和金额；
* 页面四态：加载、成功、空数据和失败，并提供重试或返回入口；
* Element Plus 表单校验、删除确认和操作结果反馈；
* README、生产构建和可复现交付。

### 完成效果

前台可以从商品列表进入详情、加入购物车并完成本地订单确认；管理端登录后可以维护商品；关闭 Mock 时页面出现错误和重试入口；未知地址进入 404；按 README 在新目录可以完成安装、启动和构建。

全员需完成基础通关要求，保证前后台双主线闭环与工程构建完整可用；学有余力者可自主完成进阶拓展任务并在实践中深入探索。

### 验收步骤

按下面六步依次验收：

| 步骤 | 验收操作 | 达标指引 |
| --- | --- | --- |
| 1 | 从商品列表进入详情、加入购物车、确认订单 | 基础通关：列表、详情、购物车和金额一致 |
| 2 | 未登录进入管理端，再完成新增、编辑和删除 | 基础通关：守卫、表格、表单、确认和反馈可用 |
| 3 | 说明 Router、API、Store 和组件分别负责什么，并执行构建 | 基础通关：核心技术边界清楚，README 可复现，build 成功 |
| 4 | 验证加载、空数据、接口失败、重试、无效 id 和持久化 | 进阶拓展（🌟 自主拓展）：错误不白屏、不被当成空数据 |
| 5 | 只按 README 在新目录安装、启动并记录异常测试 | 进阶拓展（🌟 自主拓展）：仓库与排错记录可独立复现 |
| 6 | 完成五分钟演示、失败路径、修复证据和答辩 | 进阶拓展（🌟 自主拓展）：演示过程和技术选型说明清晰 |

### 提交内容

* 项目源码、Mock 数据和 README，不包含 `node_modules/`、`dist/`、`.env` 或账号信息；
* 前台主路径、管理端主路径、失败重试三组效果图；
* 一张构建成功截图；
* 个人负责内容、关键提交和一个已知限制说明。

完成进阶拓展任务时，再补充异常测试记录、完整五分钟演示提纲和故障修复排错证据。

::: warning 安全边界
不得提交真实账号、密钥、支付信息或生产接口地址。前端模拟登录和本地 Mock 仅用于课程练习，不能当成真实支付与权限系统。
:::

## 本章小结

* 综合项目先用最小范围和用户旅程固定业务闭环，再安排开发。
* 路由、页面、组件、API 和 Store 要有清楚边界，需求卡要能直接验收。
* Mock 字段变化应在 API 或领域边界处理，不把补丁散落到每个页面。
* 协作过程要留下可运行检查点，异常路径要留下可复现记录。
* 最终成果由可运行项目、可复现 README、测试证据和答辩表达共同组成。
