Initial commit: MSH System\n\n- msh_single_uniapp: Vue 2 + UniApp 前端(微信小程序/H5/App/支付宝小程序)\n- msh_crmeb_22: Spring Boot 2.2 后端(C端API/管理端/业务逻辑)\n- models-integration: AI服务集成(Coze/KieAI/腾讯ASR)\n- docs: 产品文档与设计稿
This commit is contained in:
166
.cursor/plans/计算器结果保存食谱_f149b3dc.plan.md
Normal file
166
.cursor/plans/计算器结果保存食谱_f149b3dc.plan.md
Normal file
@@ -0,0 +1,166 @@
|
||||
---
|
||||
name: 计算器结果保存食谱
|
||||
overview: 在用户采纳营养计划时,将食谱计算器的配餐方案提取并保存到 v2_recipes 食谱表,并在首页"精选食谱"中混合展示用户自己的食谱(排在前面)。
|
||||
todos:
|
||||
- id: db-migration
|
||||
content: 新建 SQL 变更文件,v2_recipes 表新增 source 和 source_id 字段
|
||||
status: completed
|
||||
- id: entity-update
|
||||
content: V2Recipe.java 实体类新增 source 和 sourceId 属性
|
||||
status: completed
|
||||
- id: adopt-save-recipe
|
||||
content: ToolCalculatorServiceImpl.adopt() 中新增保存食谱到 v2_recipes 的逻辑(含幂等检查)
|
||||
status: completed
|
||||
- id: home-mix-recipes
|
||||
content: ToolHomeServiceImpl.getRecommendedRecipes() 混入当前用户的计算器食谱
|
||||
status: completed
|
||||
- id: home-return-fields
|
||||
content: 推荐食谱接口返回字段补充 description、source、totalProtein
|
||||
status: completed
|
||||
- id: frontend-recipe-card
|
||||
content: 首页 index.vue 食谱卡片展示适配(tag、desc 等字段映射)
|
||||
status: completed
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# 食谱计算器结果保存到食谱表
|
||||
|
||||
## 整体流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FE as 前端
|
||||
participant Ctrl as ToolController
|
||||
participant CalcSvc as ToolCalculatorServiceImpl
|
||||
participant RecipeDao as V2RecipeDao
|
||||
participant HomeSvc as ToolHomeServiceImpl
|
||||
|
||||
User->>FE: 点击"采纳计划"
|
||||
FE->>Ctrl: POST /calculator/adopt
|
||||
Ctrl->>CalcSvc: adopt(resultId)
|
||||
CalcSvc->>CalcSvc: 创建营养计划 (已有逻辑)
|
||||
CalcSvc->>RecipeDao: 保存一条食谱到 v2_recipes
|
||||
CalcSvc-->>FE: 返回 adoptResponse
|
||||
Note over FE: 首页刷新时
|
||||
FE->>Ctrl: GET /home/recipes
|
||||
Ctrl->>HomeSvc: getRecommendedRecipes()
|
||||
HomeSvc->>RecipeDao: 查询推荐食谱 + 用户自己的食谱
|
||||
HomeSvc-->>FE: 返回混合列表
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 1. 数据库变更 - v2_recipes 新增字段
|
||||
|
||||
需要新增两个字段以追踪食谱来源:
|
||||
|
||||
```sql
|
||||
ALTER TABLE v2_recipes
|
||||
ADD COLUMN source VARCHAR(20) DEFAULT 'manual' COMMENT '来源:manual(手动)/calculator(计算器)/ai(AI生成)' AFTER sort_order,
|
||||
ADD COLUMN source_id BIGINT DEFAULT NULL COMMENT '来源ID(如计算器结果ID)' AFTER source;
|
||||
```
|
||||
|
||||
同时新增一个变更 SQL 文件记录此次 DDL。
|
||||
|
||||
## 2. 后端 - 实体类更新
|
||||
|
||||
**文件**: [V2Recipe.java](msh_crmeb_22/crmeb-common/src/main/java/com/zbkj/common/model/tool/V2Recipe.java)
|
||||
|
||||
新增两个字段:
|
||||
|
||||
```java
|
||||
@ApiModelProperty(value = "来源:manual/calculator/ai")
|
||||
private String source;
|
||||
|
||||
@ApiModelProperty(value = "来源ID(计算器结果ID等)")
|
||||
private Long sourceId;
|
||||
```
|
||||
|
||||
## 3. 后端 - 采纳时保存食谱
|
||||
|
||||
**文件**: [ToolCalculatorServiceImpl.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCalculatorServiceImpl.java)
|
||||
|
||||
在 `adopt()` 方法中,步骤 5(创建营养计划)之后,新增步骤"保存食谱到 v2_recipes":
|
||||
|
||||
- 注入 `V2RecipeDao`
|
||||
- 从 `V2CalculatorResult` 中解析 `mealPlanJson` 得到 MealPlan
|
||||
- 构建 `V2Recipe` 对象:
|
||||
- `userId` = 当前用户ID
|
||||
- `name` = "每日营养配餐 - {ckdStage}",如 "每日营养配餐 - CKD 5期"
|
||||
- `description` = "蛋白质 {proteinIntake}g/天 | 能量 {energyIntake}kcal/天"
|
||||
- `coverImage` = 取午餐第一道菜的图片 URL(最具代表性)
|
||||
- `mealType` = null(整日配餐,非单餐)
|
||||
- `category` = "营养配餐"
|
||||
- `tagsJson` = `["AI配餐", "{ckdStage}"]`
|
||||
- `ingredientsJson` = 聚合三餐所有食材
|
||||
- `stepsJson` = 存放完整 mealPlanJson(早/午/晚餐详情),复用此字段存储配餐详情
|
||||
- `totalProtein` = result.getProteinIntake()
|
||||
- `totalEnergy` = result.getEnergyIntake()
|
||||
- `suitableStagesJson` = `["{ckdStage}"]`
|
||||
- `suitableDialysis` = result.getHasDialysis()
|
||||
- `status` = "published"
|
||||
- `isRecommend` = 0(不进入官方推荐,通过 source + userId 查询)
|
||||
- `isOfficial` = 0
|
||||
- `source` = "calculator"
|
||||
- `sourceId` = resultId
|
||||
- 幂等处理:先检查是否已存在 `source='calculator' AND source_id=resultId` 的记录,避免重复
|
||||
|
||||
## 4. 后端 - 首页推荐食谱混入用户食谱
|
||||
|
||||
**文件**: [ToolHomeServiceImpl.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolHomeServiceImpl.java)
|
||||
|
||||
修改 `getRecommendedRecipes()` 方法:
|
||||
|
||||
1. 如果用户已登录,先查询该用户的食谱(`user_id = currentUserId AND status = 'published' AND source = 'calculator'`,按 `created_at DESC`,取最新 1 条)
|
||||
2. 再查询官方推荐食谱(现有逻辑,`is_recommend = 1`)
|
||||
3. 将用户食谱排在前面,官方推荐排在后面,合并后返回
|
||||
4. 总数仍控制在 `limit` 范围内(如用户有 1 条自己的食谱,则官方推荐取 limit-1 条)
|
||||
5. 缓存 key 需要区分用户(登录用户的缓存 key 加上 userId)
|
||||
|
||||
## 5. 后端 - 推荐食谱接口返回字段补充
|
||||
|
||||
**文件**: [ToolHomeServiceImpl.java](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolHomeServiceImpl.java)
|
||||
|
||||
在返回数据 map 中增加字段,使前端能够区分并展示更多信息:
|
||||
|
||||
```java
|
||||
map.put("id", recipe.getRecipeId());
|
||||
map.put("name", recipe.getName());
|
||||
map.put("coverImage", recipe.getCoverImage());
|
||||
map.put("totalEnergy", recipe.getTotalEnergy());
|
||||
map.put("description", recipe.getDescription()); // 新增
|
||||
map.put("source", recipe.getSource()); // 新增:标记来源
|
||||
map.put("totalProtein", recipe.getTotalProtein()); // 新增
|
||||
```
|
||||
|
||||
## 6. 前端 - 首页食谱展示适配
|
||||
|
||||
**文件**: [index.vue (首页)](msh_single_uniapp/pages/tool_main/index.vue)
|
||||
|
||||
调整食谱卡片展示逻辑:
|
||||
|
||||
- `item.tag`:如果 `source === 'calculator'` 显示 "我的配餐",否则显示 "推荐"
|
||||
- `item.tagClass`:根据来源使用不同样式(如用户食谱用不同颜色)
|
||||
- `item.desc`:使用 `description` 字段(如 "蛋白质 75.6g/天 | 能量 2205kcal/天")
|
||||
- `item.time`:可不显示或显示 "每日配餐"
|
||||
- `item.views`:使用 `viewCount` 或隐藏
|
||||
|
||||
修改 `loadData` 中对 `recipeList` 的处理逻辑,将后端返回的数据映射为前端需要的格式。
|
||||
|
||||
## 7. 前端 - 食谱详情页适配
|
||||
|
||||
点击首页食谱卡片跳转到 `recipe-detail` 页面,需要确认该页面能正确显示来自计算器的食谱内容(特别是 `stepsJson` 中存储的 mealPlan 数据)。如果需要特殊处理,在详情页根据 `source` 字段做渲染分支。
|
||||
|
||||
## 涉及文件清单
|
||||
|
||||
|
||||
| 层级 | 文件 | 改动 |
|
||||
| -------- | --------------------------------------------- | ------------------------------ |
|
||||
| SQL | `docs/sql/v2_recipes_add_source.sql`(新建) | 新增 source、source_id 字段 |
|
||||
| Entity | `V2Recipe.java` | 新增 source、sourceId 字段 |
|
||||
| Service | `ToolCalculatorServiceImpl.java` | adopt() 中新增保存食谱逻辑 |
|
||||
| Service | `ToolHomeServiceImpl.java` | getRecommendedRecipes() 混入用户食谱 |
|
||||
| Frontend | `msh_single_uniapp/pages/tool_main/index.vue` | 食谱卡片展示适配 |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user