已完成菜单消费“固定分类/自定义分类”客户端功能实现。基础设置默认使用固定分类;自定义分类模式复用 POST /p/api/getMeal,提交 group_mode=custom_category_v1。固定和自定义模式分别使用独立 Retrofit 方法及响应 DTO,并转换为统一 MenuCatalog 供菜单页面展示。
当前状态:代码、资源、单元测试和 Debug APK 构建均已完成;Debug APK 已安装到当前连接设备,并完成固定/自定义分类与营养开/关四种组合、设置返回即时生效及隐藏筛选清理验证。已在一个餐段观察到普通业务自定义分类;多餐段完整覆盖、真实支付和客屏仍待专项验收。
| 设计项 | 落地方式 |
|---|---|
| 后端接口 | 固定和自定义模式复用 /p/api/getMeal |
| 客户端接口 | getDishMenu 与 getCustomDishMenu 两个 Retrofit 方法 |
| 响应模型 | GetDishMenuResponse 与 GetCustomDishMenuResponse 分离 |
| 页面模型 | 两套 Mapper 统一生成 MenuCatalog |
| 默认设置 | 配置缺失或非法时使用 fixed_category |
| 自定义分类 | 按服务端顺序显示启用分类,支持横向滚动 |
| 分类名称展示 | 自定义分类标签最多显示前 6 个 Unicode 字符,超长追加 ...;内部保留完整名称 |
| “全部”规则 | code=all 直接聚合接口返回的全部菜品 |
| 普通/其他规则 | 按 custom_category_id == category.id 过滤 |
| 协议异常 | schema_version 不匹配时临时请求固定分类,不修改已保存模式 |
| 营养展示兼容 | 分类模式和营养展示独立生效;设置返回时即时刷新,关闭时清除隐藏筛选 |
| 模块 | 文件 | 职责 |
|---|---|---|
| 设置模型 | model/MenuCategoryMode.java |
管理固定/自定义协议值及非法值回退 |
| 基础设置 | fragment/FragmentBasic.java、fragment_basic_layout.xml |
增加菜单消费模式双选项并持久化 |
| 接口声明 | network/APIService.java、network/RetrofitRequest.java |
增加自定义分类客户端请求方法 |
| 新响应 DTO | network/response/GetCustomDishMenuResponse.java |
承载 schema_version/categories/dishes |
| 菜品字段 | bean/DishBean.java、DishBeanJsonDeserializer.java |
解析三个自定义分类字段 |
| 统一页面模型 | model/MenuCategory.java、model/MenuCatalog.java |
隔离页面与网络协议结构 |
| 数据映射 | FixedMenuCatalogMapper.java、CustomMenuCatalogMapper.java |
生成分类列表及分类菜品映射 |
| 菜单页面 | activity/MainActivity.java |
按设置请求、动态展示、过滤、降级和记录日志 |
| 营养状态策略 | model/MenuNutritionDisplayPolicy.java |
决定关闭营养展示时清除当前营养筛选 |
| 动态分类 UI | activity_main.xml、item_home_custom_category_tab.xml |
固定栏与横向滚动动态分类栏切换 |
| 分类名称格式化 | MenuCategoryNameFormatter.java |
统一执行 6 字边界和超长省略,不改写分类模型原始名称 |
| 资源 | strings.xml、arrays.xml、dimens.xml |
集中维护文案、选项和尺寸 |
group_mode,保持旧协议和七个固定分类。group_mode=custom_category_v1。status=1 且名称有效的分类,并过滤重复 ID。...。执行命令:
JAVA_HOME=$(/usr/libexec/java_home -v 1.8) bash gradlew --no-daemon :app:testDebugUnitTest :app:assembleDebug
结果:BUILD SUCCESSFUL。
app/build/outputs/apk/debug/app-debug.apk。xmllint --noout。git diff --check 通过。lintDebug 已执行,项目因 18 个存量错误返回失败,首批错误位于未修改的 OrderDao.java。报告中本次修改文件没有 Error;相关文件仍存在项目原有的布局、硬编码和可访问性 Warning。
Lint 报告:app/build/reports/lint-results-debug.html。
验证设备:rk3568_r;应用版本:2.11.1、versionCode=36。
| 场景 | 验证结果 |
|---|---|
| 自定义分类 + 营养关闭 | 营养区域隐藏;分类标签按当前餐段接口响应展示 |
| 自定义分类 + 营养开启 | 营养区域即时显示,五类营养值可从实际菜品数据读取;分类标签仍按接口响应展示 |
| 固定分类 + 营养关闭 | 显示七个固定分类,营养区域隐藏;本次加载 31 个菜品 |
| 固定分类 + 营养开启 | 七个固定分类和营养区域同时正常显示 |
| 关闭隐藏筛选 | 先选择“蛋白质”,列表由 23 个过滤为 22 个;关闭营养展示后恢复为 23 个,当前营养素变为“未选择” |
| 购物车保持 | 设置返回并清除隐藏筛选后,测试购物车的 1 个菜品和金额保持不变 |
| 同时修改分类和营养设置 | 从“固定分类 + 营养开启”改为“自定义分类 + 营养关闭”后,只观察到一次 custom_category_v1 菜单请求 |
| 稳定性 | 验证过程中未出现应用崩溃或 FATAL EXCEPTION |
上述组合验证结束时,设备曾恢复为“自定义分类 + 营养关闭”,并清理了验证加入的临时购物车菜品。
真机组合验证完成后,代码继续进行了“营养展示默认值提取为具名常量”和“自定义分类标签超长省略”调整。最新代码已通过 73 项单元测试和 Debug 构建,最终 APK 已覆盖安装到当前设备并完成菜单页面启动冒烟验证,未出现崩溃。当前设备保存的是固定分类模式,接口也没有可用于截图的超长自定义分类测试数据,因此 6 字省略的真机视觉证据仍需在准备长名称分类数据后补充;边界规则已由 5 项单元测试覆盖。
现象:自定义分类模式下曾只显示“全部”和“其他”,此前可见的普通自定义分类标签消失。
排查证据:
| 时间 | 请求参数 | 原始响应分类 | 菜品数量 | 客户端映射分类 |
|---|---|---|---|---|
| 14:20 | group_mode=custom_category_v1 |
全部、其他 | 23 | 2 |
| 14:38 | group_mode=custom_category_v1 |
全部、养生粥、蛋、其他 | 41 | 4 |
两次请求使用同一设备编号和同一客户端协议参数,客户端映射数量均与原始响应一致。最终确认根因是餐段切换导致服务端返回的菜谱范围和分类关联发生变化,不是营养展示适配或客户端渲染逻辑删除了分类。本次排查未修改业务代码。
后续同类问题按以下顺序优先排查:
group_mode 请求的原始 categories 和 dishes。group_mode。group_mode=custom_category_v1。按用户要求,本次未执行任务关联、git add、提交、推送、分支切换或合并。
| 版本 | 日期 | 变更内容 |
|---|---|---|
v1.0 |
2026-09-07 | 完成固定分类与自定义分类客户端实现及首轮自动化验证 |
v1.1 |
2026-09-07 | 补齐营养展示设置返回即时生效和隐藏筛选清理;增加营养字段测试并完成当前设备组合验证 |
v1.2 |
2026-09-07 | 记录餐段切换引起菜谱和分类变化的排查结论,并将餐段与原始接口响应设为分类缺失问题的优先排查项 |
v1.3 |
2026-09-07 | 增加自定义分类名称最多显示 6 个字符、超长追加 ... 的页面规则和自动化测试 |