| 字段 | 内容 |
|---|---|
| Use Case ID | UC-MENU-001 |
| Use Case 名称 | 管理员配置菜单消费分类模式 |
| 云效任务编号 | VWCG-1327 |
| 所属项目 | CusumptionMachine |
| 所属模块 | 基础设置、菜单消费 |
| 优先级 | P0 |
| 版本 | v1.6 |
| 状态 | Ready |
| DoR | READY:云效任务编号已确认;关联任务、代码提交等流程不在本需求文档范围内 |
| 需求日期 | 2026-09-07 |
| 事实来源 | 用户需求、当前 Android 代码、POST /p/api/getMeal 实际接口回读 |
当前菜单消费页面使用客户端固定分类展示菜品,分类固定为“全部、主食、素菜、荤菜、蛋奶坚果、水果、汤饮”。服务端现已在原有 POST /p/api/getMeal 接口上增加 custom_category_v1 响应模式,可以返回餐厅配置的自定义分类和菜品所属分类。
本需求目标是在基础设置中增加“菜单消费模式”,让管理员可以在固定分类和自定义分类之间切换。菜单消费页面根据设置选择对应的请求和响应契约,同时保持现有购物车、营养筛选、排序和支付流程不变。
POST /p/api/getMeal,增加 group_mode=custom_category_v1。...。custom_category_v2。| 角色或系统 | 目标或职责 | 权限或数据范围 | 交互入口 |
|---|---|---|---|
| 设备管理员 | 选择菜单消费分类模式 | 当前消费机本地设置 | 基础设置页面 |
| 消费用户 | 按分类浏览和选择菜品 | 当前设备对应餐厅的菜单 | 菜单消费页面 |
| Android 客户端 | 保存模式、请求菜单、解析协议、展示分类和菜品 | 当前设备编号对应的数据 | SharedPreferences、HTTP |
| 菜单服务 | 根据 group_mode 返回固定或自定义分类菜单 |
当前设备所属餐厅 | POST /p/api/getMeal |
| ID | 条件 | 不满足时处理 | 验证方式 |
|---|---|---|---|
PRE-01 |
设备已完成基础配置并取得设备编号 | 沿用现有基础配置校验,不进入菜单请求 | 读取本地配置 |
PRE-02 |
接口地址已配置 | 沿用现有基础配置提示 | 读取本地配置 |
PRE-03 |
菜单消费入口对当前设备可用 | 沿用当前入口显示规则 | 页面检查 |
新增设置项:
菜单消费模式 [固定分类] [自定义分类]
交互要求:
建议持久化值:
| 显示文本 | 持久化值 |
|---|---|
| 固定分类 | fixed_category |
| 自定义分类 | custom_category_v1 |
固定分类模式:
自定义分类模式:
categories。...。code=all 的分类。code=all,选中第一个启用分类。固定分类和自定义分类复用同一个后端接口:
POST /p/api/getMeal
本需求不新增后端 URL。
category=false
keyword=
code=<当前设备编号>
固定分类请求不提交 group_mode。
category=false
keyword=
code=<当前设备编号>
group_mode=custom_category_v1
尽管后端路径相同,固定分类和自定义分类属于两套不同的数据契约。Android 客户端应声明两个 Retrofit 方法:
| 客户端方法 | 后端路径 | 响应类型 | 用途 |
|---|---|---|---|
getDishMenu |
/p/api/getMeal |
BaseBean<GetDishMenuResponse> |
固定分类 |
getCustomDishMenu |
/p/api/getMeal |
BaseBean<GetCustomDishMenuResponse> |
自定义分类 |
两个方法是同一后端接口的两种客户端映射,不代表新增服务端接口。
固定分类继续使用现有 GetDishMenuResponse,只承载旧结构:
{
"code": 0,
"message": "获取成功",
"data": {
"1": [],
"2": [],
"3": [],
"4": [],
"5": [],
"6": []
}
}
新增 GetCustomDishMenuResponse,只承载 custom_category_v1 结构:
{
"code": 0,
"message": "获取成功",
"data": {
"schema_version": "custom_category_v1",
"categories": [
{
"id": 0,
"code": "all",
"name": "全部",
"status": 1,
"is_system": 1
},
{
"id": 12,
"code": null,
"name": "高蛋白套餐",
"status": 1,
"is_system": 0
},
{
"id": 1,
"code": "other",
"name": "其他",
"status": 1,
"is_system": 1
}
],
"dishes": [
{
"uuid": "DISH-UUID-001",
"name": "宫保鸡丁",
"custom_category_id": 12,
"custom_category_name": "高蛋白套餐",
"custom_category_status": 1,
"price": 18,
"unit": "份",
"energy_100g": 121
}
]
}
}
GetDishMenuResponse 只描述固定分类旧协议。GetCustomDishMenuResponse 只描述自定义分类新协议。1 至 6 字段和新协议的 schema_version/categories/dishes 字段。DishBean 由两种响应共用,并增加自定义分类字段。DishBeanJsonDeserializer 必须显式解析 custom_category_id、custom_category_name 和 custom_category_status。两个网络响应分别转换为统一的页面菜单模型 MenuCatalog:
GetDishMenuResponse
→ FixedMenuCatalogMapper
→ MenuCatalog
GetCustomDishMenuResponse
→ CustomMenuCatalogMapper
→ MenuCatalog
MainActivity 只消费 MenuCatalog,不直接依赖两套网络字段结构。MenuCatalog 至少包含:
| 规则 ID | 规则名称 | 可执行规则 | 优先级 |
|---|---|---|---|
BR-001 |
默认模式 | 本地没有有效设置时必须使用 fixed_category |
P0 |
BR-002 |
固定分类请求 | 固定分类请求禁止提交 group_mode |
P0 |
BR-003 |
自定义分类请求 | 自定义分类请求必须提交 group_mode=custom_category_v1 |
P0 |
BR-004 |
响应类型隔离 | 固定与自定义分类必须使用不同响应 DTO | P0 |
BR-005 |
全部分类 | code=all 必须展示 dishes 全量数据,不按 id=0 过滤 |
P0 |
BR-006 |
普通分类 | 普通分类和 code=other 必须按 dish.custom_category_id == category.id 过滤 |
P0 |
BR-007 |
分类顺序 | 启用分类必须保持服务端返回顺序 | P0 |
BR-008 |
分类状态 | 页面只显示 status=1 的分类 |
P0 |
BR-009 |
异常菜品 | 分类为空或无法匹配的菜品必须保留在“全部”,禁止错误归类 | P0 |
BR-010 |
模式稳定性 | 请求失败或协议异常不得修改本地保存的菜单模式 | P0 |
BR-011 |
购物车稳定性 | 分类切换和刷新失败不得清空购物车 | P0 |
BR-012 |
协议版本 | 自定义分类响应必须校验 schema_version=custom_category_v1 |
P0 |
BR-013 |
分类名称展示 | 自定义分类名称超过 6 个 Unicode 字符时,标签必须显示前 6 个字符并追加 ...;完整名称不得被改写 |
P0 |
| 步骤 | 角色 | 动作或系统响应 | 页面/API | 数据或状态变化 | 验收 |
|---|---|---|---|---|---|
M1 |
设备管理员 | 进入基础设置 | 基础设置 | 读取本地菜单模式 | AC-001 |
M2 |
设备管理员 | 选择固定分类或自定义分类 | 菜单消费模式设置项 | 保存字符串模式值 | AC-002 |
M3 |
消费用户 | 进入菜单消费页面 | 菜单消费 | 页面读取已保存模式 | AC-003 |
M4 |
Android 客户端 | 根据模式调用对应 Retrofit 方法 | POST /p/api/getMeal |
发出固定或自定义请求 | AC-004、AC-005 |
M5 |
菜单服务 | 返回对应的数据契约 | 接口响应 | 得到固定或自定义响应 DTO | AC-006 |
M6 |
Android 客户端 | 使用对应 Mapper 转换响应 | Mapper | 生成统一 MenuCatalog |
AC-007 |
M7 |
Android 客户端 | 显示分类并默认选中“全部” | 菜单分类栏 | 更新当前分类 | AC-008 |
M8 |
消费用户 | 点击一个分类 | 菜单分类栏 | 按分类过滤菜品 | AC-009 |
M9 |
Android 客户端 | 继续执行营养过滤、排序和列表刷新 | 菜品列表 | 更新适配器数据 | AC-010 |
| 分支 | 分支点或条件 | 系统行为 | 结果 | 验收 |
|---|---|---|---|---|
A1@M4 |
当前模式为固定分类 | 调用 getDishMenu,不提交 group_mode |
展示现有固定分类 | AC-004 |
A2@M4 |
当前模式为自定义分类 | 调用 getCustomDishMenu,提交 custom_category_v1 |
解析动态分类 | AC-005 |
A3@M7 |
自定义响应存在 code=all |
默认选中该分类并展示全部菜品 | 全量菜品可见 | AC-008 |
A4@M7 |
自定义响应没有 code=all 但存在启用分类 |
默认选中第一个启用分类 | 对应分类菜品可见 | AC-011 |
A5@M8 |
用户选择 code=other |
按该分类 ID 过滤 | 展示“其他”菜品 | AC-012 |
| 异常或恢复 | 发生条件 | 用户反馈 | 数据处理 | 恢复方式 | 验收 |
|---|---|---|---|---|---|
E1@M4 |
网络失败或超时 | 显示现有网络错误提示 | 保留模式、购物车和已有列表 | 下拉刷新或点击重试 | AC-020 |
E2@M5 |
自定义响应的 schema_version 缺失或不匹配 |
提示“自定义分类数据格式异常” | 禁止按新协议继续解析 | 重新调用固定分类方法临时降级 | AC-021 |
E3@M6 |
categories 为空但 dishes 非空 |
页面仍可浏览菜品 | 临时生成本次展示用“全部”分类 | 下次刷新重新请求 | AC-022 |
E4@M6 |
菜品分类为空或找不到对应分类 | 不单独打断消费流程 | 菜品仅保留在“全部”并记录日志 | 后台修正分类后刷新 | AC-023 |
E5@M6 |
分类 ID 重复或分类名称为空 | 不展示无效重复项 | 保留首个有效分类并记录日志 | 后台修正后刷新 | AC-024 |
E6@M5 |
业务 code 非 0 或 data 为空 |
显示接口错误或空状态 | 不修改设置和购物车 | 点击重试 | AC-025 |
临时降级只影响本次页面数据,不允许把用户保存的“自定义分类”自动改回“固定分类”。
getMeal。DishBean。客户端应记录以下信息,不记录支付凭证或人员敏感数据:
schema_version。当自定义分类标签减少、只剩“全部/其他”或菜品数量发生明显变化时,必须先排查餐段和接口数据,再排查客户端代码:
POST /p/api/getMeal 请求是否携带 group_mode=custom_category_v1。categories、dishes、custom_category_id 和 custom_category_name,并与另一个餐段的响应进行对比。all 和 other,且菜品均归入 other,应先检查当前餐段的菜谱范围及自定义分类关联配置,不应直接判定为营养展示适配或客户端分类渲染回归。CustomMenuCatalogMapper、动态分类栏渲染和页面刷新逻辑。“营养展示”只控制营养筛选、排序和热量区域,不负责生成、删除或重排接口返回的自定义分类。排查分类缺失时,应先固定餐段和接口响应,避免把餐段数据变化误判为营养功能回归。
POST /p/api/getMeal。| AC | 关联对象 | Given | When | Then | 证据 |
|---|---|---|---|---|---|
AC-001 |
M1/BR-001 |
本地没有菜单模式设置 | 打开基础设置 | “固定分类”处于选中状态 | 页面截图、配置回读 |
AC-002 |
M2 |
基础设置已打开 | 切换菜单模式并重新进入页面 | 页面恢复最后一次有效选择 | 页面截图、配置回读 |
AC-003 |
M3 |
已保存一个合法模式 | 进入菜单消费 | 页面使用该模式发起菜单请求 | 请求日志 |
AC-004 |
A1/BR-002 |
当前为固定分类 | 请求菜单 | 请求不包含 group_mode,页面保持现有七个分类 |
抓包、页面截图 |
AC-005 |
A2/BR-003 |
当前为自定义分类 | 请求菜单 | 请求包含 group_mode=custom_category_v1 |
抓包、接口日志 |
AC-006 |
M5/BR-004 |
服务端分别返回旧、新结构 | 客户端解析 | 两种响应分别进入对应 DTO,不发生混合字段依赖 | 单元测试 |
AC-007 |
M6 |
任一种响应解析成功 | Mapper 转换 | 输出统一 MenuCatalog |
单元测试 |
AC-008 |
A3/BR-005 |
自定义响应包含 code=all |
页面首次展示或刷新成功 | 默认选中“全部”并展示全部菜品 | 页面截图、列表计数 |
AC-009 |
M8/BR-006 |
存在普通自定义分类 | 点击该分类 | 只展示匹配 custom_category_id 的菜品 |
页面截图、列表断言 |
AC-010 |
M9 |
已选择分类 | 使用营养筛选或排序 | 结果基于当前分类菜品,购物车不变 | 页面测试 |
AC-011 |
A4 |
响应没有 all 但存在启用分类 |
页面展示 | 默认选中第一个启用分类 | 单元测试、页面测试 |
AC-012 |
A5 |
存在 code=other |
点击“其他” | 展示分类 ID 匹配的菜品 | 单元测试、页面测试 |
AC-013 |
M7/BR-013 |
自定义分类名称分别为 6 个和 7 个字符 | 页面展示分类标签 | 6 个字符时原样显示;7 个字符时显示前 6 个字符加 ...,点击后仍按原分类 ID 筛选 |
单元测试、页面截图 |
AC-020 |
E1/BR-010/BR-011 |
页面已有菜品和购物车 | 刷新发生网络失败 | 已有列表、购物车和设置均不被清空 | 断网测试、截图 |
AC-021 |
E2/BR-012 |
自定义响应版本不匹配 | 客户端处理响应 | 提示异常并临时请求固定分类,不修改保存模式 | Mock 测试、日志 |
AC-022 |
E3 |
分类为空且菜品非空 | 页面处理响应 | 生成临时“全部”并展示所有菜品 | 单元测试 |
AC-023 |
E4/BR-009 |
菜品分类无法匹配 | 页面处理响应 | 菜品仍在“全部”中且日志可定位 | 单元测试、日志 |
AC-024 |
E5 |
分类 ID 重复或名称为空 | 页面处理响应 | 无重复或空名称分类项,页面不崩溃 | 单元测试 |
AC-025 |
E6 |
接口失败或无数据 | 页面处理响应 | 显示错误或空状态,可执行重试 | 页面测试 |
| Test ID | 层级 | 覆盖对象 | 预期结果 | 自动化 |
|---|---|---|---|---|
UT-MENU-001 |
单元测试 | 菜单模式默认值与合法性 | 空值和非法值返回固定分类 | 是 |
UT-MENU-002 |
单元测试 | 固定分类 Mapper | 旧响应转换为七个页面分类 | 是 |
UT-MENU-003 |
单元测试 | 自定义分类 Mapper | 分类顺序、状态和菜品关联正确 | 是 |
UT-MENU-004 |
单元测试 | all 分类 |
全量菜品不按 ID 过滤 | 是 |
UT-MENU-005 |
单元测试 | 异常分类 | 未匹配菜品保留在“全部” | 是 |
UT-MENU-006 |
单元测试 | DTO 解析 | 固定与自定义响应分别解析到对应 DTO | 是 |
UT-MENU-007 |
单元测试 | 自定义分类标签名称格式化 | 6 个字符原样显示;超长保留前 6 个字符并追加 ...;Unicode 字符不被截断 |
是 |
API-MENU-001 |
契约测试 | 固定分类请求 | 不提交 group_mode 并返回旧结构 |
是或 MockWebServer |
API-MENU-002 |
契约测试 | 自定义分类请求 | 提交协议值并返回新结构 | 是或 MockWebServer |
UI-MENU-001 |
页面测试 | 基础设置 | 默认值、切换和恢复正确 | 是或人工 |
UI-MENU-002 |
页面测试 | 动态分类栏 | 超过 6 个字符的名称按规则省略,多分类横向滚动正常 | 是或人工 |
E2E-MENU-001 |
端到端 | 固定分类消费 | 选菜、购物车和支付链路正常 | 人工真机 |
E2E-MENU-002 |
端到端 | 自定义分类消费 | 分类切换、选菜、购物车和支付链路正常 | 人工真机 |
E2E-MENU-003 |
端到端 | 网络失败恢复 | 已有数据保留且重试成功 | 人工真机 |
2026-09-07 已使用当前连接设备的实际接口配置验证自定义分类请求。验证时对设备编号进行脱敏记录。排查过程中确认,同一设备在不同餐段会返回不同菜谱和自定义分类集合。
| 项目 | 餐段切换前样本(14:20) | 餐段切换后样本(14:38) |
|---|---|---|
| 请求地址 | https://zhct.yyangpt.cn/p/api/getMeal |
https://zhct.yyangpt.cn/p/api/getMeal |
| 设备编号 | sfj_sp_*** |
sfj_sp_*** |
| 请求参数 | group_mode=custom_category_v1 |
group_mode=custom_category_v1 |
| 业务结果 | code=0、message=获取成功 |
code=0、message=获取成功 |
| 协议版本 | custom_category_v1 |
custom_category_v1 |
| 分类 | “全部、其他” | “全部、养生粥、蛋、其他” |
| 分类数量 | 2 | 4 |
| 菜品数量 | 23 | 41 |
| 客户端映射数量 | 2 | 4 |
| 分类关联异常 | 0 | 0 |
该现象的根因是餐段切换后服务端返回的菜谱范围和分类关联发生变化,不是营养展示适配删除了自定义分类。客户端两次均按响应中的 categories 原顺序展示。后续验收和问题复现必须记录餐段,并分别验证目标餐段的后台分类配置。
| UC/步骤 | 页面 | API | 数据或状态 | 规则 | 验收 | 测试 | 实现位置 |
|---|---|---|---|---|---|---|---|
M1-M2 |
基础设置 | 不适用 | 本地菜单模式 | BR-001 |
AC-001、AC-002 |
UT-MENU-001、UI-MENU-001 |
FragmentBasic、Constants |
A1@M4 |
菜单消费 | getDishMenu |
固定响应 DTO | BR-002、BR-004 |
AC-004、AC-006 |
API-MENU-001、UT-MENU-002 |
APIService、RetrofitRequest |
A2@M4 |
菜单消费 | getCustomDishMenu |
自定义响应 DTO | BR-003、BR-004 |
AC-005、AC-006 |
API-MENU-002、UT-MENU-006 |
APIService、RetrofitRequest |
M6-M9 |
菜单消费 | 不适用 | MenuCatalog |
BR-005 至 BR-009、BR-013 |
AC-007 至 AC-013 |
UT-MENU-003 至 UT-MENU-005、UT-MENU-007 |
Mapper、MainActivity、MenuCategoryNameFormatter |
E1-E6 |
菜单消费 | 固定与自定义请求 | 错误、空、降级状态 | BR-010 至 BR-012 |
AC-020 至 AC-025 |
E2E-MENU-003、Mock 测试 |
MainActivity、Mapper |
| ID | 类型 | 内容 | 影响 | 应对措施 | 状态 |
|---|---|---|---|---|---|
RISK-001 |
测试数据 | 不同餐段的菜谱和自定义分类配置可能不同 | 某些餐段只显示“全部/其他”,容易误判为客户端回归 | 按餐段检查菜谱范围及分类关联,并分别准备验收数据 | Open |
RISK-002 |
兼容性 | 自定义模式可能访问未升级环境 | 自定义响应版本不匹配 | 显式校验版本并临时降级固定分类 | Accepted |
RISK-003 |
页面布局 | 分类数量和名称不可控 | 分类挤压或不可点击 | 使用横向滚动和最小触控宽度 | Accepted |
| ID | 待确认项 | 影响 | 负责人 | 状态 |
|---|---|---|---|---|
Q-001 |
补充云效任务编号 | 已确认任务编号为 VWCG-1327;关联任务操作不在本次范围 |
产品或需求负责人 | Closed |
Q-002 |
确认每个目标餐段都配置了需要验收的普通自定义分类 | 影响多餐段完整验收,不影响协议和代码设计 | 后台配置负责人 | Open |
“固定分类/自定义分类”解决的是菜品如何分组展示;“营养展示”解决的是菜单页面是否提供营养筛选、排序、总热量以及支付后的营养反馈。两者属于相互独立的功能维度,不能因为分类来源发生变化而改变原有营养能力。
本次补充主要解决以下问题:
| 需求项 | 性质 | 说明 |
|---|---|---|
| 基础设置增加“菜单消费模式” | 新增功能 | 原系统没有固定分类与自定义分类的切换能力 |
支持 custom_category_v1 请求和动态分类 |
新增功能 | 增加新的服务端响应模式和页面展示方式 |
| 自定义分类继续支持原营养筛选、排序和总热量 | 兼容性要求 | 营养能力已经存在,不属于重新开发营养功能 |
| 修改营养设置后返回菜单页面立即生效 | 现有功能缺失修复 | 当前 MainActivity.onResume() 未重新读取营养设置 |
| 关闭营养展示时清除已选营养条件 | 缺陷修复 | 防止出现不可见的隐式筛选 |
| 明确自定义响应中的完整营养字段 | 接口契约补充 | 保证自定义分类达到与固定分类相同的营养能力 |
| 支付成功弹窗兼容两种分类模式 | 兼容性要求 | 保持现有营养开关语义和支付流程不变 |
菜单分类模式和营养展示配置必须独立组合生效:
| 分类模式 | 营养展示 | 页面行为 |
|---|---|---|
| 固定分类 | 关闭 | 显示固定分类;隐藏营养区域;菜品不受营养条件过滤 |
| 固定分类 | 开启 | 显示固定分类和营养区域;支持现有营养筛选和排序 |
| 自定义分类 | 关闭 | 显示动态分类;隐藏营养区域;只按自定义分类过滤 |
| 自定义分类 | 开启 | 显示动态分类和营养区域;先按分类、再按营养条件处理 |
营养开关继续复用 Constants.SETTING_NUTRITION_SHOW_SWITCHER,默认值保持为关闭,不增加第二个营养设置项。
开启营养展示时:
关闭营养展示时:
mCurrentNutritionTabId 和营养选项选中状态。无论采用哪种分类模式,页面统一执行以下数据处理顺序:
接口菜品
→ 按当前分类过滤
→ 按当前营养类型过滤
→ 按营养值升序或降序
→ 更新菜品列表
管理员从菜单消费页面进入基础设置,修改配置后直接返回时:
自定义分类响应中的 dishes 应继续提供现有五类营养字段:
{
"energy_100g": 121,
"carbohydrate_100g": 12.5,
"protein_100g": 18,
"fat_100g": 6.2,
"dietary_fiber_100g": 2.1
}
字段规则:
null。energy_100g,客户端只能保证热量功能可用,其他四项营养筛选可能得到空列表。MainActivity 增加统一的营养状态刷新方法,例如 refreshNutritionDisplaySetting(),负责:
调用位置:
initViews():处理首次进入菜单页面的初始状态。onResume():处理从基础设置返回后的即时状态变化。推荐的 onResume() 处理顺序:
读取最新分类模式和营养设置
→ 营养关闭时清除隐藏筛选
→ 分类模式是否变化?
是:按新模式请求一次菜单
否:营养筛选是否被清除?
是:刷新本地菜品列表
否:不处理
现有 DishBean 和 DishBeanJsonDeserializer 已承载五种营养字段,自定义分类 Mapper 应继续传递同一个 DishBean,禁止复制菜品时丢失营养字段。固定和自定义响应继续通过各自 Mapper 转换为统一 MenuCatalog,页面不得增加两套营养处理分支。
| AC | 场景 | 预期结果 | 证据 |
|---|---|---|---|
AC-NUT-001 |
固定分类、营养关闭 | 营养区域隐藏,菜品不受营养条件过滤 | 页面截图、列表计数 |
AC-NUT-002 |
固定分类、营养开启 | 五类营养筛选和排序保持现有行为 | 页面测试 |
AC-NUT-003 |
自定义分类、营养关闭 | 页面只按自定义分类展示菜品 | 页面截图、列表计数 |
AC-NUT-004 |
自定义分类、营养开启 | 先按自定义分类、再按营养条件筛选和排序 | 页面测试 |
AC-NUT-005 |
营养展示由开改为关后返回 | 立即隐藏营养区域并清除原营养筛选 | 页面测试、日志 |
AC-NUT-006 |
营养展示由关改为开后返回 | 立即显示营养区域,默认不选营养项 | 页面测试 |
AC-NUT-007 |
分类模式和营养设置同时修改 | 两项最新配置同时生效,菜单只请求一次 | 请求日志、页面测试 |
AC-NUT-008 |
自定义菜品缺少营养字段 | 页面不崩溃,缺少字段按无数据处理 | 单元测试 |
AC-NUT-009 |
切换分类或营养条件 | 购物车内容保持不变 | 页面测试 |
AC-NUT-010 |
支付成功 | 根据营养开关显示营养版或普通版成功弹窗 | 真机测试 |
| 顺序 | 工作项 | 具体动作 | 完成标准 | 状态 |
|---|---|---|---|---|
| 1 | 需求方案归档 | 将营养兼容背景、需求性质、接口约束和验收标准同步到 Markdown 与 HTML 文档 | 两个版本内容一致 | 已完成 |
| 2 | 补齐页面即时兼容 | 在 MainActivity 抽取统一营养状态刷新方法,并接入 initViews()、onResume() |
设置返回后立即生效;关闭时不存在隐藏筛选 | 已完成 |
| 3 | 补充自动化测试 | 增加自定义响应营养字段解析、Mapper 不丢字段及分类名称 6 字省略等单元测试 | 新增测试和现有测试全部通过 | 已完成,73 项测试通过 |
| 4 | 编译验证 | 使用项目兼容 JDK 执行单元测试和 Debug 构建 | 单元测试通过,Debug APK 构建成功 | 已完成 |
| 5 | 当前设备真机验收 | 覆盖固定/自定义分类与营养开/关四种组合,以及设置返回即时生效 | AC-NUT-001 至 AC-NUT-010 有可复核结果 |
部分完成:四种组合、即时生效、隐藏筛选和购物车保持已验证;真实支付、客屏仍待验收 |
| 6 | 更新实施记录 | 记录实际改动文件、验证命令、结果和仍需后台配合的测试数据 | VWCG-1327 实施记录与代码实际行为一致 | 已完成 |
当前下一步是完成剩余真机验收:固定并记录目标餐段,逐餐段验证普通业务自定义分类、多分类和长名称;随后使用真实支付回归普通/营养支付成功弹窗、语音和客屏。本计划不包含云效关联任务、Git 提交、推送、合并或发布操作。
| 检查项 | 状态 | 说明 |
|---|---|---|
| 目标与范围 | READY | 已明确固定和自定义两种模式 |
| 角色与触发 | READY | 管理员设置、用户消费和刷新入口明确 |
| 页面行为 | READY | 设置项、固定分类和动态分类行为明确 |
| API 契约 | READY | 同一路径、两个客户端方法、两个响应 DTO 已确认 |
| 数据规则 | READY | all、普通分类、other 和异常菜品规则明确 |
| 异常与恢复 | READY | 网络、协议、空分类和关联异常均已覆盖 |
| 验收和测试 | READY | P0 规则已映射验收和测试 |
| 性能指标 | READY | 本需求限定请求次数;服务端 SLA 沿用现状且不作达标声明 |
| 安全 | READY | 不新增权限和敏感数据 |
| 云效任务编号 | READY | 已确认 VWCG-1327;无需处理关联任务或代码提交 |
| 多餐段自定义分类测试数据 | DEFERRED | 已确认部分餐段有普通自定义分类、部分餐段只有“全部/其他”;需逐餐段补齐完整验收 |
当前结论:DoR: READY,Android 客户端开发和核心组合验证已完成。Q-002 不阻塞当前实现,但必须在完整真机验收前关闭。
| 版本 | 日期 | 变更内容 | 原因 |
|---|---|---|---|
v1.0 |
2026-09-07 | 建立固定分类与自定义分类需求、接口和页面方案 | 初始需求分析 |
v1.1 |
2026-09-07 | 明确复用同一后端接口路径;Android 客户端使用两个 Retrofit 方法、两个响应 DTO,并统一映射为 MenuCatalog |
避免一个响应类混合两套差异较大的协议结构 |
v1.2 |
2026-09-07 | 回填云效任务编号 VWCG-1327,将开发准备状态调整为 READY,并明确不处理关联任务和代码提交流程 |
用户补充任务编号及流程边界 |
v1.3 |
2026-09-07 | 补充营养展示兼容背景、需求性质、设置返回即时生效、隐藏筛选清理、接口营养字段约束、验收标准和下一步实施计划 | 明确新增功能与现有功能缺失的边界,防止自定义分类引入营养能力回退 |
v1.4 |
2026-09-07 | 回填营养兼容实现、68 项单元测试、Debug 构建和当前设备四种组合验证状态,更新后续验收计划 | 保持需求计划与实际实施进度一致 |
v1.5 |
2026-09-07 | 增加餐段切换导致菜谱与自定义分类变化的优先排查流程,并回填同一设备两次实际接口对比 | 避免将服务端餐段数据变化误判为营养适配或客户端分类回归 |
v1.6 |
2026-09-07 | 增加自定义分类标签名称 6 字展示上限、超长省略规则、Unicode 边界和对应验收测试 | 避免长分类名称占用过多横向空间,并保持完整分类数据不受展示截断影响 |