Browse Source

需求更新2025.3.10

master
fangyang2021 1 month ago
parent
commit
351861f80c
  1. 2
      diet-core/src/main/java/com/mathvision/diet/domain/DishLabelDO.java
  2. 32
      diet-core/src/main/java/com/mathvision/diet/service/DishService.java
  3. 92
      diet-core/src/main/java/com/mathvision/diet/service/MenuReportService.java
  4. 62
      diet-dao/src/main/java/com/mathvision/diet/domian/NutritionSortEnum.java
  5. 33
      diet-web/src/main/java/com/mathvision/diet/controller/DishController.java
  6. 5
      doc/change.md
  7. 25
      doc/dish.md
  8. 6
      doc/menu/report.md

2
diet-core/src/main/java/com/mathvision/diet/domain/DishLabelDO.java

@ -15,4 +15,6 @@ public class DishLabelDO {
String name;
List<ComponentAnalysisDO> component;
List<String> ingredients;
//update 新增三低标识
List<String> label;
}

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

@ -109,7 +109,7 @@ public class DishService {
log.info("[DishService] add dishes count = " + dishes.size() + ", operator = " + operator);
}
public void delete(List<Long> ids, Long venderId,String operator) {
public void delete(List<Long> ids, Long venderId, String operator) {
if (venderId > 0) {
dishRepository.deleteByIdInAndVender(ids, venderId);
} else {
@ -118,7 +118,7 @@ public class DishService {
log.info("[DishService] delete ids = " + ids + ", operator = " + operator);
}
public void delete(Long venderId,String operator) {
public void delete(Long venderId, String operator) {
dishRepository.deleteByVender(venderId);
log.info("[DishService] delete venderId = " + venderId + ", operator = " + operator);
}
@ -221,7 +221,7 @@ public class DishService {
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());
Map<String, BigDecimal> _items = dish.getIngredient().stream().filter(x -> ingredientMap.containsKey(x.getKey())).flatMap(x ->
ingredientMap.get(x.getKey()).getNutrient().entrySet().stream().map(n -> Pair.of(n.getKey(), n.getValue().multiply(x.getValue()).divide(new BigDecimal(100), RoundingMode.HALF_UP)))
ingredientMap.get(x.getKey()).getNutrient().entrySet().stream().map(n -> Pair.of(n.getKey(), n.getValue().multiply(x.getValue()).divide(new BigDecimal(100), RoundingMode.HALF_UP)))
).filter(x -> x.getValue() != null && x.getValue().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toMap(Pair::getKey, Pair::getValue, BigDecimal::add));
_items.put("sugar", sugar(dish, ingredientMap));
MUST_DISPLAY_ITEM.forEach(x -> {
@ -232,13 +232,17 @@ public class DishService {
Map<String, BigDecimal> items = _items.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> {
switch (v.getKey()) {
case "protein" :
case "fat" :
case "carbs" :
case "sugar" : return v.getValue().compareTo(new BigDecimal("0.5")) > 0 ? v.getValue() : BigDecimal.ZERO;
case "energy" : return v.getValue().compareTo(new BigDecimal("4")) > 0 ? v.getValue() : BigDecimal.ZERO;
case "sodium" : return v.getValue().compareTo(new BigDecimal("5")) > 0 ? v.getValue() : BigDecimal.ZERO;
default: return v.getValue();
case "protein":
case "fat":
case "carbs":
case "sugar":
return v.getValue().compareTo(new BigDecimal("0.5")) > 0 ? v.getValue() : BigDecimal.ZERO;
case "energy":
return v.getValue().compareTo(new BigDecimal("4")) > 0 ? v.getValue() : BigDecimal.ZERO;
case "sodium":
return v.getValue().compareTo(new BigDecimal("5")) > 0 ? v.getValue() : BigDecimal.ZERO;
default:
return v.getValue();
}
}));
@ -253,7 +257,10 @@ public class DishService {
}
String name = foodNutrient.getValue();
String value = String.format("%s(%s)", formatValue.format(x.getValue().floatValue()), foodNutrient.getMeasurement() == null ? "-" : foodNutrient.getMeasurement());
//String value = String.format("%s(%s)", formatValue.format(x.getValue().floatValue()), foodNutrient.getMeasurement() == null ? "-" : foodNutrient.getMeasurement());
//update 能量需要单独做去小数点四舍五入
String value = String.format("%s(%s)", "energy".equals(x.getKey()) ? formatInteger.format(x.getValue().floatValue()) : formatValue.format(x.getValue().floatValue()), foodNutrient.getMeasurement() == null ? "-" : foodNutrient.getMeasurement());
String nrv = foodNutrient.getNrv() == null || foodNutrient.getNrv().floatValue() == 0 ? "-" : String.format("%s%%", formatInteger.format(x.getValue().divide(foodNutrient.getNrv(), 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100))));
if (StringUtils.equalsIgnoreCase(x.getKey(), "sodium")) {
float salt = x.getValue().multiply(new BigDecimal("0.0025")).floatValue();
@ -262,8 +269,7 @@ public class DishService {
}
return ComponentAnalysisDO.builder().key(x.getKey()).name(name).nutrition(value).nrv(nrv).build();
}).collect(Collectors.toList());
return DishLabelDO.builder().name(dish.getName()).ingredients(ingredients).component(component).build();
return DishLabelDO.builder().name(dish.getName()).ingredients(ingredients).component(component).label(dish.getLabel()).build();
}).collect(Collectors.toList());
}

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

@ -8,10 +8,7 @@ import com.alibaba.fastjson2.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Range;
import com.mathvision.diet.domian.MealType;
import com.mathvision.diet.domian.MeasurementType;
import com.mathvision.diet.domian.MenuDishItemDTO;
import com.mathvision.diet.domian.RuleItemDTO;
import com.mathvision.diet.domian.*;
import com.mathvision.diet.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
@ -24,10 +21,8 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@ -57,7 +52,12 @@ public class MenuReportService {
.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));
//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));
//update 今日食材种类改成标准的四种分类,去除烹调油、调味品。按照【谷薯杂豆类】【蔬菜水果】【畜禽鱼蛋】【奶豆坚果类】
Map<String, String> categoryType = new HashMap<>();
nutrition.getFoodCategoryDay().forEach(foodCategoryDay -> foodCategoryDay.getCategory().forEach(category -> categoryType.put(category, foodCategoryDay.getName())));
Map<String, Integer> types = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> ingredientMap.containsKey(item.getKey())).map(item -> ingredientMap.get(item.getKey()).getType()).filter(categoryType::containsKey).map(categoryType::get)).collect(Collectors.toMap(categoryName -> categoryName, categoryName -> 1, Integer::sum));
itemStandard.forEach((key, value) -> {
if (!items.containsKey(key)) {
@ -93,7 +93,7 @@ public class MenuReportService {
}
JSONObject content = new JSONObject();
content.put("nutrition", String.format("%s/%s", foodNutrient.getValue(), foodNutrient.getMeasurement()));
content.put("virtual", value);
content.put("virtual", "energy".equals(key) ? value.setScale(0, RoundingMode.HALF_UP) : value);
Map<String, BigDecimal> standard = itemStandard.get(key);
BigDecimal max = standard == null ? null : standard.get("max");
@ -133,9 +133,9 @@ public class MenuReportService {
content.put("overload", "-");
content.put("conclusion", "适量");
} else {
if(value.compareTo(max) > 0) {
if (value.compareTo(max) > 0) {
byMax = true;
} else {
} else {
byMin = true;
}
}
@ -145,7 +145,7 @@ public class MenuReportService {
if (byMin) {
BigDecimal overload = calculatePercentage(value, min);
content.put("overload", overload + "%");
if(overload.abs().compareTo(overflow) > 0) {
if (overload.abs().compareTo(overflow) > 0) {
content.put("conclusion", "不足");
} else {
content.put("conclusion", "适量");
@ -155,8 +155,8 @@ public class MenuReportService {
if (byMax) {
BigDecimal overload = calculatePercentage(value, max);
content.put("overload", overload + "%");
if(overload.compareTo(overflow) > 0) {
if(ul != null && value.compareTo(ul) > 0) {
if (overload.compareTo(overflow) > 0) {
if (ul != null && value.compareTo(ul) > 0) {
content.put("conclusion", "严重超标");
} else {
content.put("conclusion", "过量");
@ -168,7 +168,10 @@ public class MenuReportService {
contents.add(content);
});
result.put("ingredient", contents);
// update 按规则排序
JSONArray sortContents = NutritionSortEnum.sortByRule(contents);
result.put("ingredient", sortContents);
return result;
}
@ -181,6 +184,7 @@ public class MenuReportService {
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));
Map<Pair<Long, String>, BigDecimal> weightDay = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> ingredientMap.containsKey(item.getKey())).map(item -> Triple.of(dish.getDay(), ingredientMap.get(item.getKey()).getType(), item.getValue().getOrDefault(crow, BigDecimal.ZERO)))).collect(Collectors.toMap(x -> Pair.of(x.getLeft(), x.getMiddle()), Triple::getRight, BigDecimal::add));
Map<Pair<Long, String>, String> ingredientDetailsDay = dishes.stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> ingredientMap.containsKey(item.getKey())).map(item -> Triple.of(dish.getDay(), ingredientMap.get(item.getKey()).getType(), ingredientMap.get(item.getKey()).getName()))).collect(Collectors.toMap(x -> Pair.of(x.getLeft(), x.getMiddle()), Triple::getRight,(existing, replacement) -> existing + ", " + replacement));
Map<Long, Object> dayRule = Maps.newHashMap();
dishes.stream().map(MenuDish::getDay).forEach(day -> dayRule.put(day, dayStandard.stream().map(standard -> {
@ -188,6 +192,8 @@ public class MenuReportService {
content.put("day", day);
content.put("name", standard.getName());
content.put("standard", standard.getRange());
String details = ingredientDetailsDay.entrySet().stream().filter(x -> x.getKey().getKey().equals(day) && standard.getCategory().contains(x.getKey().getValue())).map(Map.Entry::getValue).collect(Collectors.joining(","));
content.put("details", details);
if (MeasurementType.quantity.equals(standard.getType())) {
long supplied = typesDay.entrySet().stream().filter(x -> x.getKey().getKey().equals(day) && standard.getCategory().contains(x.getKey().getValue())).map(Map.Entry::getValue).reduce(Integer::sum).orElse(0);
content.put("measurement", standard.getType());
@ -206,6 +212,8 @@ public class MenuReportService {
JSONObject content = new JSONObject();
content.put("name", standard.getName());
content.put("standard", standard.getRange());
String details = ingredientDetailsDay.entrySet().stream().filter(x -> standard.getCategory().contains(x.getKey().getValue())).map(Map.Entry::getValue).collect(Collectors.joining(","));
content.put("details", details);
if (MeasurementType.quantity.equals(standard.getType())) {
long supplied = typesDay.entrySet().stream().filter(x -> standard.getCategory().contains(x.getKey().getValue())).map(Map.Entry::getValue).reduce(Integer::sum).orElse(0);
content.put("measurement", standard.getType());
@ -238,7 +246,7 @@ public class MenuReportService {
}
public JSONObject energy(long day, String crow, List<MenuDish> dishes) {
List<String> allConcerned= Lists.newArrayList("protein", "fat", "carbs");
List<String> allConcerned = Lists.newArrayList("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())))
@ -281,17 +289,17 @@ public class MenuReportService {
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<Long, BigDecimal> salt = dishes.stream().collect(Collectors.groupingBy(MenuDish::getDay)).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
entry -> entry.getValue().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 -> StringUtils.equalsIgnoreCase("sodium", x.getKey()))
.map(x -> x.getValue().multiply(new BigDecimal("0.0025")))
.reduce(BigDecimal :: add)
.orElse(BigDecimal.ZERO)));
.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 -> StringUtils.equalsIgnoreCase("sodium", x.getKey()))
.map(x -> x.getValue().multiply(new BigDecimal("0.0025")))
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO)));
Map<Long, BigDecimal> sugar = dishes.stream().collect(Collectors.groupingBy(MenuDish::getDay)).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
entry -> entry.getValue().stream().flatMap(dish -> dish.getIngredient().stream().filter(item -> item.getValue().containsKey(crow) && item.getValue().get(crow).doubleValue() > 0 && ingredientMap.containsKey(item.getKey()))
.map(x -> Pair.of(ingredientMap.get(x.getKey()), x.getValue()))
.filter(x -> StringUtils.equals("糖类", x.getKey().getType()))
.map(x -> x.getValue().values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO))
.map(x -> Pair.of(ingredientMap.get(x.getKey()), x.getValue()))
.filter(x -> StringUtils.equals("糖类", x.getKey().getType()))
.map(x -> x.getValue().values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO))
).reduce(BigDecimal::add).orElse(BigDecimal.ZERO)));
Map<Long, BigDecimal> oil = dishes.stream().collect(Collectors.groupingBy(MenuDish::getDay)).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
@ -316,7 +324,7 @@ public class MenuReportService {
headers.add(Lists.newArrayList("日均营养分析", "营养素"));
headers.add(Lists.newArrayList("日均营养分析", "实际摄入"));
headers.add(Lists.newArrayList("日均营养分析", "标准范围"));
headers.add(Lists.newArrayList("日均营养分析", "UL值"));
//headers.add(Lists.newArrayList("日均营养分析", "UL值"));
headers.add(Lists.newArrayList("日均营养分析", "溢出范围"));
headers.add(Lists.newArrayList("日均营养分析", "评价"));
@ -325,8 +333,8 @@ public class MenuReportService {
if (ingredient == null) {
return;
}
List<List<Object>> contents = ingredient.stream().map(x -> (JSONObject)x).map(x -> Lists.newArrayList(x.get("nutrition"), x.get("virtual"), x.get("standard"), x.get("ul"), x.get("overload"), x.get("conclusion"))).collect(Collectors.toList());
//List<List<Object>> contents = ingredient.stream().map(x -> (JSONObject) x).map(x -> Lists.newArrayList(x.get("nutrition"), x.get("virtual"), x.get("standard"), x.get("ul"), x.get("overload"), x.get("conclusion"))).collect(Collectors.toList());
List<List<Object>> contents = ingredient.stream().map(x -> (JSONObject) x).map(x -> Lists.newArrayList(x.get("nutrition"), x.get("virtual"), x.get("standard"), x.get("overload"), x.get("conclusion"))).collect(Collectors.toList());
excelWriter.write(contents, EasyExcel.writerSheet("日均营养分析-" + crow).head(headers).build());
});
@ -342,7 +350,7 @@ public class MenuReportService {
return;
}
List<List<Object>> contents = energy.stream().map(x -> (JSONObject)x).map(x -> Lists.newArrayList(x.get("name"), x.get("standard"), x.get("value"), x.get("conclusion"))).collect(Collectors.toList());
List<List<Object>> contents = energy.stream().map(x -> (JSONObject) x).map(x -> Lists.newArrayList(x.get("name"), x.get("standard"), x.get("value"), x.get("conclusion"))).collect(Collectors.toList());
excelWriter.write(contents, EasyExcel.writerSheet("日均能量来源分布-" + crow).head(headers).build());
});
@ -352,6 +360,8 @@ public class MenuReportService {
headers.add(Lists.newArrayList("食材种类统计", "种类名称"));
headers.add(Lists.newArrayList("食材种类统计", "至少需要"));
headers.add(Lists.newArrayList("食材种类统计", "当前含有"));
//update 《食材种类统计》表格增加包含食材明细清单
headers.add(Lists.newArrayList("食材种类统计", "包含食材"));
headers.add(Lists.newArrayList("食材种类统计", "还需"));
JSONObject types = types(menu, crow, menuDishService.query(menu.getId(), menu.getVender()));
@ -361,12 +371,16 @@ public class MenuReportService {
List<List<Object>> contents = Lists.newArrayList();
JSONArray weekRule = types.getJSONArray("weekRule");
//update 《食材种类统计》表格“至少需要”一栏去掉单位“克”,包含食材明细;
if (weekRule != null) {
contents.addAll(weekRule.stream().map(x -> (JSONObject)x).map(x -> Lists.newArrayList("周合计", x.get("name"), MeasurementType.quantity.name().equals(x.getString("measurement")) ? x.get("standard") + "种" : x.get("standard") + "克", x.get("supplied"), x.get("lack"))).collect(Collectors.toList()));
//contents.addAll(weekRule.stream().map(x -> (JSONObject) x).map(x -> Lists.newArrayList("周合计", x.get("name"), MeasurementType.quantity.name().equals(x.getString("measurement")) ? x.get("standard") + "种" : x.get("standard") + "克", x.get("supplied"), x.get("lack"))).collect(Collectors.toList()));
contents.addAll(weekRule.stream().map(x -> (JSONObject) x).map(x -> Lists.newArrayList("周合计", x.get("name"), x.get("standard"), x.get("supplied"), x.get("details"), x.get("lack"))).collect(Collectors.toList()));
}
Map<Long, List<JSONObject>> dayRule = types.getObject("dayRule", new TypeReference<Map<Long, List<JSONObject>>>() {});
Map<Long, List<JSONObject>> dayRule = types.getObject("dayRule", new TypeReference<Map<Long, List<JSONObject>>>() {
});
if (dayRule != null) {
dayRule.forEach((k, v) -> contents.addAll(v.stream().map(x -> Lists.newArrayList("周" + x.getString("day"), x.get("name"), MeasurementType.quantity.name().equals(x.getString("measurement")) ? x.get("standard") + "种" : x.get("standard") + "克", x.get("supplied"), x.get("lack"))).collect(Collectors.toList())));
//dayRule.forEach((k, v) -> contents.addAll(v.stream().map(x -> Lists.newArrayList("周" + x.getString("day"), x.get("name"), MeasurementType.quantity.name().equals(x.getString("measurement")) ? x.get("standard") + "种" : x.get("standard") + "克", x.get("supplied"), x.get("lack"))).collect(Collectors.toList())));
dayRule.forEach((k, v) -> contents.addAll(v.stream().map(x -> Lists.newArrayList("周" + x.getString("day"), x.get("name"), x.get("standard"), x.get("supplied"), x.get("details"), x.get("lack"))).collect(Collectors.toList())));
}
excelWriter.write(contents, EasyExcel.writerSheet("食材种类统计-" + crow).head(headers).build());
});
@ -382,7 +396,7 @@ public class MenuReportService {
return;
}
List<List<Object>> contents = polys.entrySet().stream().filter(kv -> StringUtils.isNumeric(kv.getKey())).map(kv -> ((Map<Object, Object>)kv.getValue()).entrySet().stream().map(x -> Lists.newArrayList(kv.getKey().equals("0") ? "周合计" : "周" + kv.getKey(), x.getKey(), x.getValue())).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList());
List<List<Object>> contents = polys.entrySet().stream().filter(kv -> StringUtils.isNumeric(kv.getKey())).map(kv -> ((Map<Object, Object>) kv.getValue()).entrySet().stream().map(x -> Lists.newArrayList(kv.getKey().equals("0") ? "周合计" : "周" + kv.getKey(), x.getKey(), x.getValue())).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList());
excelWriter.write(contents, EasyExcel.writerSheet("烹饪方式统计-" + crow).head(headers).build());
});
}
@ -405,10 +419,14 @@ public class MenuReportService {
VenderConfig config = venderService.queryConfig(menu.getVender());
BigDecimal scale = menu.getMeals().stream().map(MealType::toType).distinct().map(x -> {
switch (x) {
case breakfast: return config.getBreakfast();
case lunch: return config.getLunch();
case dinner: return config.getDinner();
default: return BigDecimal.ZERO;
case breakfast:
return config.getBreakfast();
case lunch:
return config.getLunch();
case dinner:
return config.getDinner();
default:
return BigDecimal.ZERO;
}
}).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

62
diet-dao/src/main/java/com/mathvision/diet/domian/NutritionSortEnum.java

@ -0,0 +1,62 @@
package com.mathvision.diet.domian;
import java.util.*;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
/**
* @author fy
* @description: 营养素排序枚举
*/
public enum NutritionSortEnum {
ENERGY("能量/kcal"),
PROTEIN("蛋白质/g"),
FAT("脂肪/g"),
CARBOHYDRATE("碳水化合物/g"),
CALCIUM("钙/mg"),
IRON("铁/mg"),
ZINC("锌/mg"),
VITAMIN_A("维生素A/μgRAE"),
VITAMIN_B1("维生素B1/mg"),
VITAMIN_B2("维生素B2/mg"),
VITAMIN_C("维生素C/mg"),
DIETARY_FIBER("膳食纤维/g"),
SODIUM("钠/mg");
private final String label;
private static final Map<String, Integer> nutritionOrder = new HashMap<>();
static {
for (int index = 0; index < values().length; index++) {
nutritionOrder.put(values()[index].label, index);
}
}
NutritionSortEnum(String label) {
this.label = label;
}
public static Comparator<String> getComparator() {
return (nutrition1, nutrition2) -> {
Integer order1 = nutritionOrder.get(nutrition1);
Integer order2 = nutritionOrder.get(nutrition2);
return Comparator.comparingInt((Integer order) -> order == null ? Integer.MAX_VALUE : order)
.compare(order1, order2);
};
}
public static JSONArray sortByRule(JSONArray contents) {
List<JSONObject> sortedList = new ArrayList<>();
for (int i = 0; i < contents.size(); i++) {
sortedList.add(contents.getJSONObject(i));
}
sortedList.sort((o1, o2) -> {
String nutrition1 = o1 instanceof JSONObject ? o1.getString("nutrition") : null;
String nutrition2 = o2 instanceof JSONObject ? o2.getString("nutrition") : null;
return getComparator().compare(nutrition1, nutrition2);
});
return new JSONArray(sortedList);
}
}

33
diet-web/src/main/java/com/mathvision/diet/controller/DishController.java

@ -29,7 +29,7 @@ import java.util.stream.Collectors;
@RequestMapping("/api/dish")
@Controller
public class DishController extends BaseController {
public class DishController extends BaseController {
@Resource
EnumService enumService;
@ -54,7 +54,8 @@ public class DishController extends BaseController {
Assert.isTrue(CollectionUtils.isNotEmpty(month) && month.stream().allMatch(x -> Range.closed(1, 12).contains(x)), "[参数错误]请选择正确的月份!");
Assert.isTrue(JSON.isValid(ingredient), "[参数错误]食材列表必填!");
List<DishItemDTO> items = JSON.parseObject(ingredient, new TypeReference<List<DishItemDTO>>(){});
List<DishItemDTO> items = JSON.parseObject(ingredient, new TypeReference<List<DishItemDTO>>() {
});
Assert.isTrue(items.stream().allMatch(x -> ingredientService.existsIngredientByKey(x.getKey())), "[参数错误]请选择系统存在的食材!");
if (isAdmin()) {
Assert.isTrue(CollectionUtils.isNotEmpty(vendors), "[参数错误]单位列表必填!");
@ -67,13 +68,22 @@ public class DishController extends BaseController {
dishService.add(vendors.stream().map(vender -> Dish.builder().name(name).vender(vender).marks(mark).poly(poly).month(month).icon(icon).ingredient(items).operate(getUid()).created(dateTime).modify(dateTime).build()).collect(Collectors.toList()), getUid());
}
//update 新增修改菜品,名称做重复检测和提醒
@ResponseBody
@RequestMapping(path = "check/name", method = RequestMethod.GET)
public boolean checkName(@RequestParam(required = false) Long id, @RequestParam Long vender, @RequestParam String name) {
Assert.isTrue(vender != null, "[参数错误]单位id必填!");
Assert.isTrue(StringUtils.isNotBlank(name), "[参数错误]菜品名称必填!");
return dishService.notExists(id, name, vender);
}
@ResponseBody
@RequestMapping(path = "copy", method = RequestMethod.PUT)
public void copy(@RequestParam Long id, @RequestParam(required = false) List<Long> vendors) {
Dish dish = isAdmin() ? dishService.get(id) : dishService.get(id, getVender());
Assert.notNull(dish, "[参数错误]菜品不存在, 复制失败!");
if(isAdmin()) {
if (isAdmin()) {
vendors = vendors == null ? Lists.newArrayList() : vendors.stream().filter(venderService::exists).distinct().collect(Collectors.toList());
} else {
vendors = Lists.newArrayList(getVender());
@ -92,37 +102,38 @@ public class DishController extends BaseController {
@ResponseBody
@RequestMapping(method = RequestMethod.POST)
public void update(@RequestParam Long id, @RequestParam(required = false) String name, @RequestParam(required = false) String icon, @RequestParam(required = false) List<Integer> month, @RequestParam(required = false) String mark, @RequestParam(required = false) String poly, @RequestParam(required = false) String ingredient) {
Dish dish = isAdmin()? dishService.get(id) : dishService.get(id, getVender());
Dish dish = isAdmin() ? dishService.get(id) : dishService.get(id, getVender());
Assert.isTrue(dish != null, "[参数错误]菜品不存在!");
boolean flag = false;
if(StringUtils.isNotBlank(name) && !StringUtils.equals(name, dish.getName())) {
if (StringUtils.isNotBlank(name) && !StringUtils.equals(name, dish.getName())) {
Assert.isTrue(dishService.notExists(id, name, dish.getVender()), "[参数错误]菜品名称已存在!");
dish.setName(name);
flag = true;
}
if(StringUtils.isNotBlank(icon) && !icon.equals(dish.getIcon())) {
if (StringUtils.isNotBlank(icon) && !icon.equals(dish.getIcon())) {
dish.setIcon(icon);
flag = true;
}
if(StringUtils.isNotBlank(mark) && !mark.equals(dish.getMarks())) {
if (StringUtils.isNotBlank(mark) && !mark.equals(dish.getMarks())) {
Assert.isTrue(enumService.checkMark(mark), "[参数错误]菜品标签不在取值范围内!");
dish.setMarks(mark);
flag = true;
}
if(StringUtils.isNotBlank(poly) && !poly.equals(dish.getPoly())) {
if (StringUtils.isNotBlank(poly) && !poly.equals(dish.getPoly())) {
Assert.isTrue(enumService.checkPoly(poly), "[参数错误]烹饪手法不在取值范围内!");
dish.setPoly(poly);
flag = true;
}
if(CollectionUtils.isNotEmpty(month)) {
if (CollectionUtils.isNotEmpty(month)) {
Assert.isTrue(CollectionUtils.isNotEmpty(month) && month.stream().allMatch(x -> Range.closed(1, 12).contains(x)), "[参数错误]请选择正确的月份!");
dish.setMonth(month);
flag = true;
}
if (JSON.isValid(ingredient)) {
List<DishItemDTO> items = JSON.parseObject(ingredient, new TypeReference<List<DishItemDTO>>(){});
if(CollectionUtils.isNotEmpty(items)) {
List<DishItemDTO> items = JSON.parseObject(ingredient, new TypeReference<List<DishItemDTO>>() {
});
if (CollectionUtils.isNotEmpty(items)) {
Assert.isTrue(items.stream().allMatch(x -> ingredientService.existsIngredientByKey(x.getKey())), "[参数错误]请选择系统存在的食材!");
dish.setIngredient(items);
flag = true;

5
doc/change.md

@ -64,3 +64,8 @@
### 12.15
* 油盐糖接口: 增删改查;
### 2025.3.7
* 油盐糖接口(/api/dish/label): 返回值增加三低标签, 字段名-label, 类型-list;
* 类型分析接口(/api/menu/analysis/types): 食谱详情-营养分析-食材种类, dayRule和weekRule返回list结果中每项元素,新增食材明细-details字段,类型-string;
* 新增菜品名称重复校验接口(/api/dish/check/name)。

25
doc/dish.md

@ -192,6 +192,7 @@ ids=1,2,3 // 传了ID返回指定标签,不传返回所有菜品的标签列
"ingredients": [
"小麦"
],
"label": ["低盐", "低脂", "低糖"],
"name": "番茄炒鸡蛋"
}
],
@ -285,4 +286,26 @@ id=1 // 源菜品编号, 必填
"desc": "成功",
"success": true
}
~~~
~~~
# 9. 名称重复校验
> GET /api/dish/check/name
### 输入:
```text
id=47 // 菜品id, 非必填
vender=1 // 单位id,必填
name=回锅肉 // 菜品名称,必填
```
### 输出:
~~~json
{
"body": false, // true:不重复,名称有效; false:重复
"code": 200,
"desc": "成功",
"success": true
}
~~~

6
doc/menu/report.md

@ -218,7 +218,8 @@ crow=xxx //
"standard": "10~100",
"measurement": "weight",
"supplied": 320,
"lack": -220
"lack": -220,
"details": "[稻米(代表值)大米, 黑米, 荞麦]"
}
]
},
@ -228,7 +229,8 @@ crow=xxx //
"standard": "10~100",
"measurement": "weight",
"supplied": 320,
"lack": -220
"lack": -220,
"details": "[稻米(代表值)大米, 黑米, 荞麦]"
}
]
},

Loading…
Cancel
Save