VWCG-1327 菜单消费分类模式实施记录

1. 实施结论

已完成菜单消费“固定分类/自定义分类”客户端功能实现。基础设置默认使用固定分类;自定义分类模式复用 POST /p/api/getMeal,提交 group_mode=custom_category_v1。固定和自定义模式分别使用独立 Retrofit 方法及响应 DTO,并转换为统一 MenuCatalog 供菜单页面展示。

当前状态:代码、资源、单元测试和 Debug APK 构建均已完成;Debug APK 已安装到当前连接设备,并完成固定/自定义分类与营养开/关四种组合、设置返回即时生效及隐藏筛选清理验证。已在一个餐段观察到普通业务自定义分类;多餐段完整覆盖、真实支付和客屏仍待专项验收。

2. 核心设计

设计项 落地方式
后端接口 固定和自定义模式复用 /p/api/getMeal
客户端接口 getDishMenugetCustomDishMenu 两个 Retrofit 方法
响应模型 GetDishMenuResponseGetCustomDishMenuResponse 分离
页面模型 两套 Mapper 统一生成 MenuCatalog
默认设置 配置缺失或非法时使用 fixed_category
自定义分类 按服务端顺序显示启用分类,支持横向滚动
分类名称展示 自定义分类标签最多显示前 6 个 Unicode 字符,超长追加 ...;内部保留完整名称
“全部”规则 code=all 直接聚合接口返回的全部菜品
普通/其他规则 custom_category_id == category.id 过滤
协议异常 schema_version 不匹配时临时请求固定分类,不修改已保存模式
营养展示兼容 分类模式和营养展示独立生效;设置返回时即时刷新,关闭时清除隐藏筛选

3. 代码改动

模块 文件 职责
设置模型 model/MenuCategoryMode.java 管理固定/自定义协议值及非法值回退
基础设置 fragment/FragmentBasic.javafragment_basic_layout.xml 增加菜单消费模式双选项并持久化
接口声明 network/APIService.javanetwork/RetrofitRequest.java 增加自定义分类客户端请求方法
新响应 DTO network/response/GetCustomDishMenuResponse.java 承载 schema_version/categories/dishes
菜品字段 bean/DishBean.javaDishBeanJsonDeserializer.java 解析三个自定义分类字段
统一页面模型 model/MenuCategory.javamodel/MenuCatalog.java 隔离页面与网络协议结构
数据映射 FixedMenuCatalogMapper.javaCustomMenuCatalogMapper.java 生成分类列表及分类菜品映射
菜单页面 activity/MainActivity.java 按设置请求、动态展示、过滤、降级和记录日志
营养状态策略 model/MenuNutritionDisplayPolicy.java 决定关闭营养展示时清除当前营养筛选
动态分类 UI activity_main.xmlitem_home_custom_category_tab.xml 固定栏与横向滚动动态分类栏切换
分类名称格式化 MenuCategoryNameFormatter.java 统一执行 6 字边界和超长省略,不改写分类模型原始名称
资源 strings.xmlarrays.xmldimens.xml 集中维护文案、选项和尺寸

4. 行为说明

5. 自动化验证

5.1 单元测试与 APK 构建

执行命令:

JAVA_HOME=$(/usr/libexec/java_home -v 1.8) bash gradlew --no-daemon :app:testDebugUnitTest :app:assembleDebug

结果:BUILD SUCCESSFUL

5.2 资源与格式

5.3 Lint

lintDebug 已执行,项目因 18 个存量错误返回失败,首批错误位于未修改的 OrderDao.java。报告中本次修改文件没有 Error;相关文件仍存在项目原有的布局、硬编码和可访问性 Warning。

Lint 报告:app/build/reports/lint-results-debug.html

5.4 当前设备验证

验证设备:rk3568_r;应用版本:2.11.1versionCode=36

场景 验证结果
自定义分类 + 营养关闭 营养区域隐藏;分类标签按当前餐段接口响应展示
自定义分类 + 营养开启 营养区域即时显示,五类营养值可从实际菜品数据读取;分类标签仍按接口响应展示
固定分类 + 营养关闭 显示七个固定分类,营养区域隐藏;本次加载 31 个菜品
固定分类 + 营养开启 七个固定分类和营养区域同时正常显示
关闭隐藏筛选 先选择“蛋白质”,列表由 23 个过滤为 22 个;关闭营养展示后恢复为 23 个,当前营养素变为“未选择”
购物车保持 设置返回并清除隐藏筛选后,测试购物车的 1 个菜品和金额保持不变
同时修改分类和营养设置 从“固定分类 + 营养开启”改为“自定义分类 + 营养关闭”后,只观察到一次 custom_category_v1 菜单请求
稳定性 验证过程中未出现应用崩溃或 FATAL EXCEPTION

上述组合验证结束时,设备曾恢复为“自定义分类 + 营养关闭”,并清理了验证加入的临时购物车菜品。

真机组合验证完成后,代码继续进行了“营养展示默认值提取为具名常量”和“自定义分类标签超长省略”调整。最新代码已通过 73 项单元测试和 Debug 构建,最终 APK 已覆盖安装到当前设备并完成菜单页面启动冒烟验证,未出现崩溃。当前设备保存的是固定分类模式,接口也没有可用于截图的超长自定义分类测试数据,因此 6 字省略的真机视觉证据仍需在准备长名称分类数据后补充;边界规则已由 5 项单元测试覆盖。

5.5 自定义分类标签缺失问题排查

现象:自定义分类模式下曾只显示“全部”和“其他”,此前可见的普通自定义分类标签消失。

排查证据:

时间 请求参数 原始响应分类 菜品数量 客户端映射分类
14:20 group_mode=custom_category_v1 全部、其他 23 2
14:38 group_mode=custom_category_v1 全部、养生粥、蛋、其他 41 4

两次请求使用同一设备编号和同一客户端协议参数,客户端映射数量均与原始响应一致。最终确认根因是餐段切换导致服务端返回的菜谱范围和分类关联发生变化,不是营养展示适配或客户端渲染逻辑删除了分类。本次排查未修改业务代码。

后续同类问题按以下顺序优先排查:

  1. 先确认问题时刻对应的餐段及是否刚发生餐段切换。
  2. 再核对同一设备编号、同一 group_mode 请求的原始 categoriesdishes
  3. 如果原始响应只有“全部/其他”,优先检查该餐段的菜谱与自定义分类关联配置。
  4. 只有原始响应已包含普通自定义分类但页面未展示时,才进入客户端 DTO、Mapper、动态分类 UI 和刷新逻辑排查。

6. 待验收项

7. Git 边界

按用户要求,本次未执行任务关联、git add、提交、推送、分支切换或合并。

8. 变更记录

版本 日期 变更内容
v1.0 2026-09-07 完成固定分类与自定义分类客户端实现及首轮自动化验证
v1.1 2026-09-07 补齐营养展示设置返回即时生效和隐藏筛选清理;增加营养字段测试并完成当前设备组合验证
v1.2 2026-09-07 记录餐段切换引起菜谱和分类变化的排查结论,并将餐段与原始接口响应设为分类缺失问题的优先排查项
v1.3 2026-09-07 增加自定义分类名称最多显示 6 个字符、超长追加 ... 的页面规则和自动化测试