食谱计算器后端接口开发文档
版本:v1.0
创建日期:2026-02-01
所属模块:Tool(工具模块)
配套前端:msh_single_uniapp/pages/tool/calculator.vue / calculator-result.vue
一、功能概述
食谱计算器是慢生活智能营养专家的核心功能之一,面向肾病(CKD)及透析患者,根据用户输入的健康数据,自动计算:
- 健康指标:eGFR、标准体重、BMI、CKD分期
- 每日营养目标:蛋白质摄入量(g/d)、能量摄入量(kcal/d)
- 食物份数建议:7 类食物的每日推荐份数
- 一日三餐配餐方案:早餐、午餐、晚餐的菜品清单(含图片、食材用量)
- 重要提示:根据患者情况给出饮食注意事项
用户可进一步采纳营养计划,进入打卡流程(另单独接口)。
二、接口清单
| 序号 |
接口名称 |
HTTP方法 |
路径 |
说明 |
| 1 |
计算营养方案 |
POST |
/api/front/tool/calculator/calculate |
核心接口,输入健康数据,返回计算结果 |
| 2 |
获取计算结果详情 |
GET |
/api/front/tool/calculator/result/{id} |
通过结果ID获取完整结果(含配餐) |
| 3 |
采纳营养计划 |
POST |
/api/front/tool/calculator/adopt |
用户采纳后创建营养计划,进入打卡流程 |
三、接口详细设计
3.1 计算营养方案
基础信息
| 项目 |
值 |
| 请求路径 |
POST /api/front/tool/calculator/calculate |
| 是否鉴权 |
是(需登录) |
| Content-Type |
application/json |
请求参数(Request Body)
| 参数名 |
类型 |
必填 |
说明 |
校验规则 |
gender |
String |
是 |
性别 |
可选值:male / female |
age |
Integer |
是 |
年龄(岁) |
1 ≤ age ≤ 150 |
height |
Integer |
是 |
身高(cm) |
50 ≤ height ≤ 250 |
dialysis |
Boolean |
是 |
是否透析 |
true / false |
dialysisType |
String |
否 |
透析类型 |
当 dialysis=true 时有效;可选值:hemodialysis(血透)/ peritoneal(腹透) |
dryWeight |
Number |
是 |
干体重(kg) |
20 ≤ dryWeight ≤ 300,支持1位小数 |
creatinine |
Number |
是 |
血肌酐(μmol/L) |
0 < creatinine ≤ 2000,支持2位小数 |
请求示例
响应参数(Response Body)
| 参数名 |
类型 |
说明 |
code |
Integer |
状态码,200 表示成功 |
message |
String |
提示信息 |
data |
Object |
计算结果对象 |
data 结构
| 字段名 |
类型 |
说明 |
id / resultId |
Long |
计算结果唯一ID,用于后续查询/采纳 |
healthData |
Object |
健康数据计算结果 |
nutritionGoals |
Object |
每日营养目标 |
foodList |
Array |
食物份数建议列表 |
mealPlan |
Object |
一日三餐配餐方案 |
importantTips |
Array<String> |
重要提示文案列表 |
createdAt |
String |
创建时间 ISO8601 |
healthData 结构
| 字段名 |
类型 |
说明 |
计算公式 |
eGFR |
String |
肾小球滤过率(ml/min/1.73m²) |
CKD-EPI 公式(见附录 A) |
standardWeight |
String |
标准体重(kg) |
男:(height - 80) × 0.7;女:(height - 70) × 0.6 |
bmi |
String |
体重指数 |
dryWeight / (height/100)² |
bmiStatus |
String |
BMI 状态描述 |
见附录 B |
ckdStage |
String |
CKD 分期 |
见附录 C |
nutritionGoals 结构
| 字段名 |
类型 |
说明 |
计算公式 |
protein |
String |
每日蛋白质目标(克) |
透析期:standardWeight × 1.2;非透析期:standardWeight × 0.8 |
energy |
String |
每日能量目标(千卡) |
standardWeight × 35 |
foodList 结构(数组,7 项)
| 字段名 |
类型 |
说明 |
number |
Integer |
序号 1-7 |
name |
String |
食物类别名称(如"谷薯50g") |
portion |
String |
推荐份数 |
mealPlan 结构
| 字段名 |
类型 |
说明 |
breakfast |
Array |
早餐菜品列表 |
lunch |
Array |
午餐菜品列表 |
dinner |
Array |
晚餐菜品列表 |
菜品对象结构
| 字段名 |
类型 |
说明 |
name |
String |
菜品名称 |
image |
String |
菜品图片 URL |
ingredients |
Array<String> |
食材列表(如 ["牛奶 120g", "面条 90g"]) |
响应示例
{
"code": 200,
"message": "success",
"data": {
"id": 100234,
"healthData": {
"eGFR": "7.9",
"standardWeight": "63.0",
"bmi": "22.7",
"bmiStatus": "正常",
"ckdStage": "CKD 5期"
},
"nutritionGoals": {
"protein": "75.6",
"energy": "2205"
},
"foodList": [
{ "number": 1, "name": "谷薯50g", "portion": "5.7" },
{ "number": 2, "name": "淀粉100g", "portion": "0.77" },
{ "number": 3, "name": "绿叶蔬菜200g", "portion": "1" },
{ "number": 4, "name": "瓜果蔬菜200g", "portion": "2" },
{ "number": 5, "name": "奶类230g", "portion": "1" },
{ "number": 6, "name": "肉蛋类50/60g", "portion": "7" },
{ "number": 7, "name": "油脂类10g", "portion": "5.7" }
],
"mealPlan": {
"breakfast": [
{
"name": "牛奶",
"image": "https://cdn.xxx.com/images/milk.jpg",
"ingredients": ["牛奶 120g"]
},
{
"name": "鸡蛋拌面",
"image": "https://cdn.xxx.com/images/egg-noodle.jpg",
"ingredients": ["面条 90g", "鸡蛋 120g", "葱花 5g"]
},
{
"name": "凉拌黄瓜",
"image": "https://cdn.xxx.com/images/cucumber.jpg",
"ingredients": ["黄瓜 100g"]
}
],
"lunch": [
{
"name": "米饭",
"image": "https://cdn.xxx.com/images/rice.jpg",
"ingredients": ["大米 100g"]
},
{
"name": "清蒸鲈鱼",
"image": "https://cdn.xxx.com/images/bass.jpg",
"ingredients": ["鲈鱼 120g", "生姜 5g", "葱 5g"]
},
{
"name": "蒜蓉西兰花",
"image": "https://cdn.xxx.com/images/broccoli.jpg",
"ingredients": ["西兰花 150g", "大蒜 5g", "植物油 8g"]
},
{
"name": "冬瓜汤",
"image": "https://cdn.xxx.com/images/wax-gourd-soup.jpg",
"ingredients": ["冬瓜 150g"]
}
],
"dinner": [
{
"name": "杂粮饭",
"image": "https://cdn.xxx.com/images/mixed-rice.jpg",
"ingredients": ["大米 70g", "小米 30g"]
},
{
"name": "香菇炒鸡丁",
"image": "https://cdn.xxx.com/images/chicken-mushroom.jpg",
"ingredients": ["鸡胸肉 100g", "香菇 50g", "植物油 8g"]
},
{
"name": "清炒油菜",
"image": "https://cdn.xxx.com/images/bok-choy.jpg",
"ingredients": ["油菜 150g", "植物油 5g"]
},
{
"name": "番茄蛋花汤",
"image": "https://cdn.xxx.com/images/tomato-egg-soup.jpg",
"ingredients": ["番茄 100g", "鸡蛋 60g"]
}
]
},
"importantTips": [
"以上配餐由 AI 生成,仅适用于无其他并发症的单纯尿毒症人群",
"透析患者需严格控制水分摄入",
"建议低盐饮食(每日少于 5g)",
"注意限制高钾食物(香蕉、橙子、土豆等)",
"限制高磷食物(坚果、动物内脏等)",
"特别提醒:尿毒症合并其他并发症人群不适用此配餐,请务必咨询专业营养师调整方案"
],
"createdAt": "2026-02-01T10:30:00+08:00"
}
}
错误码
| code |
message |
说明 |
| 400 |
参数校验失败 |
请求参数不符合校验规则 |
| 401 / 410000-410002 |
未登录/登录过期 |
需重新登录 |
| 500 |
系统异常 |
服务端内部错误 |
3.2 获取计算结果详情
基础信息
| 项目 |
值 |
| 请求路径 |
GET /api/front/tool/calculator/result/{id} |
| 是否鉴权 |
是 |
| 路径参数 |
id:计算结果ID(Long) |
响应
与 3.1 的 data 结构相同,用于结果页刷新或分享后重新加载。
3.3 采纳营养计划
基础信息
| 项目 |
值 |
| 请求路径 |
POST /api/front/tool/calculator/adopt |
| 是否鉴权 |
是 |
| Content-Type |
application/json |
请求参数
| 参数名 |
类型 |
必填 |
说明 |
resultId |
Long |
是 |
计算结果ID |
请求示例
响应
| 字段名 |
类型 |
说明 |
code |
Integer |
200 成功 |
message |
String |
提示信息 |
data.planId |
Long |
新创建的营养计划ID |
data.startDate |
String |
计划开始日期 |
data.endDate |
String |
计划结束日期(默认 +7 天) |
响应示例
业务规则
- 同一用户同一时间只能有 1 个激活状态(
status=active) 的营养计划;若已存在则自动将旧计划标记为 abandoned。
- 采纳成功后赠送 +20 积分(积分任务:采纳营养方案)。
四、数据库表设计
4.1 计算结果表(calculator_results)
存储每次计算的输入与输出,方便查询历史、分析
4.2 营养计划表(nutrition_plans)
PRD 中已定义,补充关联
关联关系:nutrition_plans.source_result_id → calculator_results.id(可选字段,用于溯源)
五、核心算法
5.1 eGFR 计算(CKD-EPI 2021 公式)
5.2 标准体重
5.3 BMI
5.4 BMI 状态
| BMI 范围 |
状态描述 |
| < 18.5 |
体型过轻 |
| 18.5 - 23.9 |
正常 |
| 24.0 - 27.9 |
超重 |
| ≥ 28.0 |
肥胖 |
5.5 CKD 分期
| eGFR 范围 |
分期 |
| ≥ 90 |
CKD 1期 |
| 60 - 89 |
CKD 2期 |
| 45 - 59 |
CKD 3a期 |
| 30 - 44 |
CKD 3b期 |
| 15 - 29 |
CKD 4期 |
| < 15(非透析) |
CKD 5期 |
| 透析患者 |
透析期 |
5.6 营养目标
5.7 食物份数
基于能量和蛋白质目标,按照《慢性肾脏病患者膳食指导(2017)》推荐比例分配,具体算法可参考专业营养软件或配置表。
5.8 配餐方案生成
- 规则匹配:基于 CKD 分期、透析类型、营养目标,从预置的 配餐模板库(recipes) 中匹配合适方案。
- AI 生成(可选):调用 AI 模型根据营养目标动态生成菜品及食材用量。
- 输出:早/午/晚三餐各 2-4 道菜,包含图片 URL 和食材列表。
六、性能与安全
6.1 缓存策略
| 数据 |
缓存方式 |
过期时间 |
说明 |
| 计算结果 |
Redis Hash |
24 小时 |
key = calc_result:{id} |
| 配餐模板库 |
本地缓存 / Redis |
1 小时 |
减少 DB 查询 |
6.2 限流
| 接口 |
QPS 限制 |
说明 |
| calculate |
10/用户/分钟 |
防止恶意刷算 |
| result/{id} |
60/用户/分钟 |
允许刷新 |
| adopt |
5/用户/分钟 |
防重复提交 |
6.3 幂等性
- calculate:每次计算生成新记录,允许重复调用。
- adopt:采纳接口需幂等设计,同一
resultId 多次调用只创建一个计划;可用 user_id + result_id 唯一索引或分布式锁。
6.4 数据安全
- 所有接口均需登录鉴权(Header:
Authori-zation)。
- 用户只能查询/采纳自己的计算结果(
user_id 校验)。
- 敏感健康数据传输全程 HTTPS。
七、测试用例
7.1 正常场景
| 用例编号 |
描述 |
输入 |
预期输出 |
| TC01 |
男性透析患者计算 |
gender=male, age=55, height=170, dialysis=true, dryWeight=65.5, creatinine=850 |
返回 code=200,healthData/nutritionGoals/mealPlan 完整 |
| TC02 |
女性非透析患者 |
gender=female, age=48, height=160, dialysis=false, dryWeight=52, creatinine=180 |
返回 code=200,ckdStage 按 eGFR 判断 |
| TC03 |
查询结果详情 |
GET /result/100234 |
返回与 calculate 相同结构 |
| TC04 |
采纳营养计划 |
resultId=100234 |
返回 planId,计划 status=active |
7.2 异常场景
| 用例编号 |
描述 |
输入 |
预期输出 |
| TC11 |
年龄超出范围 |
age=200 |
code=400, message 包含"年龄" |
| TC12 |
未登录调用 |
无 Token |
code=401/410000 |
| TC13 |
查询他人结果 |
id 属于其他用户 |
code=403 |
| TC14 |
重复采纳 |
同一 resultId 调用两次 |
第二次返回已存在的 planId(幂等) |
八、附录
附录 A:CKD-EPI 2021 公式
无种族系数版本,适用于中国人群
附录 B:BMI 分类标准(中国)
| BMI |
分类 |
| < 18.5 |
体型过轻 |
| 18.5 - 23.9 |
正常 |
| 24.0 - 27.9 |
超重 |
| ≥ 28.0 |
肥胖 |
附录 C:CKD 分期标准
| 分期 |
eGFR (ml/min/1.73m²) |
描述 |
| 1期 |
≥ 90 |
肾功能正常或升高 |
| 2期 |
60-89 |
轻度下降 |
| 3a期 |
45-59 |
轻-中度下降 |
| 3b期 |
30-44 |
中-重度下降 |
| 4期 |
15-29 |
重度下降 |
| 5期 |
< 15 |
肾衰竭 |
| 透析期 |
— |
已接受透析治疗 |
九、变更记录
| 版本 |
日期 |
作者 |
变更内容 |
| v1.0 |
2026-02-01 |
— |
初稿 |
文档结束