docs: 新增测试问题分析报告(食谱计算器/AI营养师/食物百科/健康知识)
针对测试反馈的四个问题进行代码级分析,包含根因定位、涉及文件和修复建议。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
301
docs/测试问题分析报告_2026-03-22.md
Normal file
301
docs/测试问题分析报告_2026-03-22.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# 测试问题分析报告
|
||||
|
||||
> **日期:** 2026-03-22
|
||||
> **分析人:** Claude AI
|
||||
> **项目:** 民生汇 - 慢性肾病营养管理小程序
|
||||
|
||||
---
|
||||
|
||||
## 一、食谱计算器 —— 用油量计算逻辑错误
|
||||
|
||||
### 问题描述
|
||||
|
||||
食谱计算器计算出的用油量偏多,不符合实际膳食指导标准。
|
||||
|
||||
### 问题定位
|
||||
|
||||
**文件:** `msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCalculatorServiceImpl.java`
|
||||
**位置:** `generateFoodPortions()` 方法,第 516 行
|
||||
|
||||
```java
|
||||
// 当前代码(有误)
|
||||
list.add(createFoodPortion(7, "油脂类10g", round(5.7 * energyRatio)));
|
||||
```
|
||||
|
||||
### 根因分析
|
||||
|
||||
油脂类的份数计算使用了系数 `5.7`,与第 510 行谷薯类的系数完全相同:
|
||||
|
||||
```java
|
||||
list.add(createFoodPortion(1, "谷薯50g", round(5.7 * energyRatio))); // 谷薯类
|
||||
list.add(createFoodPortion(7, "油脂类10g", round(5.7 * energyRatio))); // 油脂类(错误地使用了同一系数)
|
||||
```
|
||||
|
||||
其中 `energyRatio = energy / 2000.0`。以标准体重 60kg 患者为例:
|
||||
|
||||
- 每日能量目标 = 60 × 35 = 2100 kcal
|
||||
- energyRatio = 2100 / 2000 = 1.05
|
||||
- 油脂份数 = 5.7 × 1.05 ≈ **6.0 份**
|
||||
- 每份 10g,即每天需要 **60g 油**
|
||||
|
||||
根据《中国居民膳食指南》和《慢性肾脏病患者膳食指导(2017)》,CKD 患者每日食用油推荐量为 **25-30g**,当前计算结果严重偏高。
|
||||
|
||||
### 修复建议
|
||||
|
||||
将油脂类的计算系数从 `5.7` 调整为 `2.5`:
|
||||
|
||||
```java
|
||||
// 修复后
|
||||
list.add(createFoodPortion(7, "油脂类10g", round(2.5 * energyRatio)));
|
||||
```
|
||||
|
||||
修复后以同一患者为例:2.5 × 1.05 ≈ 2.6 份,即每日约 26g 油,符合膳食指南要求。
|
||||
|
||||
### 优先级:高
|
||||
|
||||
---
|
||||
|
||||
## 二、AI 营养师 —— 反应慢、内容凌乱、体验差
|
||||
|
||||
### 问题描述
|
||||
|
||||
AI 营养师功能反应比较慢,提供的内容比较凌乱,逻辑性差,整体体验感不好。
|
||||
|
||||
### 问题定位
|
||||
|
||||
**后端文件:** `msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolAiNutritionistServiceImpl.java`
|
||||
**前端文件:** `msh_single_uniapp/pages/tool/ai-nutritionist.vue`
|
||||
|
||||
### 根因分析
|
||||
|
||||
#### 1. AI 服务未真正接入(核心原因)
|
||||
|
||||
后端 `sendMessage()` 方法(第 89-97 行)使用的是 **Mock 模拟回复**,并未真正接入 AI 服务:
|
||||
|
||||
```java
|
||||
// Mock AI response
|
||||
// In real system, this would call AI service
|
||||
// Here we just set a mock response for now
|
||||
message.setAiResponse("这是一个模拟的AI回复。");
|
||||
message.setAiResponseStatus("success");
|
||||
```
|
||||
|
||||
虽然项目中存在 `ToolCozeServiceImpl`(Coze AI 服务)的实现,但 `sendMessage()` 方法中并未调用它。
|
||||
|
||||
#### 2. 前端轮询机制导致延迟感
|
||||
|
||||
前端通过定时轮询 `getResponse()` 接口等待 AI 回复:
|
||||
- 用户发送消息 → 后端同步写入 mock 数据 → 前端轮询获取结果
|
||||
- 轮询间隔本身带来延迟,加上网络开销,用户体感"反应慢"
|
||||
|
||||
#### 3. 缺乏流式响应
|
||||
|
||||
当前架构没有 SSE(Server-Sent Events)或 WebSocket 支持,无法实现"逐字输出"的流式效果,用户需等待完整回复后才能看到内容。
|
||||
|
||||
### 修复建议
|
||||
|
||||
1. **正式接入 Coze AI 服务**:在 `sendMessage()` 中调用 `ToolCozeServiceImpl`,真正发起 AI 对话请求
|
||||
2. **优化 Prompt 模板**:设计结构化的系统提示词(System Prompt),要求 AI 回复遵循固定格式(如:摘要 → 营养分析 → 建议 → 注意事项),提升内容逻辑性
|
||||
3. **引入 SSE 流式返回**:后端通过 SSE 推送逐步响应,前端实时渲染,提升交互体验
|
||||
4. **增加加载状态动效**:在等待回复期间展示更好的"正在思考"动画
|
||||
|
||||
### 优先级:高
|
||||
|
||||
---
|
||||
|
||||
## 三、食物百科 —— 成分表不全、图片错误、缺少重量标注
|
||||
|
||||
### 问题描述
|
||||
|
||||
食物百科中食物成分表内容不全,图片显示有错误,而且没有标注具体是多少重量的食物所提供的营养成分。
|
||||
|
||||
### 问题定位
|
||||
|
||||
**后端文件:** `msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolFoodServiceImpl.java`
|
||||
**前端文件:** `msh_single_uniapp/pages/tool/food-detail.vue`
|
||||
**数据模型:** `msh_crmeb_22/crmeb-common/src/main/java/com/zbkj/common/model/tool/V2Food.java`
|
||||
|
||||
### 根因分析
|
||||
|
||||
#### 3.1 食物成分表内容不全
|
||||
|
||||
后端 `getDetail()` 方法返回的营养字段不完整:
|
||||
|
||||
```java
|
||||
// 当前返回的字段
|
||||
map.put("energy", food.getEnergy());
|
||||
map.put("protein", food.getProtein());
|
||||
map.put("fat", food.getFat());
|
||||
map.put("carbohydrate", food.getCarbohydrate());
|
||||
map.put("potassium", food.getPotassium());
|
||||
map.put("phosphorus", food.getPhosphorus());
|
||||
map.put("sodium", food.getSodium());
|
||||
```
|
||||
|
||||
`V2Food` 模型中定义了但未返回的字段包括:
|
||||
- `calcium`(钙)
|
||||
- `iron`(铁)
|
||||
- `vitaminC`(维生素 C)
|
||||
- `nutrientsJson`(扩展营养素 JSON)
|
||||
- `recommendedAmount`(推荐摄入量)
|
||||
|
||||
前端 `food-detail.vue` 的 `parseNutritionTable()` 方法尝试解析 `calcium`、`purine` 等字段,但后端根本没有返回这些数据。
|
||||
|
||||
#### 3.2 图片显示错误
|
||||
|
||||
两个层面的图片问题:
|
||||
|
||||
**a) 前端硬编码了 Figma 临时 URL**
|
||||
|
||||
`food-detail.vue` 和 `nutrient-detail.vue` 中的默认图片使用了 Figma API 的临时资源 URL:
|
||||
|
||||
```javascript
|
||||
iconWhyImportant: 'https://www.figma.com/api/mcp/asset/51e00c9b-5719-4391-9dff-68b70d24aece'
|
||||
```
|
||||
|
||||
这些 URL 是开发阶段从 Figma 设计稿导出的临时链接,过期后图片无法加载。
|
||||
|
||||
**b) 后端 AI 生图服务不稳定**
|
||||
|
||||
`DishImageService` 通过 AI 生成食物图片并上传 OSS。当 AI API 调用失败时,部分食物的 `image` 字段为空或仍为旧的无效 URL,导致前端图片显示异常。
|
||||
|
||||
#### 3.3 缺少重量标注
|
||||
|
||||
后端接口返回数据中 **没有 `servingSize`(份量基准)字段**。前端虽然显示了"每100g"标签,但这是硬编码的静态文本,并非根据实际数据动态展示。如果数据库中部分食物的营养数据不是基于 100g 标准录入的,就会产生误导。
|
||||
|
||||
### 修复建议
|
||||
|
||||
1. **补充后端返回字段**:在 `getDetail()` 中增加 `calcium`、`iron`、`vitaminC`、`nutrientsJson`、`recommendedAmount` 等字段的返回
|
||||
2. **替换 Figma 临时 URL**:将所有 Figma API 链接替换为上传至 OSS 的稳定图片资源
|
||||
3. **增加图片容错处理**:前端为食物图片增加 `@error` 事件处理,在图片加载失败时显示占位图
|
||||
4. **增加重量标注字段**:数据库添加 `serving_size` 字段(如"每100g"、"每份(50g)"),后端返回后前端动态显示
|
||||
|
||||
### 优先级:中高
|
||||
|
||||
---
|
||||
|
||||
## 四、健康知识营养素板块 —— 所有选项显示同一内容
|
||||
|
||||
### 问题描述
|
||||
|
||||
健康知识中营养素板块,所有的营养素选项(蛋白质、钾、磷、钠、钙、水分)点击后显示的都是同一个内容。
|
||||
|
||||
### 问题定位
|
||||
|
||||
**列表页:** `msh_single_uniapp/pages/tool/nutrition-knowledge.vue` 第 39 行
|
||||
**详情页:** `msh_single_uniapp/pages/tool/nutrient-detail.vue` 第 114 行、第 137-277 行
|
||||
|
||||
### 根因分析
|
||||
|
||||
这是一个**前端事件传参 + 数据默认值**联合导致的 Bug。
|
||||
|
||||
#### Bug 链条
|
||||
|
||||
**第一环:列表页事件传参问题**
|
||||
|
||||
`nutrition-knowledge.vue` 中营养素卡片的点击事件:
|
||||
|
||||
```html
|
||||
@click="goToNutrientDetail" :data-nutrient-index="index"
|
||||
```
|
||||
|
||||
`goToNutrientDetail` 方法通过 `event.currentTarget.dataset.nutrientIndex` 获取索引值。但在**微信小程序**环境中,`dataset` 的属性名会被自动转换为全小写(`nutrientindex` 而非 `nutrientIndex`),导致取值为 `undefined`。
|
||||
|
||||
当 index 为 `undefined` 时,`this.nutrientList[undefined]` 返回 `undefined`,方法执行 `if (!item) return` 直接退出,**不发起页面跳转**。
|
||||
|
||||
即使跳转成功,中文参数 `name` 经过 `encodeURIComponent` 编码后,在某些小程序版本中解码可能不正确,导致 `nutrientMap[name]` 匹配失败。
|
||||
|
||||
**第二环:详情页默认数据兜底**
|
||||
|
||||
`nutrient-detail.vue` 的 `data()` 中硬编码了**"钠(Sodium)"**作为默认数据:
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
nutrientData: {
|
||||
name: '钠',
|
||||
english: 'Sodium (Na)',
|
||||
icon: '🧂',
|
||||
// ... 其他钠的数据
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当 `loadNutrientData(name)` 中 `name` 为空或不匹配 `nutrientMap` 的任何 key 时,`nutrientData` 不会被更新,页面始终显示默认的"钠"内容。
|
||||
|
||||
**结果**:无论点击哪个营养素,要么不跳转,要么跳转后参数丢失,最终所有页面都显示默认的"钠"内容。
|
||||
|
||||
### 修复建议
|
||||
|
||||
**修复 1:改用直接传参方式(推荐)**
|
||||
|
||||
```html
|
||||
<!-- nutrition-knowledge.vue -->
|
||||
<!-- 修改前 -->
|
||||
@click="goToNutrientDetail" :data-nutrient-index="index"
|
||||
|
||||
<!-- 修改后 -->
|
||||
@click="goToNutrientDetail(index)"
|
||||
```
|
||||
|
||||
```javascript
|
||||
// 方法改为接收 index 参数
|
||||
goToNutrientDetail(index) {
|
||||
const item = this.nutrientList[index];
|
||||
if (!item) return;
|
||||
uni.navigateTo({
|
||||
url: `/pages/tool/nutrient-detail?name=${encodeURIComponent(item.name)}`
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**修复 2:详情页增加参数解码和容错**
|
||||
|
||||
```javascript
|
||||
// nutrient-detail.vue
|
||||
onLoad(options) {
|
||||
if (options.name) {
|
||||
const name = decodeURIComponent(options.name);
|
||||
this.loadNutrientData(name);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**修复 3:默认数据改为空状态**
|
||||
|
||||
将 `data()` 中的默认 `nutrientData` 改为空对象,并在页面增加空状态提示,避免误导用户。
|
||||
|
||||
### 优先级:高
|
||||
|
||||
---
|
||||
|
||||
## 问题优先级汇总
|
||||
|
||||
| 序号 | 问题 | 类型 | 优先级 | 影响范围 |
|
||||
|------|------|------|--------|----------|
|
||||
| 一 | 食谱计算器用油量偏多 | 算法缺陷 | 高 | 所有使用计算器的用户 |
|
||||
| 二 | AI 营养师体验差 | 功能缺失 | 高 | 所有使用 AI 营养师的用户 |
|
||||
| 三 | 食物百科成分表/图片/重量 | 数据不完整 | 中高 | 所有查看食物详情的用户 |
|
||||
| 四 | 营养素板块显示重复 | 前端 Bug | 高 | 所有查看营养素详情的用户 |
|
||||
|
||||
---
|
||||
|
||||
## 涉及文件清单
|
||||
|
||||
### 后端(Java)
|
||||
|
||||
| 文件 | 问题 |
|
||||
|------|------|
|
||||
| `ToolCalculatorServiceImpl.java` | 问题一:油脂系数错误 |
|
||||
| `ToolAiNutritionistServiceImpl.java` | 问题二:AI 服务未接入 |
|
||||
| `ToolFoodServiceImpl.java` | 问题三:返回字段不完整 |
|
||||
| `V2Food.java` | 问题三:缺少 serving_size 字段 |
|
||||
|
||||
### 前端(Vue)
|
||||
|
||||
| 文件 | 问题 |
|
||||
|------|------|
|
||||
| `pages/tool/food-detail.vue` | 问题三:图片 URL、重量标注 |
|
||||
| `pages/tool/nutrient-detail.vue` | 问题三/四:Figma URL、默认数据 |
|
||||
| `pages/tool/nutrition-knowledge.vue` | 问题四:事件传参兼容性 |
|
||||
Reference in New Issue
Block a user