17 changed files with 1070 additions and 946 deletions
@ -0,0 +1,213 @@ |
|||||
|
package com.mathvision.diet.service; |
||||
|
|
||||
|
import com.alibaba.fastjson2.JSONArray; |
||||
|
import com.alibaba.fastjson2.JSONObject; |
||||
|
import com.google.common.collect.Lists; |
||||
|
import com.google.common.collect.Maps; |
||||
|
import com.google.common.collect.Range; |
||||
|
import com.mathvision.diet.domian.MenuDishItemDTO; |
||||
|
import com.mathvision.diet.entity.*; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.collections4.CollectionUtils; |
||||
|
import org.apache.commons.lang3.tuple.Pair; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
import java.math.BigDecimal; |
||||
|
import java.math.RoundingMode; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class MenuReportService { |
||||
|
@Resource |
||||
|
EnumService enumService; |
||||
|
|
||||
|
@Resource |
||||
|
NutritionService nutritionService; |
||||
|
|
||||
|
@Resource |
||||
|
IngredientService ingredientService; |
||||
|
|
||||
|
public JSONObject assess(Menu menu, long day, String crow, List<MenuDish> dishes) { |
||||
|
Nutrition nutrition = nutritionService.get(menu.getNutrient()); |
||||
|
BigDecimal overflow = nutrition.getOverflow(); |
||||
|
Map<String, Map<String, BigDecimal>> itemStandard = nutrition.getIngredient().getOrDefault(crow, new HashMap<>()); |
||||
|
Map<String, Ingredient> ingredientMap = ingredientService.getFullByKeys(dishes.stream().filter(x -> CollectionUtils.isNotEmpty(x.getIngredient())).flatMap(x -> x.getIngredient().stream().map(MenuDishItemDTO::getKey)).collect(Collectors.toSet())).stream().collect(Collectors.toMap(Ingredient::getKey, v -> v)); |
||||
|
Map<String, BigDecimal> items = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> item.getValue().containsKey(crow) && item.getValue().get(crow).doubleValue() > 0 && ingredientMap.containsKey(item.getKey()))).flatMap(x -> ingredientMap.get(x.getKey()).getNutrient().entrySet().stream().map(n -> Pair.of(n.getKey(), n.getValue().multiply(x.getValue().get(crow)).divide(new BigDecimal(100), RoundingMode.HALF_UP)))).collect(Collectors.toMap(Pair::getKey, Pair::getValue, BigDecimal::add)); |
||||
|
Map<String, Integer> types = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> ingredientMap.containsKey(item.getKey())).map(item -> ingredientMap.get(item.getKey()).getType())).collect(Collectors.toMap(x -> x, x -> 1, Integer::sum)); |
||||
|
|
||||
|
JSONObject result = new JSONObject(); |
||||
|
result.put("day", day); |
||||
|
result.put("crow", crow); |
||||
|
result.put("meals", dishes.stream().map(MenuDish::getMeal).collect(Collectors.toSet())); |
||||
|
result.put("types", types); |
||||
|
|
||||
|
JSONArray contents = new JSONArray(); |
||||
|
items.forEach((key, value) -> { |
||||
|
FoodNutrient foodNutrient = enumService.getNutrient(key); |
||||
|
|
||||
|
if (foodNutrient == null) { |
||||
|
return; |
||||
|
} |
||||
|
JSONObject content = new JSONObject(); |
||||
|
content.put("nutrition", String.format("%s/%s", foodNutrient.getValue(), foodNutrient.getMeasurement())); |
||||
|
content.put("virtual", value); |
||||
|
|
||||
|
Map<String, BigDecimal> standard = itemStandard.get(key); |
||||
|
BigDecimal max = standard == null ? null : standard.get("max"); |
||||
|
BigDecimal min = standard == null ? null : standard.get("min"); |
||||
|
BigDecimal ul = standard == null ? null : standard.get("ul"); |
||||
|
if (max == null) { |
||||
|
if (min == null) { |
||||
|
content.put("standard", "-"); |
||||
|
content.put("ul", ul == null ? "-" : ul.toString()); |
||||
|
content.put("overload", "-"); |
||||
|
content.put("conclusion", "-"); |
||||
|
} else { |
||||
|
content.put("standard", "≥" + min); |
||||
|
content.put("ul", ul == null ? "-" : ul.toString()); |
||||
|
if (min.compareTo(value) > 0) { |
||||
|
content.put("overload", value.subtract(min).divide(min, RoundingMode.FLOOR)); |
||||
|
if(min.subtract(value).compareTo(overflow.divide(new BigDecimal(100), RoundingMode.FLOOR).multiply(value)) > 0) { |
||||
|
content.put("conclusion", "不足"); |
||||
|
} else { |
||||
|
content.put("conclusion", "适量"); |
||||
|
} |
||||
|
} else { |
||||
|
content.put("overload", BigDecimal.ZERO); |
||||
|
content.put("conclusion", "适量"); |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
if (min == null) { |
||||
|
content.put("standard", "≤" + max); |
||||
|
content.put("ul", ul == null ? "-" : ul.toString()); |
||||
|
if (max.compareTo(value) < 0) { |
||||
|
if(value.subtract(max).compareTo(overflow.divide(new BigDecimal(100), RoundingMode.FLOOR).multiply(value)) > 0) { |
||||
|
if(ul != null && value.compareTo(ul) > 0) { |
||||
|
content.put("conclusion", "严重超标"); |
||||
|
} else { |
||||
|
content.put("conclusion", "超量"); |
||||
|
} |
||||
|
} else { |
||||
|
content.put("conclusion", "适量"); |
||||
|
} |
||||
|
content.put("overload", value.subtract(max).divide(max, RoundingMode.FLOOR)); |
||||
|
} else { |
||||
|
content.put("overload", BigDecimal.ZERO); |
||||
|
} |
||||
|
} else { |
||||
|
content.put("standard", min + "~" + max); |
||||
|
content.put("ul", ul == null ? "-" : ul.toString()); |
||||
|
if (min.compareTo(value) > 0) { |
||||
|
content.put("overload", value.subtract(min).divide(min, RoundingMode.FLOOR)); |
||||
|
if(min.subtract(value).compareTo(overflow.divide(new BigDecimal(100), RoundingMode.FLOOR).multiply(value)) > 0) { |
||||
|
content.put("conclusion", "不足"); |
||||
|
} else { |
||||
|
content.put("conclusion", "适量"); |
||||
|
} |
||||
|
} else { |
||||
|
if (max.compareTo(value) < 0) { |
||||
|
content.put("overload", value.subtract(max).divide(max, RoundingMode.FLOOR)); |
||||
|
if(value.subtract(max).compareTo(overflow.divide(new BigDecimal(100), RoundingMode.FLOOR).multiply(value)) > 0) { |
||||
|
if(ul != null && value.compareTo(ul) > 0) { |
||||
|
content.put("conclusion", "严重超标"); |
||||
|
} else { |
||||
|
content.put("conclusion", "超量"); |
||||
|
} |
||||
|
} else { |
||||
|
content.put("conclusion", "适量"); |
||||
|
} |
||||
|
} else { |
||||
|
content.put("overload", "0%"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
contents.add(content); |
||||
|
}); |
||||
|
result.put("ingredient", contents); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public JSONObject types(Menu menu, List<MenuDish> dishes) { |
||||
|
Nutrition nutrition = nutritionService.get(menu.getNutrient()); |
||||
|
Map<String, BigDecimal> dayStandard = nutrition.getFoodCategoryDay(); |
||||
|
Map<String, BigDecimal> weekStandard = nutrition.getFoodCategoryWeek(); |
||||
|
Map<String, Ingredient> ingredientMap = ingredientService.getFullByKeys(dishes.stream().filter(x -> CollectionUtils.isNotEmpty(x.getIngredient())).flatMap(x -> x.getIngredient().stream().map(MenuDishItemDTO::getKey)).collect(Collectors.toSet())).stream().collect(Collectors.toMap(Ingredient::getKey, v -> v)); |
||||
|
Map<Pair<Long, String>, Integer> typesDay = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> ingredientMap.containsKey(item.getKey())).map(item -> Pair.of(dish.getDay(), ingredientMap.get(item.getKey()).getType()))).collect(Collectors.toMap(x -> x, x -> 1, Integer::sum)); |
||||
|
JSONArray dayRule = new JSONArray(); |
||||
|
Map<Long, JSONArray> dayMaps = Maps.newHashMap(); |
||||
|
typesDay.forEach((key, num) -> { |
||||
|
Long day = key.getKey(); |
||||
|
JSONArray dayCollection = dayMaps.getOrDefault(day, new JSONArray()); |
||||
|
String type = key.getValue(); |
||||
|
int standard = dayStandard.getOrDefault(type, BigDecimal.ZERO).intValue(); |
||||
|
JSONObject content = new JSONObject(); |
||||
|
content.put("day", day); |
||||
|
content.put("name", type); |
||||
|
content.put("standard", standard); |
||||
|
content.put("supplied", num); |
||||
|
content.put("lack", num >= standard ? 0 : standard - num); |
||||
|
dayCollection.add(content); |
||||
|
dayMaps.put(day, dayCollection); |
||||
|
}); |
||||
|
dayRule.addAll(dayMaps.values()); |
||||
|
|
||||
|
Map<String, Integer> typesAll = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> ingredientMap.containsKey(item.getKey())).map(item -> ingredientMap.get(item.getKey()).getType())).collect(Collectors.toMap(x -> x, x -> 1, Integer::sum)); |
||||
|
JSONArray weekRule = new JSONArray(); |
||||
|
typesAll.forEach((type, num) -> { |
||||
|
BigDecimal standard = weekStandard.getOrDefault(type, BigDecimal.ZERO); |
||||
|
JSONObject content = new JSONObject(); |
||||
|
content.put("name", type); |
||||
|
content.put("standard", standard); |
||||
|
content.put("supplied", num); |
||||
|
content.put("lack", num.compareTo(standard.intValue()) > 0 ? 0 : standard.intValue() - num); |
||||
|
weekRule.add(content); |
||||
|
}); |
||||
|
|
||||
|
JSONObject result = new JSONObject(); |
||||
|
result.put("dayRule", dayRule); |
||||
|
result.put("weekRule", weekRule); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public JSONObject energy(long day, String crow, List<MenuDish> dishes) { |
||||
|
List<String> allConcerned= Lists.newArrayList("energy", "protein", "fat", "carbs"); |
||||
|
Map<String, Ingredient> ingredientMap = ingredientService.getFullByKeys(dishes.stream().filter(x -> CollectionUtils.isNotEmpty(x.getIngredient())).flatMap(x -> x.getIngredient().stream().map(MenuDishItemDTO::getKey)).collect(Collectors.toSet())).stream().collect(Collectors.toMap(Ingredient::getKey, v -> v)); |
||||
|
Map<String, BigDecimal> items = dishes.stream() |
||||
|
.flatMap(dish -> dish.getIngredient().stream().filter(item -> item.getValue().containsKey(crow) && item.getValue().get(crow).doubleValue() > 0 && ingredientMap.containsKey(item.getKey()))) |
||||
|
.flatMap(x -> ingredientMap.get(x.getKey()).getNutrient().entrySet().stream().map(n -> Pair.of(n.getKey(), n.getValue().multiply(x.getValue().get(crow)).divide(new BigDecimal(100), RoundingMode.HALF_UP)))) |
||||
|
.filter(x -> allConcerned.contains(x.getKey())) |
||||
|
.collect(Collectors.toMap(Pair::getKey, Pair::getValue, BigDecimal::add)); |
||||
|
|
||||
|
JSONObject result = new JSONObject(); |
||||
|
result.put("day", day); |
||||
|
result.put("crow", crow); |
||||
|
result.put("meals", dishes.stream().map(MenuDish::getMeal).collect(Collectors.toSet())); |
||||
|
|
||||
|
BigDecimal energy = items.get("energy"); |
||||
|
if (energy == null || energy.doubleValue() <= 0) { |
||||
|
return result; |
||||
|
} |
||||
|
JSONArray contents = new JSONArray(); |
||||
|
contents.add(toEnergyContent(energy, "protein", Range.closed(10, 20), items, ingredientMap)); |
||||
|
contents.add(toEnergyContent(energy, "fat", Range.closed(20, 30), items, ingredientMap)); |
||||
|
contents.add(toEnergyContent(energy, "carbs", Range.closed(50, 60), items, ingredientMap)); |
||||
|
result.put("energy", contents); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private JSONObject toEnergyContent(BigDecimal energy, String key, Range<Integer> standard, Map<String, BigDecimal> items, Map<String, Ingredient> ingredientMap) { |
||||
|
double value = items.getOrDefault(key, BigDecimal.ZERO).divide(energy, RoundingMode.FLOOR).multiply(new BigDecimal(100)).doubleValue(); |
||||
|
JSONObject result = JSONObject.of("name", enumService.getNutrient(key).getValue() + "/总能量"); |
||||
|
result.put("standard", String.format("%s~%s", standard.lowerEndpoint(), standard.upperEndpoint())); |
||||
|
result.put("value", value); |
||||
|
result.put("conclusion", standard.lowerEndpoint() > value ? "略低" : standard.upperEndpoint() < value ? "略高" : "合适"); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
package com.mathvision.diet.controller; |
||||
|
|
||||
|
import com.alibaba.fastjson2.JSONObject; |
||||
|
import com.mathvision.diet.entity.Menu; |
||||
|
import com.mathvision.diet.entity.MenuDish; |
||||
|
import com.mathvision.diet.service.MenuDishService; |
||||
|
import com.mathvision.diet.service.MenuReportService; |
||||
|
import com.mathvision.diet.service.MenuService; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.springframework.stereotype.Controller; |
||||
|
import org.springframework.util.Assert; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMethod; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
import java.time.LocalDate; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@RequestMapping("/api/menu/analysis") |
||||
|
@Controller |
||||
|
public class MenuReportController extends BaseController { |
||||
|
|
||||
|
@Resource |
||||
|
MenuService menuService; |
||||
|
|
||||
|
@Resource |
||||
|
MenuDishService menuDishService; |
||||
|
|
||||
|
@Resource |
||||
|
MenuReportService menuReportService; |
||||
|
|
||||
|
@ResponseBody |
||||
|
@RequestMapping(method = RequestMethod.GET) |
||||
|
public JSONObject analysis(@RequestParam Long id, @RequestParam(required = false) Long day, @RequestParam(required = false) String crow) { |
||||
|
Menu menu = checkAndGetMenu(id); |
||||
|
day = checkAndGetDay(day, menu.getDay()); |
||||
|
crow = checkAndGetCrow(crow, menu.getCrows()); |
||||
|
List<MenuDish> dishes = menuDishService.query(id, menu.getVender(), day); |
||||
|
return menuReportService.assess(menu, day, crow, dishes); |
||||
|
} |
||||
|
|
||||
|
@ResponseBody |
||||
|
@RequestMapping(value = "types", method = RequestMethod.GET) |
||||
|
public JSONObject types(@RequestParam Long id) { |
||||
|
Menu menu = checkAndGetMenu(id); |
||||
|
List<MenuDish> dishes = menuDishService.query(id, menu.getVender()); |
||||
|
return menuReportService.types(menu, dishes); |
||||
|
} |
||||
|
|
||||
|
@ResponseBody |
||||
|
@RequestMapping(value = "energy", method = RequestMethod.GET) |
||||
|
public JSONObject energy(@RequestParam Long id, @RequestParam(required = false) Long day, @RequestParam(required = false) String crow) { |
||||
|
Menu menu = checkAndGetMenu(id); |
||||
|
day = checkAndGetDay(day, menu.getDay()); |
||||
|
crow = checkAndGetCrow(crow, menu.getCrows()); |
||||
|
List<MenuDish> dishes = menuDishService.query(id, menu.getVender(), day); |
||||
|
return menuReportService.energy(day, crow, dishes); |
||||
|
} |
||||
|
|
||||
|
private Menu checkAndGetMenu(Long id) { |
||||
|
Menu menu = isAdmin() ? menuService.get(id) : menuService.get(id, getVender()); |
||||
|
Assert.notNull(menu, "[参数错误]食谱不存在!"); |
||||
|
return menu; |
||||
|
} |
||||
|
|
||||
|
private Long checkAndGetDay(Long day, Long defaultDay) { |
||||
|
return (day == null || day < 1 || day > defaultDay) ? (long) LocalDate.now().getDayOfWeek().getValue() : day; |
||||
|
} |
||||
|
|
||||
|
private String checkAndGetCrow(String crow, List<String> allCrow) { |
||||
|
return StringUtils.isBlank(crow) || !allCrow.contains(crow) ? allCrow.get(0) : crow; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
package com.mathvision.diet.domain; |
||||
|
|
||||
|
public class Session { |
||||
|
private static final ThreadLocal<UserDO> SESSION = new ThreadLocal<>(); |
||||
|
|
||||
|
public static UserDO get() { |
||||
|
return SESSION.get(); |
||||
|
} |
||||
|
|
||||
|
public static void set(UserDO userDO) { |
||||
|
SESSION.set(userDO); |
||||
|
} |
||||
|
|
||||
|
public static void clear() { |
||||
|
SESSION.remove(); |
||||
|
} |
||||
|
} |
||||
@ -1 +1,354 @@ |
|||||
|
<h1>1. 食谱分析</h1> |
||||
|
<blockquote> |
||||
|
<p>GET /api/menu/analysis</p> |
||||
|
</blockquote> |
||||
|
<h3>输入:</h3> |
||||
|
<pre><code class="text">id=1 // 食谱ID, 必填 |
||||
|
day=3 // 那一天, 默认当天 |
||||
|
crow=xxx //人群,默认第一个人群 |
||||
|
</code></pre> |
||||
|
<h3>输出:</h3> |
||||
|
<pre><code class="json">{ |
||||
|
"body": { |
||||
|
"day": 5, |
||||
|
"crow": "10", |
||||
|
"meals": [ |
||||
|
"早餐" |
||||
|
], |
||||
|
"types": { |
||||
|
"蛋类": 5, |
||||
|
"鱼虾类": 2, |
||||
|
"调味品": 1 |
||||
|
}, |
||||
|
"ingredient": [ |
||||
|
{ |
||||
|
"nutrition": "膳食纤维/g", |
||||
|
"virtual": 0, |
||||
|
"standard": "1~2", |
||||
|
"ul": "-", |
||||
|
"overload": -1, |
||||
|
"conclusion": "不足" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "钙/mg", |
||||
|
"virtual": 2, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "维生素B1/mg", |
||||
|
"virtual": 1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "碳水化合物/g", |
||||
|
"virtual": 0.1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "蛋白质/g", |
||||
|
"virtual": 0.1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "维生素B2/mg", |
||||
|
"virtual": 2, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "脂肪/g", |
||||
|
"virtual": 0.0, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "铁/mg", |
||||
|
"virtual": 0.1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "维生素A/μgRAE", |
||||
|
"virtual": 4, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "能量kcal/kcal", |
||||
|
"virtual": 0.79, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"code": 200, |
||||
|
"desc": "成功", |
||||
|
"success": true |
||||
|
} |
||||
|
</code></pre> |
||||
|
<h1>2. 食谱分析</h1> |
||||
|
<blockquote> |
||||
|
<p>GET /api/menu/analysis/energy</p> |
||||
|
</blockquote> |
||||
|
<h3>输入:</h3> |
||||
|
<pre><code class="text">id=1 // 食谱ID, 必填 |
||||
|
day=3 // 那一天, 默认当天 |
||||
|
crow=xxx //人群,默认第一个人群 |
||||
|
</code></pre> |
||||
|
<h3>输出:</h3> |
||||
|
<pre><code class="json">{ |
||||
|
"body": { |
||||
|
"day": 5, |
||||
|
"crow": "10", |
||||
|
"meals": [ |
||||
|
"早餐" |
||||
|
], |
||||
|
"energy": [ |
||||
|
{ |
||||
|
"name": "蛋白质/总能量", |
||||
|
"standard": "10~20", |
||||
|
"value": 10.0, |
||||
|
"conclusion": "合适" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "脂肪/总能量", |
||||
|
"standard": "20~30", |
||||
|
"value": 0.0, |
||||
|
"conclusion": "略低" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "碳水化合物/总能量", |
||||
|
"standard": "50~60", |
||||
|
"value": 10.0, |
||||
|
"conclusion": "略低" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"code": 200, |
||||
|
"desc": "成功", |
||||
|
"success": true |
||||
|
} |
||||
|
</code></pre> |
||||
|
<h1>3. 食谱分析</h1> |
||||
|
<blockquote> |
||||
|
<p>GET /api/menu/analysis/types</p> |
||||
|
</blockquote> |
||||
|
<h3>输入:</h3> |
||||
|
<pre><code class="text">id=1 // 食谱ID, 必填 |
||||
|
crow=xxx //人群,默认第一个人群 |
||||
|
</code></pre> |
||||
|
<h3>输出:</h3> |
||||
|
<pre><code class="json">{ |
||||
|
"body": { |
||||
|
"dayRule": [ |
||||
|
[ |
||||
|
{ |
||||
|
"day": 1, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 1, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 1, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 2, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 2, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 2, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 3, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 3, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 3, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 4, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 4, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 4, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 5, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 5, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 5, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 6, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 6, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 6, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 7, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 7, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 7, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
] |
||||
|
], |
||||
|
"weekRule": [ |
||||
|
{ |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 35, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 14, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 7, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"code": 200, |
||||
|
"desc": "成功", |
||||
|
"success": true |
||||
|
} |
||||
|
</code></pre> |
||||
|
|
||||
|
|||||
@ -0,0 +1,366 @@ |
|||||
|
# 1. 食谱分析 |
||||
|
|
||||
|
|
||||
|
> GET /api/menu/analysis |
||||
|
|
||||
|
### 输入: |
||||
|
```text |
||||
|
id=1 // 食谱ID, 必填 |
||||
|
day=3 // 那一天, 默认当天 |
||||
|
crow=xxx //人群,默认第一个人群 |
||||
|
``` |
||||
|
|
||||
|
### 输出: |
||||
|
~~~json |
||||
|
{ |
||||
|
"body": { |
||||
|
"day": 5, |
||||
|
"crow": "10", |
||||
|
"meals": [ |
||||
|
"早餐" |
||||
|
], |
||||
|
"types": { |
||||
|
"蛋类": 5, |
||||
|
"鱼虾类": 2, |
||||
|
"调味品": 1 |
||||
|
}, |
||||
|
"ingredient": [ |
||||
|
{ |
||||
|
"nutrition": "膳食纤维/g", |
||||
|
"virtual": 0, |
||||
|
"standard": "1~2", |
||||
|
"ul": "-", |
||||
|
"overload": -1, |
||||
|
"conclusion": "不足" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "钙/mg", |
||||
|
"virtual": 2, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "维生素B1/mg", |
||||
|
"virtual": 1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "碳水化合物/g", |
||||
|
"virtual": 0.1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "蛋白质/g", |
||||
|
"virtual": 0.1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "维生素B2/mg", |
||||
|
"virtual": 2, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "脂肪/g", |
||||
|
"virtual": 0.0, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "铁/mg", |
||||
|
"virtual": 0.1, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "维生素A/μgRAE", |
||||
|
"virtual": 4, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
}, |
||||
|
{ |
||||
|
"nutrition": "能量kcal/kcal", |
||||
|
"virtual": 0.79, |
||||
|
"standard": "-", |
||||
|
"ul": "-", |
||||
|
"overload": "-", |
||||
|
"conclusion": "-" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"code": 200, |
||||
|
"desc": "成功", |
||||
|
"success": true |
||||
|
} |
||||
|
~~~ |
||||
|
|
||||
|
|
||||
|
# 2. 食谱分析 |
||||
|
|
||||
|
> GET /api/menu/analysis/energy |
||||
|
|
||||
|
### 输入: |
||||
|
```text |
||||
|
id=1 // 食谱ID, 必填 |
||||
|
day=3 // 那一天, 默认当天 |
||||
|
crow=xxx //人群,默认第一个人群 |
||||
|
``` |
||||
|
|
||||
|
### 输出: |
||||
|
~~~json |
||||
|
{ |
||||
|
"body": { |
||||
|
"day": 5, |
||||
|
"crow": "10", |
||||
|
"meals": [ |
||||
|
"早餐" |
||||
|
], |
||||
|
"energy": [ |
||||
|
{ |
||||
|
"name": "蛋白质/总能量", |
||||
|
"standard": "10~20", |
||||
|
"value": 10.0, |
||||
|
"conclusion": "合适" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "脂肪/总能量", |
||||
|
"standard": "20~30", |
||||
|
"value": 0.0, |
||||
|
"conclusion": "略低" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "碳水化合物/总能量", |
||||
|
"standard": "50~60", |
||||
|
"value": 10.0, |
||||
|
"conclusion": "略低" |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"code": 200, |
||||
|
"desc": "成功", |
||||
|
"success": true |
||||
|
} |
||||
|
~~~ |
||||
|
|
||||
|
# 3. 食谱分析 |
||||
|
|
||||
|
> GET /api/menu/analysis/types |
||||
|
|
||||
|
### 输入: |
||||
|
```text |
||||
|
id=1 // 食谱ID, 必填 |
||||
|
crow=xxx //人群,默认第一个人群 |
||||
|
``` |
||||
|
|
||||
|
### 输出: |
||||
|
~~~json |
||||
|
{ |
||||
|
"body": { |
||||
|
"dayRule": [ |
||||
|
[ |
||||
|
{ |
||||
|
"day": 1, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 1, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 1, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 2, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 2, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 2, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 3, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 3, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 3, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 4, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 4, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 4, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 5, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 5, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 5, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 6, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 6, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 6, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
], |
||||
|
[ |
||||
|
{ |
||||
|
"day": 7, |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 2, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 7, |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 5, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"day": 7, |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 1, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
] |
||||
|
], |
||||
|
"weekRule": [ |
||||
|
{ |
||||
|
"name": "蛋类", |
||||
|
"standard": 0, |
||||
|
"supplied": 35, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "鱼虾类", |
||||
|
"standard": 0, |
||||
|
"supplied": 14, |
||||
|
"lack": 0 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "调味品", |
||||
|
"standard": 0, |
||||
|
"supplied": 7, |
||||
|
"lack": 0 |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"code": 200, |
||||
|
"desc": "成功", |
||||
|
"success": true |
||||
|
} |
||||
|
~~~ |
||||
Loading…
Reference in new issue