caoyiwen 2 years ago
parent
commit
0284b25d17
  1. 7
      diet-core/src/main/java/com/mathvision/diet/service/DishService.java
  2. 185
      diet-core/src/main/java/com/mathvision/diet/service/MenuDishService.java
  3. 213
      diet-core/src/main/java/com/mathvision/diet/service/MenuReportService.java
  4. 10
      diet-web/src/main/java/com/mathvision/diet/aspect/GlobalRequestAspect.java
  5. 2
      diet-web/src/main/java/com/mathvision/diet/aspect/GlobalResponseAspect.java
  6. 2
      diet-web/src/main/java/com/mathvision/diet/constant/Constant.java
  7. 20
      diet-web/src/main/java/com/mathvision/diet/controller/BaseController.java
  8. 11
      diet-web/src/main/java/com/mathvision/diet/controller/MenuDishController.java
  9. 75
      diet-web/src/main/java/com/mathvision/diet/controller/MenuReportController.java
  10. 17
      diet-web/src/main/java/com/mathvision/diet/domain/Session.java
  11. 11
      diet-web/src/main/resources/application.yml
  12. 5
      diet-web/src/main/resources/static/change.html
  13. 353
      diet-web/src/main/resources/static/menu/dish.html
  14. 353
      diet-web/src/main/resources/static/menu/report.html
  15. 5
      doc/change.md
  16. 367
      doc/menu/dish.md
  17. 366
      doc/menu/report.md

7
diet-core/src/main/java/com/mathvision/diet/service/DishService.java

@ -10,6 +10,7 @@ import com.mathvision.diet.entity.Ingredient;
import com.mathvision.diet.repository.DishRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.data.domain.Page;
@ -129,9 +130,13 @@ public class DishService {
}
}
if (dishes.isEmpty()) {
return Lists.newArrayList();
}
Map<String, Ingredient> ingredientMap = ingredientService.getFullByKeys(dishes.stream().filter(x -> CollectionUtils.isNotEmpty(x.getIngredient())).flatMap(x -> x.getIngredient().stream().map(DishItemDTO::getKey)).collect(Collectors.toSet())).stream().collect(Collectors.toMap(Ingredient::getKey, v -> v));
return dishes.parallelStream().filter(dish -> CollectionUtils.isNotEmpty(dish.getIngredient())).map(dish -> {
List<String> ingredients = dish.getIngredient().stream().filter(DishItemDTO::getIsMain).map(DishItemDTO::getKey).filter(ingredientMap::containsKey).map(x -> ingredientMap.get(x).getName()).collect(Collectors.toList());
List<String> ingredients = dish.getIngredient().stream().filter(item -> BooleanUtils.isTrue(item.getIsMain())).map(DishItemDTO::getKey).filter(ingredientMap::containsKey).map(x -> ingredientMap.get(x).getName()).collect(Collectors.toList());
List<ComponentAnalysisDO> component = dish.getIngredient().stream().filter(x -> ingredientMap.containsKey(x.getKey())).flatMap(x -> {
Ingredient ingredient = ingredientMap.get(x.getKey());
return ingredient.getNutrient().entrySet().stream().map(n -> Pair.of(n.getKey(), n.getValue().multiply(x.getValue()).divide(new BigDecimal(100), RoundingMode.HALF_UP)));

185
diet-core/src/main/java/com/mathvision/diet/service/MenuDishService.java

@ -31,12 +31,6 @@ import java.util.stream.IntStream;
@Service
public class MenuDishService {
@Resource
EnumService enumService;
@Resource
NutritionService nutritionService;
@Resource
MenuDishRepository menuDishRepository;
@ -81,185 +75,6 @@ public class MenuDishService {
return menuDishRepository.findByMenuAndVenderAndDay(menuId, vender, day);
}
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;
}
public void export(Menu menu, OutputStream outputStream) {
Map<String, Map<Long, List<MenuDish>>> menuDishes = menuDishRepository.findByMenu(menu.getId()).stream().collect(Collectors.groupingBy(MenuDish::getMeal, Collectors.groupingBy(MenuDish::getDay)));
List<String> allMeals = new ArrayList<>(menuDishes.keySet()).stream().sorted(Comparator.comparing(MealType::toType)).collect(Collectors.toList());

213
diet-core/src/main/java/com/mathvision/diet/service/MenuReportService.java

@ -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;
}
}

10
diet-web/src/main/java/com/mathvision/diet/aspect/GlobalRequestAspect.java

@ -3,6 +3,7 @@ package com.mathvision.diet.aspect;
import com.alibaba.fastjson2.JSON;
import com.mathvision.diet.constant.Constant;
import com.mathvision.diet.domain.Result;
import com.mathvision.diet.domain.Session;
import com.mathvision.diet.domain.UserDO;
import com.mathvision.diet.domian.AuthType;
import com.mathvision.diet.entity.RoleItem;
@ -56,21 +57,16 @@ public class GlobalRequestAspect implements HandlerInterceptor, WebMvcConfigurer
}
private boolean verifySession(HttpServletRequest request, HttpServletResponse response) {
UserDO userDO = (UserDO)request.getSession().getAttribute(Constant.SESSION_USER_KEY);
if (userDO == null) {
String token = request.getHeader(Constant.TOKEN_HEADER_KEY);
if (StringUtils.isBlank(token)) {
throw new DietException(Result.NOT_LOGIN);
}
userDO = JWTUtils.verify(token);
UserDO userDO = JWTUtils.verify(token);
if (userDO == null) {
throw new DietException(Result.NOT_LOGIN);
} else {
userDO.setRoleItems(enumService.getRoleItems(userDO.getRoleItems().stream().map(RoleItem::getId).collect(Collectors.toList())));
request.getSession().setMaxInactiveInterval(Constant.TOKEN_EXPIRE_SECOND);
request.getSession().setAttribute(Constant.SESSION_USER_KEY, userDO);
request.getSession().setAttribute(Constant.SESSION_USER_TYPE, userDO.isAdmin());
}
Session.set(userDO);
}
if (!hasRole(userDO.isAdmin() ? AuthType.SERVER : AuthType.CLIENT, userDO.getRoleItems(), request.getRequestURI().toLowerCase(), request.getMethod().toLowerCase())) {
throw new DietException(Result.NOT_PRIVILEGED);

2
diet-web/src/main/java/com/mathvision/diet/aspect/GlobalResponseAspect.java

@ -6,6 +6,7 @@ import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.mathvision.diet.constant.Constant;
import com.mathvision.diet.domain.Result;
import com.mathvision.diet.domain.ResultCode;
import com.mathvision.diet.domain.Session;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
@ -48,6 +49,7 @@ public class GlobalResponseAspect implements ResponseBodyAdvice<Object> {
if (result instanceof Result) {
return result;
}
Session.clear();
return new Result(ResultCode.success, result);
}
}

2
diet-web/src/main/java/com/mathvision/diet/constant/Constant.java

@ -8,8 +8,6 @@ import java.util.List;
public class Constant {
public static final int TOKEN_EXPIRE_SECOND = 7200;
public static final String TOKEN_HEADER_KEY = "Authorization";
public static final String SESSION_USER_KEY = "user";
public static final String SESSION_USER_TYPE = "type";
public static final List<MediaType> SUPPORTED_MEDIA_TYPES = Lists.newArrayList(
MediaType.APPLICATION_JSON,

20
diet-web/src/main/java/com/mathvision/diet/controller/BaseController.java

@ -2,6 +2,7 @@ package com.mathvision.diet.controller;
import com.mathvision.diet.constant.Constant;
import com.mathvision.diet.domain.Result;
import com.mathvision.diet.domain.Session;
import com.mathvision.diet.domain.UserDO;
import com.mathvision.diet.exception.DietException;
import com.mathvision.diet.utils.JWTUtils;
@ -13,7 +14,6 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.Objects;
@ -29,28 +29,14 @@ public class BaseController {
}
public UserDO getSession() {
return (UserDO)getRequest().getSession().getAttribute(Constant.SESSION_USER_KEY);
return Session.get();
}
public void setSession(UserDO userDO) {
HttpSession httpSession = getRequest().getSession();
if (httpSession == null) {
return;
}
httpSession.setMaxInactiveInterval(Constant.TOKEN_EXPIRE_SECOND);
httpSession.setAttribute(Constant.SESSION_USER_KEY, userDO);
httpSession.setAttribute(Constant.SESSION_USER_TYPE, userDO.isAdmin());
getResponse().setHeader(Constant.TOKEN_HEADER_KEY, JWTUtils.getToken(userDO));
}
public void delSession() {
HttpSession httpSession = getRequest().getSession();
if (httpSession == null) {
return;
}
httpSession.removeAttribute(Constant.SESSION_USER_KEY);
httpSession.removeAttribute(Constant.SESSION_USER_TYPE);
getResponse().setHeader(Constant.TOKEN_HEADER_KEY, null);
}
@ -69,7 +55,7 @@ public class BaseController {
}
public boolean isAdmin() {
return (Boolean) getRequest().getSession().getAttribute(Constant.SESSION_USER_TYPE);
return getSession().isAdmin();
}
public Long auth(Long venderId) {

11
diet-web/src/main/java/com/mathvision/diet/controller/MenuDishController.java

@ -46,6 +46,10 @@ public class MenuDishController extends BaseController {
@Resource
private IngredientService ingredientService;
// TODO
@Resource
MenuReportService menuReportService;
@ResponseBody
@RequestMapping(method = RequestMethod.PUT)
public Long add(@RequestParam Long menuId, @RequestParam Long dishId, @RequestParam Integer day, @RequestParam String meal, @RequestParam(required = false) String mark, @RequestParam String ingredient) {
@ -101,7 +105,6 @@ public class MenuDishController extends BaseController {
}
}
@ResponseBody
@RequestMapping(value = "export", method = RequestMethod.GET)
public void export(@RequestParam Long id) throws IOException {
@ -124,7 +127,7 @@ public class MenuDishController extends BaseController {
day = (day == null || day < 1 || day > menu.getDay()) ? (long) LocalDate.now().getDayOfWeek().getValue() : day;
crow = StringUtils.isBlank(crow) || !menu.getCrows().contains(crow) ? menu.getCrows().get(0) : crow;
List<MenuDish> dishes = menuDishService.query(id, menu.getVender(), day);
return menuDishService.assess(menu, day, crow, dishes);
return menuReportService.assess(menu, day, crow, dishes);
}
@ResponseBody
@ -133,7 +136,7 @@ public class MenuDishController extends BaseController {
Menu menu = isAdmin() ? menuService.get(id) : menuService.get(id, getVender());
Assert.notNull(menu, "[参数错误]食谱不存在!");
List<MenuDish> dishes = menuDishService.query(id, menu.getVender());
return menuDishService.types(menu, dishes);
return menuReportService.types(menu, dishes);
}
@ResponseBody
@ -144,7 +147,7 @@ public class MenuDishController extends BaseController {
day = (day == null || day < 1 || day > menu.getDay()) ? (long) LocalDate.now().getDayOfWeek().getValue() : day;
crow = StringUtils.isBlank(crow) || !menu.getCrows().contains(crow) ? menu.getCrows().get(0) : crow;
List<MenuDish> dishes = menuDishService.query(id, menu.getVender(), day);
return menuDishService.energy(day, crow, dishes);
return menuReportService.energy(day, crow, dishes);
}
@ResponseBody

75
diet-web/src/main/java/com/mathvision/diet/controller/MenuReportController.java

@ -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;
}
}

17
diet-web/src/main/java/com/mathvision/diet/domain/Session.java

@ -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();
}
}

11
diet-web/src/main/resources/application.yml

@ -10,11 +10,16 @@ spring:
database-platform: org.hibernate.dialect.MySQLDialect
open-in-view: false
session:
invalid: 600
server:
port: 9527
maxHttpHeaderSize: 20KB
tomcat:
maxConnections: 2000
maxHttpFormPostSize: 2MB
maxSwallowSize: 2MB
session:
invalid: 600
logging:
config: classpath:logback-spring.xml

5
diet-web/src/main/resources/static/change.html

@ -27,4 +27,9 @@
<li>菜品接口: 更改食材列表数据结构,增加是否主料(boolean)。</li>
<li>枚举接口: 增加餐次枚举和食谱状态枚举</li>
</ul>
<h3>10.08</h3>
<ul>
<li>食谱接口: 将食谱分析接口从食谱菜品拿出来, 放到了食谱分析章节, 请求路径中去除了dish路径, 涉及3个接口;</li>
<li>鉴权接口: 去除了session方式;</li>
</ul>

353
diet-web/src/main/resources/static/menu/dish.html

@ -226,357 +226,4 @@ menuDishId=1 // ʳ
&quot;success&quot;: true
}
</code></pre>
<h1>8. 食谱分析</h1>
<blockquote>
<p>GET /api/menu/dish/analysis</p>
</blockquote>
<h3>输入:</h3>
<pre><code class="text">id=1 // 食谱ID, 必填
day=3 // 那一天, 默认当天
crow=xxx //人群,默认第一个人群
</code></pre>
<h3>输出:</h3>
<pre><code class="json">{
&quot;body&quot;: {
&quot;day&quot;: 5,
&quot;crow&quot;: &quot;10&quot;,
&quot;meals&quot;: [
&quot;早餐&quot;
],
&quot;types&quot;: {
&quot;蛋类&quot;: 5,
&quot;鱼虾类&quot;: 2,
&quot;调味品&quot;: 1
},
&quot;ingredient&quot;: [
{
&quot;nutrition&quot;: &quot;膳食纤维/g&quot;,
&quot;virtual&quot;: 0,
&quot;standard&quot;: &quot;1~2&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: -1,
&quot;conclusion&quot;: &quot;不足&quot;
},
{
&quot;nutrition&quot;: &quot;钙/mg&quot;,
&quot;virtual&quot;: 2,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;维生素B1/mg&quot;,
&quot;virtual&quot;: 1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;碳水化合物/g&quot;,
&quot;virtual&quot;: 0.1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;蛋白质/g&quot;,
&quot;virtual&quot;: 0.1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;维生素B2/mg&quot;,
&quot;virtual&quot;: 2,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;脂肪/g&quot;,
&quot;virtual&quot;: 0.0,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;铁/mg&quot;,
&quot;virtual&quot;: 0.1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;维生素A/μgRAE&quot;,
&quot;virtual&quot;: 4,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;能量kcal/kcal&quot;,
&quot;virtual&quot;: 0.79,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
}
]
},
&quot;code&quot;: 200,
&quot;desc&quot;: &quot;成功&quot;,
&quot;success&quot;: true
}
</code></pre>
<h1>9. 食谱分析</h1>
<blockquote>
<p>GET /api/menu/dish/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">{
&quot;body&quot;: {
&quot;day&quot;: 5,
&quot;crow&quot;: &quot;10&quot;,
&quot;meals&quot;: [
&quot;早餐&quot;
],
&quot;energy&quot;: [
{
&quot;name&quot;: &quot;蛋白质/总能量&quot;,
&quot;standard&quot;: &quot;10~20&quot;,
&quot;value&quot;: 10.0,
&quot;conclusion&quot;: &quot;合适&quot;
},
{
&quot;name&quot;: &quot;脂肪/总能量&quot;,
&quot;standard&quot;: &quot;20~30&quot;,
&quot;value&quot;: 0.0,
&quot;conclusion&quot;: &quot;略低&quot;
},
{
&quot;name&quot;: &quot;碳水化合物/总能量&quot;,
&quot;standard&quot;: &quot;50~60&quot;,
&quot;value&quot;: 10.0,
&quot;conclusion&quot;: &quot;略低&quot;
}
]
},
&quot;code&quot;: 200,
&quot;desc&quot;: &quot;成功&quot;,
&quot;success&quot;: true
}
</code></pre>
<h1>10. 食谱分析</h1>
<blockquote>
<p>GET /api/menu/dish/analysis/types</p>
</blockquote>
<h3>输入:</h3>
<pre><code class="text">id=1 // 食谱ID, 必填
crow=xxx //人群,默认第一个人群
</code></pre>
<h3>输出:</h3>
<pre><code class="json">{
&quot;body&quot;: {
&quot;dayRule&quot;: [
[
{
&quot;day&quot;: 1,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 1,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 1,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 2,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 2,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 2,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 3,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 3,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 3,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 4,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 4,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 4,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 5,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 5,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 5,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 6,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 6,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 6,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 7,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 7,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 7,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
]
],
&quot;weekRule&quot;: [
{
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 35,
&quot;lack&quot;: 0
},
{
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 14,
&quot;lack&quot;: 0
},
{
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 7,
&quot;lack&quot;: 0
}
]
},
&quot;code&quot;: 200,
&quot;desc&quot;: &quot;成功&quot;,
&quot;success&quot;: true
}
</code></pre>

353
diet-web/src/main/resources/static/menu/report.html

@ -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">{
&quot;body&quot;: {
&quot;day&quot;: 5,
&quot;crow&quot;: &quot;10&quot;,
&quot;meals&quot;: [
&quot;早餐&quot;
],
&quot;types&quot;: {
&quot;蛋类&quot;: 5,
&quot;鱼虾类&quot;: 2,
&quot;调味品&quot;: 1
},
&quot;ingredient&quot;: [
{
&quot;nutrition&quot;: &quot;膳食纤维/g&quot;,
&quot;virtual&quot;: 0,
&quot;standard&quot;: &quot;1~2&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: -1,
&quot;conclusion&quot;: &quot;不足&quot;
},
{
&quot;nutrition&quot;: &quot;钙/mg&quot;,
&quot;virtual&quot;: 2,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;维生素B1/mg&quot;,
&quot;virtual&quot;: 1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;碳水化合物/g&quot;,
&quot;virtual&quot;: 0.1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;蛋白质/g&quot;,
&quot;virtual&quot;: 0.1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;维生素B2/mg&quot;,
&quot;virtual&quot;: 2,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;脂肪/g&quot;,
&quot;virtual&quot;: 0.0,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;铁/mg&quot;,
&quot;virtual&quot;: 0.1,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;维生素A/μgRAE&quot;,
&quot;virtual&quot;: 4,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
},
{
&quot;nutrition&quot;: &quot;能量kcal/kcal&quot;,
&quot;virtual&quot;: 0.79,
&quot;standard&quot;: &quot;-&quot;,
&quot;ul&quot;: &quot;-&quot;,
&quot;overload&quot;: &quot;-&quot;,
&quot;conclusion&quot;: &quot;-&quot;
}
]
},
&quot;code&quot;: 200,
&quot;desc&quot;: &quot;成功&quot;,
&quot;success&quot;: 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">{
&quot;body&quot;: {
&quot;day&quot;: 5,
&quot;crow&quot;: &quot;10&quot;,
&quot;meals&quot;: [
&quot;早餐&quot;
],
&quot;energy&quot;: [
{
&quot;name&quot;: &quot;蛋白质/总能量&quot;,
&quot;standard&quot;: &quot;10~20&quot;,
&quot;value&quot;: 10.0,
&quot;conclusion&quot;: &quot;合适&quot;
},
{
&quot;name&quot;: &quot;脂肪/总能量&quot;,
&quot;standard&quot;: &quot;20~30&quot;,
&quot;value&quot;: 0.0,
&quot;conclusion&quot;: &quot;略低&quot;
},
{
&quot;name&quot;: &quot;碳水化合物/总能量&quot;,
&quot;standard&quot;: &quot;50~60&quot;,
&quot;value&quot;: 10.0,
&quot;conclusion&quot;: &quot;略低&quot;
}
]
},
&quot;code&quot;: 200,
&quot;desc&quot;: &quot;成功&quot;,
&quot;success&quot;: 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">{
&quot;body&quot;: {
&quot;dayRule&quot;: [
[
{
&quot;day&quot;: 1,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 1,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 1,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 2,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 2,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 2,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 3,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 3,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 3,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 4,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 4,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 4,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 5,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 5,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 5,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 6,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 6,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 6,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
],
[
{
&quot;day&quot;: 7,
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 2,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 7,
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 5,
&quot;lack&quot;: 0
},
{
&quot;day&quot;: 7,
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 1,
&quot;lack&quot;: 0
}
]
],
&quot;weekRule&quot;: [
{
&quot;name&quot;: &quot;蛋类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 35,
&quot;lack&quot;: 0
},
{
&quot;name&quot;: &quot;鱼虾类&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 14,
&quot;lack&quot;: 0
},
{
&quot;name&quot;: &quot;调味品&quot;,
&quot;standard&quot;: 0,
&quot;supplied&quot;: 7,
&quot;lack&quot;: 0
}
]
},
&quot;code&quot;: 200,
&quot;desc&quot;: &quot;成功&quot;,
&quot;success&quot;: true
}
</code></pre>

5
doc/change.md

@ -25,3 +25,8 @@
### 9.23
* 菜品接口: 更改食材列表数据结构,增加是否主料(boolean)。
* 枚举接口: 增加餐次枚举和食谱状态枚举
### 10.08
* 食谱接口: 将食谱分析接口从食谱菜品拿出来, 放到了食谱分析章节, 请求路径中去除了dish路径, 涉及3个接口;
* 鉴权接口: 去除了session方式;

367
doc/menu/dish.md

@ -256,370 +256,3 @@ id=1 // 食谱ID
"success": true
}
~~~
# 8. 食谱分析
> GET /api/menu/dish/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
}
~~~
# 9. 食谱分析
> GET /api/menu/dish/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
}
~~~
# 10. 食谱分析
> GET /api/menu/dish/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
}
~~~

366
doc/menu/report.md

@ -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…
Cancel
Save