From 0130a2650352cdf28dc88a61fe1fed0ad02c5bc8 Mon Sep 17 00:00:00 2001
From: fangyang2021 <3020949587@qq.com>
Date: Mon, 5 Jan 2026 14:34:55 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BD=8E=E7=B3=96=E6=A0=87=E7=AD=BEBUG?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=20202601?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 37 +
diet-core/pom.xml | 58 +
.../diet/domain/ComponentAnalysisDO.java | 17 +
.../mathvision/diet/domain/DishLabelDO.java | 20 +
.../com/mathvision/diet/domain/UserDO.java | 33 +
.../diet/excel/BigDecimalStringConverter.java | 48 +
.../diet/excel/IngredientModel.java | 69 +
.../mathvision/diet/excel/ResultModel.java | 31 +
.../diet/service/DemoEnvLimitService.java | 70 +
.../mathvision/diet/service/DishService.java | 297 +++
.../mathvision/diet/service/EnumService.java | 153 ++
.../diet/service/IngredientService.java | 244 ++
.../diet/service/MenuDishService.java | 273 +++
.../diet/service/MenuReleaseService.java | 93 +
.../diet/service/MenuReportService.java | 447 ++++
.../diet/service/MenuReviewService.java | 105 +
.../mathvision/diet/service/MenuService.java | 138 ++
.../diet/service/NutritionService.java | 104 +
.../mathvision/diet/service/SugarService.java | 69 +
.../mathvision/diet/service/UserService.java | 274 +++
.../diet/service/VenderService.java | 143 ++
.../mathvision/diet/word/ServerTableData.java | 25 +
.../diet/word/ServerTablePolicy.java | 80 +
diet-dao/pom.xml | 48 +
.../diet/convert/AuthTypeConvert.java | 19 +
.../diet/convert/DishItemConvert.java | 22 +
.../diet/convert/GenderTypeConvert.java | 19 +
.../diet/convert/IngredientConvert.java | 22 +
.../diet/convert/MarkTypeConvert.java | 19 +
.../diet/convert/MenuDishConvert.java | 23 +
.../diet/convert/MenuStatusConvert.java | 19 +
.../diet/convert/RoleTypeConvert.java | 19 +
.../diet/convert/RuleItemConvert.java | 23 +
.../diet/convert/VenderTypeConvert.java | 19 +
.../com/mathvision/diet/domian/AuthType.java | 26 +
.../mathvision/diet/domian/ClientType.java | 5 +
.../mathvision/diet/domian/DishItemDTO.java | 17 +
.../mathvision/diet/domian/GenderType.java | 25 +
.../mathvision/diet/domian/IngredientDTO.java | 32 +
.../com/mathvision/diet/domian/MarkType.java | 25 +
.../com/mathvision/diet/domian/MealType.java | 25 +
.../diet/domian/MeasurementType.java | 25 +
.../mathvision/diet/domian/MenuCountDTO.java | 30 +
.../diet/domian/MenuDishItemDTO.java | 28 +
.../mathvision/diet/domian/MenuStatus.java | 39 +
.../mathvision/diet/domian/MessageType.java | 5 +
.../diet/domian/NutritionSortEnum.java | 62 +
.../com/mathvision/diet/domian/RoleType.java | 25 +
.../mathvision/diet/domian/RuleItemDTO.java | 58 +
.../mathvision/diet/domian/VenderType.java | 25 +
.../java/com/mathvision/diet/entity/Dish.java | 76 +
.../mathvision/diet/entity/FoodCategory.java | 41 +
.../com/mathvision/diet/entity/FoodMark.java | 41 +
.../mathvision/diet/entity/FoodNutrient.java | 48 +
.../com/mathvision/diet/entity/FoodPoly.java | 42 +
.../mathvision/diet/entity/Ingredient.java | 64 +
.../diet/entity/IngredientMark.java | 50 +
.../java/com/mathvision/diet/entity/Menu.java | 95 +
.../mathvision/diet/entity/MenuApprove.java | 43 +
.../com/mathvision/diet/entity/MenuDish.java | 72 +
.../com/mathvision/diet/entity/Nutrition.java | 73 +
.../java/com/mathvision/diet/entity/Role.java | 57 +
.../com/mathvision/diet/entity/RoleItem.java | 52 +
.../com/mathvision/diet/entity/Sugar.java | 70 +
.../java/com/mathvision/diet/entity/User.java | 64 +
.../com/mathvision/diet/entity/UserLog.java | 41 +
.../mathvision/diet/entity/UserMessage.java | 47 +
.../com/mathvision/diet/entity/UserRole.java | 44 +
.../mathvision/diet/entity/UserSession.java | 50 +
.../com/mathvision/diet/entity/Vender.java | 89 +
.../mathvision/diet/entity/VenderConfig.java | 51 +
.../diet/repository/DishRepository.java | 34 +
.../repository/FoodCategoryRepository.java | 8 +
.../diet/repository/FoodMarkRepository.java | 8 +
.../repository/FoodNutrientRepository.java | 8 +
.../diet/repository/FoodPolyRepository.java | 8 +
.../repository/IngredientDTORepository.java | 16 +
.../repository/IngredientMarkRepository.java | 23 +
.../diet/repository/IngredientRepository.java | 42 +
.../repository/MenuApproveRepository.java | 15 +
.../diet/repository/MenuDishRepository.java | 37 +
.../diet/repository/MenuRepository.java | 59 +
.../diet/repository/NutritionRepository.java | 16 +
.../diet/repository/RoleItemRepository.java | 8 +
.../diet/repository/RoleRepository.java | 35 +
.../diet/repository/SugarRepository.java | 11 +
.../diet/repository/UserLogRepository.java | 23 +
.../repository/UserMessageRepository.java | 16 +
.../diet/repository/UserRepository.java | 30 +
.../diet/repository/UserRoleRepository.java | 26 +
.../repository/UserSessionRepository.java | 16 +
.../repository/VenderConfigRepository.java | 19 +
.../diet/repository/VenderRepository.java | 33 +
diet-web/pom.xml | 65 +
.../java/com/mathvision/diet/Application.java | 13 +
.../diet/aspect/GlobalExceptionHandler.java | 79 +
.../diet/aspect/GlobalRequestAspect.java | 95 +
.../diet/aspect/GlobalResponseAspect.java | 53 +
.../mathvision/diet/constant/Constant.java | 30 +
.../diet/controller/AuthController.java | 58 +
.../diet/controller/BaseController.java | 106 +
.../diet/controller/BasicController.java | 24 +
.../diet/controller/DishController.java | 166 ++
.../diet/controller/IconController.java | 51 +
.../diet/controller/IngredientController.java | 137 ++
.../diet/controller/MenuController.java | 174 ++
.../diet/controller/MenuDishController.java | 263 +++
.../controller/MenuDisplayController.java | 34 +
.../controller/MenuReleaseController.java | 60 +
.../diet/controller/MenuReportController.java | 93 +
.../diet/controller/MenuReviewController.java | 63 +
.../diet/controller/NutritionController.java | 143 ++
.../diet/controller/RoleController.java | 53 +
.../diet/controller/SugarController.java | 139 ++
.../diet/controller/UserController.java | 54 +
.../diet/controller/VenderController.java | 170 ++
.../com/mathvision/diet/domain/Result.java | 64 +
.../mathvision/diet/domain/ResultCode.java | 35 +
.../com/mathvision/diet/domain/Session.java | 17 +
.../diet/exception/DietException.java | 15 +
.../com/mathvision/diet/utils/JWTUtils.java | 49 +
.../mathvision/diet/vo/MenuDishDetailVO.java | 28 +
.../com/mathvision/diet/vo/MenuDishVO.java | 17 +
.../src/main/resources/application-dev.yml | 23 +
.../src/main/resources/application-local.yml | 22 +
.../src/main/resources/application-prod.yml | 22 +
diet-web/src/main/resources/application.yml | 28 +
.../src/main/resources/logback-spring.xml | 137 ++
diet-web/src/main/resources/static/basic.html | 416 ++++
.../src/main/resources/static/change.html | 73 +
diet-web/src/main/resources/static/dish.html | 261 +++
diet-web/src/main/resources/static/icon.html | 29 +
diet-web/src/main/resources/static/index.html | 47 +
.../src/main/resources/static/ingredient.html | 181 ++
diet-web/src/main/resources/static/menu.html | 12 +
.../src/main/resources/static/menu/dish.html | 236 ++
.../main/resources/static/menu/display.html | 92 +
.../src/main/resources/static/menu/menu.html | 193 ++
.../main/resources/static/menu/release.html | 94 +
.../main/resources/static/menu/report.html | 290 +++
.../main/resources/static/menu/review.html | 129 +
.../src/main/resources/static/nutrition.html | 189 ++
diet-web/src/main/resources/static/sugar.html | 98 +
diet-web/src/main/resources/static/user.html | 269 +++
.../src/main/resources/static/vender.html | 227 ++
doc/basic.md | 433 ++++
doc/change.md | 71 +
doc/dish.md | 311 +++
doc/icon.md | 31 +
doc/index.md | 48 +
doc/ingredient.md | 211 ++
doc/menu.md | 9 +
doc/menu/dish.md | 265 +++
doc/menu/display.md | 97 +
doc/menu/menu.md | 220 ++
doc/menu/release.md | 108 +
doc/menu/report.md | 312 +++
doc/menu/review.md | 149 ++
doc/nutrition.md | 210 ++
doc/sugar.md | 113 +
doc/user.md | 304 +++
doc/vender.md | 261 +++
pom.xml | 73 +
sql/diet.sql | 420 ++++
sql/init.sql | 2074 +++++++++++++++++
165 files changed, 16369 insertions(+)
create mode 100644 .gitignore
create mode 100644 diet-core/pom.xml
create mode 100644 diet-core/src/main/java/com/mathvision/diet/domain/ComponentAnalysisDO.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/domain/DishLabelDO.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/domain/UserDO.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/excel/BigDecimalStringConverter.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/excel/IngredientModel.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/excel/ResultModel.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/DemoEnvLimitService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/DishService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/EnumService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/IngredientService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/MenuDishService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/MenuReleaseService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/MenuReportService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/MenuReviewService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/MenuService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/NutritionService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/SugarService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/UserService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/service/VenderService.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/word/ServerTableData.java
create mode 100644 diet-core/src/main/java/com/mathvision/diet/word/ServerTablePolicy.java
create mode 100644 diet-dao/pom.xml
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/AuthTypeConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/DishItemConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/GenderTypeConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/IngredientConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/MarkTypeConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/MenuDishConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/MenuStatusConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/RoleTypeConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/RuleItemConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/convert/VenderTypeConvert.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/AuthType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/ClientType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/DishItemDTO.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/GenderType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/IngredientDTO.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MarkType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MealType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MeasurementType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MenuCountDTO.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MenuDishItemDTO.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MenuStatus.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/MessageType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/NutritionSortEnum.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/RoleType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/RuleItemDTO.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/domian/VenderType.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Dish.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/FoodCategory.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/FoodMark.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/FoodNutrient.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/FoodPoly.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Ingredient.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/IngredientMark.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Menu.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/MenuApprove.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/MenuDish.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Nutrition.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Role.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/RoleItem.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Sugar.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/User.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/UserLog.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/UserMessage.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/UserRole.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/UserSession.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/Vender.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/entity/VenderConfig.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/DishRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/FoodCategoryRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/FoodMarkRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/FoodNutrientRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/FoodPolyRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/IngredientDTORepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/IngredientMarkRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/IngredientRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/MenuApproveRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/MenuDishRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/MenuRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/NutritionRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/RoleItemRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/RoleRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/SugarRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/UserLogRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/UserMessageRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/UserRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/UserRoleRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/UserSessionRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/VenderConfigRepository.java
create mode 100644 diet-dao/src/main/java/com/mathvision/diet/repository/VenderRepository.java
create mode 100644 diet-web/pom.xml
create mode 100644 diet-web/src/main/java/com/mathvision/diet/Application.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/aspect/GlobalExceptionHandler.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/aspect/GlobalRequestAspect.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/aspect/GlobalResponseAspect.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/constant/Constant.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/AuthController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/BaseController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/BasicController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/DishController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/IconController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/IngredientController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/MenuController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/MenuDishController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/MenuDisplayController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/MenuReleaseController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/MenuReportController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/MenuReviewController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/NutritionController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/RoleController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/SugarController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/UserController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/controller/VenderController.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/domain/Result.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/domain/ResultCode.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/domain/Session.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/exception/DietException.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/utils/JWTUtils.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/vo/MenuDishDetailVO.java
create mode 100644 diet-web/src/main/java/com/mathvision/diet/vo/MenuDishVO.java
create mode 100644 diet-web/src/main/resources/application-dev.yml
create mode 100644 diet-web/src/main/resources/application-local.yml
create mode 100644 diet-web/src/main/resources/application-prod.yml
create mode 100644 diet-web/src/main/resources/application.yml
create mode 100644 diet-web/src/main/resources/logback-spring.xml
create mode 100644 diet-web/src/main/resources/static/basic.html
create mode 100644 diet-web/src/main/resources/static/change.html
create mode 100644 diet-web/src/main/resources/static/dish.html
create mode 100644 diet-web/src/main/resources/static/icon.html
create mode 100644 diet-web/src/main/resources/static/index.html
create mode 100644 diet-web/src/main/resources/static/ingredient.html
create mode 100644 diet-web/src/main/resources/static/menu.html
create mode 100644 diet-web/src/main/resources/static/menu/dish.html
create mode 100644 diet-web/src/main/resources/static/menu/display.html
create mode 100644 diet-web/src/main/resources/static/menu/menu.html
create mode 100644 diet-web/src/main/resources/static/menu/release.html
create mode 100644 diet-web/src/main/resources/static/menu/report.html
create mode 100644 diet-web/src/main/resources/static/menu/review.html
create mode 100644 diet-web/src/main/resources/static/nutrition.html
create mode 100644 diet-web/src/main/resources/static/sugar.html
create mode 100644 diet-web/src/main/resources/static/user.html
create mode 100644 diet-web/src/main/resources/static/vender.html
create mode 100644 doc/basic.md
create mode 100644 doc/change.md
create mode 100644 doc/dish.md
create mode 100644 doc/icon.md
create mode 100644 doc/index.md
create mode 100644 doc/ingredient.md
create mode 100644 doc/menu.md
create mode 100644 doc/menu/dish.md
create mode 100644 doc/menu/display.md
create mode 100644 doc/menu/menu.md
create mode 100644 doc/menu/release.md
create mode 100644 doc/menu/report.md
create mode 100644 doc/menu/review.md
create mode 100644 doc/nutrition.md
create mode 100644 doc/sugar.md
create mode 100644 doc/user.md
create mode 100644 doc/vender.md
create mode 100644 pom.xml
create mode 100644 sql/diet.sql
create mode 100644 sql/init.sql
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..89bcb65
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/
+.jpb/
+*.iws
+*.iml
+*.ipr
+logs/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store!/
\ No newline at end of file
diff --git a/diet-core/pom.xml b/diet-core/pom.xml
new file mode 100644
index 0000000..e60c0e8
--- /dev/null
+++ b/diet-core/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+
+ com.mathvision.diet
+ diet-core
+ 1.0-SNAPSHOT
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+ com.mathvision.diet
+ diet-dao
+ 1.0-SNAPSHOT
+
+
+ com.alibaba
+ easyexcel
+ 3.3.2
+
+
+ org.apache.poi
+ poi-ooxml
+
+
+ org.apache.poi
+ poi-ooxml-schemas
+
+
+ org.apache.poi
+ poi
+
+
+
+
+ com.deepoove
+ poi-tl
+ 1.12.2
+
+
+ org.apache.poi
+ poi
+ 5.2.2
+
+
+ io.github.draco1023
+ poi-tl-ext
+ 0.4.15
+
+
+
\ No newline at end of file
diff --git a/diet-core/src/main/java/com/mathvision/diet/domain/ComponentAnalysisDO.java b/diet-core/src/main/java/com/mathvision/diet/domain/ComponentAnalysisDO.java
new file mode 100644
index 0000000..906ae04
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/domain/ComponentAnalysisDO.java
@@ -0,0 +1,17 @@
+package com.mathvision.diet.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ComponentAnalysisDO {
+ String key;
+ String name;
+ String nutrition;
+ String nrv;
+}
diff --git a/diet-core/src/main/java/com/mathvision/diet/domain/DishLabelDO.java b/diet-core/src/main/java/com/mathvision/diet/domain/DishLabelDO.java
new file mode 100644
index 0000000..ea9cbb3
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/domain/DishLabelDO.java
@@ -0,0 +1,20 @@
+package com.mathvision.diet.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DishLabelDO {
+ String name;
+ List component;
+ List ingredients;
+ //update 新增三低标识
+ List label;
+}
diff --git a/diet-core/src/main/java/com/mathvision/diet/domain/UserDO.java b/diet-core/src/main/java/com/mathvision/diet/domain/UserDO.java
new file mode 100644
index 0000000..30fd986
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/domain/UserDO.java
@@ -0,0 +1,33 @@
+package com.mathvision.diet.domain;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.mathvision.diet.entity.RoleItem;
+import com.mathvision.diet.entity.Vender;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.Instant;
+import java.util.List;
+
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserDO {
+ private String uid;
+ private String name;
+ private String phone;
+ private Vender vender;
+ private Long roleId;
+ private String roleName;
+ private String roleType;
+ private Instant time;
+ private List roleItems;
+
+ @JSONField(serialize = false)
+ public boolean isAdmin() {
+ return vender == null || vender.getId() == null;
+ }
+}
\ No newline at end of file
diff --git a/diet-core/src/main/java/com/mathvision/diet/excel/BigDecimalStringConverter.java b/diet-core/src/main/java/com/mathvision/diet/excel/BigDecimalStringConverter.java
new file mode 100644
index 0000000..4c7f385
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/excel/BigDecimalStringConverter.java
@@ -0,0 +1,48 @@
+package com.mathvision.diet.excel;
+
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.alibaba.excel.util.NumberUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+
+@Slf4j
+public class BigDecimalStringConverter implements Converter {
+ public BigDecimalStringConverter() {
+ }
+
+ public Class supportJavaTypeKey() {
+ return BigDecimal.class;
+ }
+
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return CellDataTypeEnum.STRING;
+ }
+
+ public BigDecimal convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ if(cellData == null) {
+ return null;
+ }
+ if(CellDataTypeEnum.NUMBER.equals(cellData.getType())) {
+ return cellData.getNumberValue();
+ }
+ if (CellDataTypeEnum.STRING.equals(cellData.getType())) {
+ try {
+ return NumberUtils.parseBigDecimal(cellData.getStringValue().trim(), contentProperty);
+ } catch (Exception e) {
+ log.error("[BigDecimalStringConverter] convertToJavaData<" + cellData.getStringValue() + "> exception :" + e.getMessage(), e);
+ return new BigDecimal(-1);
+ }
+ }
+ return null;
+ }
+
+ public WriteCellData> convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ return NumberUtils.formatToCellDataString(value, contentProperty);
+ }
+}
diff --git a/diet-core/src/main/java/com/mathvision/diet/excel/IngredientModel.java b/diet-core/src/main/java/com/mathvision/diet/excel/IngredientModel.java
new file mode 100644
index 0000000..d7b8e43
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/excel/IngredientModel.java
@@ -0,0 +1,69 @@
+package com.mathvision.diet.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@HeadRowHeight(30)
+@ContentRowHeight(15)
+@ColumnWidth(25)
+@ContentFontStyle(fontHeightInPoints = (short) 12)
+public class IngredientModel {
+
+ @ExcelProperty("食物编码")
+ private String key;
+
+ @ExcelProperty("食物名称")
+ private String name;
+
+ @ExcelProperty("食物类型")
+ private String type;
+
+ @ExcelProperty(value = "能量(kcal)", converter = BigDecimalStringConverter.class)
+ private BigDecimal energy;
+
+ @ExcelProperty(value = "蛋白质(g)", converter = BigDecimalStringConverter.class)
+ private BigDecimal protein;
+
+ @ExcelProperty(value = "脂肪(g)", converter = BigDecimalStringConverter.class)
+ private BigDecimal fat;
+
+ @ExcelProperty(value = "碳水化合物(g)", converter = BigDecimalStringConverter.class)
+ private BigDecimal carbs;
+
+ @ExcelProperty(value = "钙(mg)", converter = BigDecimalStringConverter.class)
+ private BigDecimal calcium;
+
+ @ExcelProperty(value = "铁(mg)", converter = BigDecimalStringConverter.class)
+ private BigDecimal iron;
+
+ @ExcelProperty(value = "锌(mg)", converter = BigDecimalStringConverter.class)
+ private BigDecimal zinc;
+
+ @ExcelProperty(value = "维生素A(μgRAE)", converter = BigDecimalStringConverter.class)
+ private BigDecimal va;
+
+ @ExcelProperty(value = "维生素B1(mg)硫胺素", converter = BigDecimalStringConverter.class)
+ private BigDecimal vb1;
+
+ @ExcelProperty(value = "维生素B2(mg)核黄素", converter = BigDecimalStringConverter.class)
+ private BigDecimal vb2;
+
+ @ExcelProperty(value = "维生素C(mg)", converter = BigDecimalStringConverter.class)
+ private BigDecimal vc;
+
+ @ExcelProperty(value = "膳食纤维(g)", converter = BigDecimalStringConverter.class)
+ private BigDecimal fiber;
+
+ @ExcelProperty(value = "钠(mg)", converter = BigDecimalStringConverter.class)
+ private BigDecimal sodium;
+}
diff --git a/diet-core/src/main/java/com/mathvision/diet/excel/ResultModel.java b/diet-core/src/main/java/com/mathvision/diet/excel/ResultModel.java
new file mode 100644
index 0000000..0f16ae3
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/excel/ResultModel.java
@@ -0,0 +1,31 @@
+package com.mathvision.diet.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentFontStyle;
+import com.alibaba.excel.annotation.write.style.ContentRowHeight;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@HeadRowHeight(30)
+@ContentRowHeight(15)
+@ColumnWidth(18)
+@ContentFontStyle(fontHeightInPoints = (short) 12)
+public class ResultModel {
+
+ @ColumnWidth(80)
+ @ExcelProperty("数据标识")
+ private String key;
+
+ @ColumnWidth(35)
+ @ExcelProperty("导入结果")
+ private String result;
+
+}
diff --git a/diet-core/src/main/java/com/mathvision/diet/service/DemoEnvLimitService.java b/diet-core/src/main/java/com/mathvision/diet/service/DemoEnvLimitService.java
new file mode 100644
index 0000000..0700310
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/service/DemoEnvLimitService.java
@@ -0,0 +1,70 @@
+package com.mathvision.diet.service;
+
+import com.google.common.util.concurrent.RateLimiter;
+import com.mathvision.diet.repository.DishRepository;
+import com.mathvision.diet.repository.MenuRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+public class DemoEnvLimitService {
+ @Value(value = "${demo.is-demo:false}")
+ private boolean isDemo;
+
+ @Value(value = "${demo.params.img-enable:false}")
+ private boolean imgEnable;
+
+ @Value(value = "${demo.params.dish-num:10}")
+ private long dishNum;
+
+ @Value(value = "${demo.params.menu-num:5}")
+ private long menuNum;
+
+ @Value(value = "${demo.params.rate-block:true}")
+ private boolean rateBlock;
+
+ @Value(value = "${demo.params.rate-limit:500}")
+ private int rateLimit;
+
+ private static RateLimiter apiRateLimiter;
+
+ @Resource
+ private DishRepository dishRepository;
+
+ @Resource
+ private MenuRepository menuRepository;
+
+ @PostConstruct
+ public void init() {
+ if (isDemo) apiRateLimiter = RateLimiter.create(rateLimit, 10, TimeUnit.SECONDS);
+ }
+
+ public boolean checkImgEnable() {
+ return isDemo ? imgEnable : true;
+ }
+
+ public boolean checkDishNum(Long vendor) {
+ return !isDemo || dishRepository.countByVender(vendor) < dishNum;
+ }
+
+ public boolean checkMenuNum(Long vendor) {
+ return !isDemo || menuRepository.countByVender(vendor) < menuNum;
+ }
+
+ public boolean checkRateLimit() {
+ if (isDemo) {
+ if (rateBlock){
+ apiRateLimiter.acquire();
+ }else {
+ return apiRateLimiter.tryAcquire();
+ }
+ }
+ return true;
+ }
+}
diff --git a/diet-core/src/main/java/com/mathvision/diet/service/DishService.java b/diet-core/src/main/java/com/mathvision/diet/service/DishService.java
new file mode 100644
index 0000000..42f0649
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/service/DishService.java
@@ -0,0 +1,297 @@
+package com.mathvision.diet.service;
+
+import com.google.common.collect.Lists;
+import com.mathvision.diet.domain.ComponentAnalysisDO;
+import com.mathvision.diet.domain.DishLabelDO;
+import com.mathvision.diet.domian.DishItemDTO;
+import com.mathvision.diet.entity.Dish;
+import com.mathvision.diet.entity.FoodNutrient;
+import com.mathvision.diet.entity.Ingredient;
+import com.mathvision.diet.repository.DishRepository;
+import com.mathvision.diet.repository.MenuDishRepository;
+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;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.persistence.criteria.Predicate;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
+import java.time.Instant;
+import java.util.*;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class DishService {
+ private static final List MUST_DISPLAY_ITEM = Lists.newArrayList("energy", "protein", "fat", "carbs", "sodium");
+ private static final List WANT_DISPLAY_ITEM = Lists.newArrayList("energy", "protein", "fat", "carbs", "sugar", "sodium");
+
+ private static final Lock UPDATE_LABEL_LOCK = new ReentrantLock();
+ private static Instant UPDATE_LABEL_TIME;
+
+ @Resource
+ private EnumService enumService;
+
+ @Resource
+ private IngredientService ingredientService;
+
+ @Resource
+ private DishRepository dishRepository;
+
+ @Resource
+ private MenuDishRepository menuDishRepository;
+
+ @Scheduled(cron = "0/2 * * * * *")
+ public void init() {
+ if (!UPDATE_LABEL_LOCK.tryLock()) {
+ return;
+ }
+ try {
+ List dishes = UPDATE_LABEL_TIME == null ? dishRepository.findAll() : dishRepository.findByModifyGreaterThan(UPDATE_LABEL_TIME.minusMillis(1000));
+ if (dishes.isEmpty()) {
+ return;
+ }
+ UPDATE_LABEL_TIME = Instant.now();
+ Map 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));
+ dishes.forEach(dish -> {
+ Map 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)))
+ ).collect(Collectors.toMap(Pair::getKey, Pair::getValue, BigDecimal::add));
+ items.put("sugar", sugar(dish, ingredientMap));
+
+ List label = Lists.newArrayList();
+ if (items.getOrDefault("sodium", BigDecimal.ZERO).compareTo(new BigDecimal("120")) <= 0) {
+ label.add("低盐");
+ }
+ if (items.getOrDefault("fat", BigDecimal.ZERO).compareTo(new BigDecimal("3")) <= 0) {
+ label.add("低脂");
+ }
+ if (items.getOrDefault("sugar", BigDecimal.ZERO).compareTo(new BigDecimal("5")) <= 0) {
+ label.add("低糖");
+ }
+ dish.setLabel(label);
+ });
+ dishRepository.saveAll(dishes);
+ } catch (Exception e) {
+ log.error("[DishService] update label exception : {}", e.getMessage(), e);
+ } finally {
+ UPDATE_LABEL_LOCK.unlock();
+ }
+ }
+
+ public Dish copy(Long id, Long vender, String operator, Instant instant) {
+ Dish dish = get(id);
+ List dishes = dishRepository.findByVenderAndName(vender, dish.getName());
+ if (CollectionUtils.isNotEmpty(dishes)) {
+ return dishes.get(0);
+ }
+ dish = dishRepository.save(Dish.builder().name(dish.getName()).vender(vender).marks(dish.getMarks()).label(dish.getLabel()).poly(dish.getPoly()).month(dish.getMonth()).icon(dish.getIcon()).ingredient(dish.getIngredient()).operate(operator).created(instant).modify(instant).build());
+ log.info("[DishService] copy dish name = {}, operator = {}", dish.getName(), operator);
+ return dish;
+ }
+
+ public void copy(Dish dish, List vendors, String operator) {
+ Instant instant = Instant.now();
+ List dishes = vendors.stream().filter(vender -> notExists(null, dish.getName(), vender)).map(vender -> Dish.builder().name(dish.getName()).vender(vender).marks(dish.getMarks()).poly(dish.getPoly()).label(dish.getLabel()).month(dish.getMonth()).icon(dish.getIcon()).ingredient(dish.getIngredient()).operate(operator).created(instant).modify(instant).build()).collect(Collectors.toList());
+ dishRepository.saveAll(dishes);
+ log.info("[DishService] copy dishes count = {}, operator = {}", dishes.size(), operator);
+ }
+
+ public void add(List dishes, String operator) {
+ dishRepository.saveAll(dishes);
+ log.info("[DishService] add dishes count = {}, operator = {}", dishes.size(), operator);
+ }
+
+ public void delete(List ids, Long venderId, String operator) {
+ if (venderId > 0) {
+ dishRepository.deleteByIdInAndVender(ids, venderId);
+ //食谱菜品空数据优化
+ menuDishRepository.deleteByDishInAndVender(ids, venderId);
+ } else {
+ dishRepository.deleteAllByIdInBatch(ids);
+ menuDishRepository.deleteByDishIn(ids);
+ }
+ log.info("[DishService] delete ids = {}, operator = {}", ids, operator);
+ }
+
+ public void delete(Long venderId, String operator) {
+ dishRepository.deleteByVender(venderId);
+ log.info("[DishService] delete venderId = {}, operator = {}", venderId, operator);
+ }
+
+ public void update(Dish dish, String operator) {
+ dish.setModify(Instant.now());
+ dishRepository.save(dish);
+ log.info("[DishService] update name = {}, operator = {}", dish.getName(), operator);
+ }
+
+ public boolean exists(Long vender, List ids) {
+ return dishRepository.existsByVenderAndIdIn(vender, ids);
+ }
+
+ public boolean notExists(Long id, String name, Long vender) {
+ return id == null ? !dishRepository.existsByVenderAndName(vender, name) : !dishRepository.existsByVenderAndNameAndIdNot(vender, name, id);
+ }
+
+ public Dish get(Long id) {
+ return dishRepository.findById(id).orElse(null);
+ }
+
+ public Dish get(Long id, Long vender) {
+ return dishRepository.findByIdAndVender(id, vender);
+ }
+
+ public List query(String keyword) {
+ return dishRepository.findByNameLikeOrderByIdDesc("%" + keyword + "%");
+ }
+
+ public Page list(Long vender, String name, String mark, String poly, String label, PageRequest pageRequest) {
+ return dishRepository.findAll(toSpecification(vender, name, mark, poly, label), pageRequest);
+ }
+
+ private Specification toSpecification(Long vender, String name, String mark, String poly, String label) {
+ return (root, query, builder) -> {
+ List predicates = new ArrayList<>();
+
+ if (vender > 0) {
+ predicates.add(builder.equal(root.get("vender"), vender));
+ }
+
+ if (StringUtils.isNotBlank(mark)) {
+ predicates.add(builder.equal(root.get("marks"), mark));
+ }
+
+ if (StringUtils.isNotBlank(poly)) {
+ predicates.add(builder.equal(root.get("poly"), poly));
+ }
+
+ if (StringUtils.isNotBlank(name)) {
+ predicates.add(builder.like(root.get("name"), "%" + name + "%"));
+ }
+
+ if (StringUtils.isNotBlank(label)) {
+ predicates.add(builder.like(root.get("label"), "%" + label + "%"));
+ }
+
+ if (predicates.size() > 1) {
+ return builder.and(predicates.toArray(new Predicate[0]));
+ } else if (predicates.size() == 1) {
+ return predicates.get(0);
+ } else {
+ return null;
+ }
+ };
+ }
+
+ public List label(List ids, Long vender) {
+ List dishes = Lists.newArrayList();
+ if (CollectionUtils.isNotEmpty(ids)) {
+ if (vender > 0) {
+ dishes.addAll(dishRepository.findByVenderAndIdIn(vender, ids));
+ } else {
+ dishes.addAll(dishRepository.findByIdIn(ids));
+ }
+ } else {
+ if (vender > 0) {
+ dishes.addAll(dishRepository.findByVender(vender));
+ } else {
+ dishes.addAll(dishRepository.findAll());
+ }
+ }
+
+ if (dishes.isEmpty()) {
+ return Lists.newArrayList();
+ }
+
+ DecimalFormat formatInteger = new DecimalFormat();
+ formatInteger.setMaximumFractionDigits(0);
+ formatInteger.setMinimumFractionDigits(0);
+ formatInteger.setRoundingMode(RoundingMode.HALF_UP);
+
+ DecimalFormat formatValue = new DecimalFormat();
+ formatValue.setMaximumFractionDigits(1);
+ formatValue.setMinimumFractionDigits(1);
+ formatValue.setRoundingMode(RoundingMode.HALF_UP);
+
+ Map 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 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 _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)))
+ ).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 -> {
+ if (!_items.containsKey(x)) {
+ _items.put(x, BigDecimal.ZERO);
+ }
+ });
+
+ Map 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();
+ }
+ }));
+
+ List component = items.entrySet().stream().filter(x -> MUST_DISPLAY_ITEM.contains(x.getKey()) || WANT_DISPLAY_ITEM.contains(x.getKey()) && x.getValue() != null && x.getValue().compareTo(BigDecimal.ZERO) > 0).map(x -> {
+ FoodNutrient foodNutrient = enumService.getNutrient(x.getKey());
+ if (foodNutrient == null) {
+ if (x.getKey().equals("sugar")) {
+ foodNutrient = FoodNutrient.builder().key(x.getKey()).value("糖").measurement("g").build();
+ } else {
+ foodNutrient = FoodNutrient.builder().key(x.getKey()).value(x.getKey()).measurement("-").build();
+ }
+ }
+
+ String name = foodNutrient.getValue();
+ //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();
+ name = "钠/食盐";
+ value = String.format("%s(mg)/%s(g)", formatInteger.format(x.getValue().floatValue()), formatValue.format(salt));
+ }
+ 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).label(dish.getLabel()).build();
+ }).collect(Collectors.toList());
+ }
+
+ private BigDecimal sugar(Dish dish, Map ingredientMap) {
+ BigDecimal total = dish.getIngredient().stream().map(DishItemDTO::getValue).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
+ BigDecimal sugar = dish.getIngredient().stream().filter(x -> ingredientMap.containsKey(x.getKey()))
+ .map(x -> Pair.of(ingredientMap.get(x.getKey()), x.getValue()))
+ .filter(x -> StringUtils.equals("糖类", x.getKey().getType())).map(Pair::getValue).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
+ // 计算每100克食材中糖的含量
+ if (total.compareTo(BigDecimal.ZERO) == 0) {
+ return BigDecimal.ZERO;
+ }
+ return sugar.divide(total, 4, RoundingMode.HALF_UP)
+ .multiply(new BigDecimal("100"))
+ .setScale(1, RoundingMode.HALF_UP);
+ }
+}
\ No newline at end of file
diff --git a/diet-core/src/main/java/com/mathvision/diet/service/EnumService.java b/diet-core/src/main/java/com/mathvision/diet/service/EnumService.java
new file mode 100644
index 0000000..a4bfc34
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/service/EnumService.java
@@ -0,0 +1,153 @@
+package com.mathvision.diet.service;
+
+import com.google.common.collect.Sets;
+import com.mathvision.diet.domian.*;
+import com.mathvision.diet.entity.*;
+import com.mathvision.diet.repository.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.KeyValue;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class EnumService {
+ private final FoodPolyRepository foodPolyRepository;
+
+ public EnumService(FoodPolyRepository foodPolyRepository) {
+ this.foodPolyRepository = foodPolyRepository;
+ }
+
+ private static Map> AUTH_ITEMS = new HashMap<>();
+ private static Map ROLE_ITEMS = new HashMap<>();
+ private static Map FOOD_MARK = new HashMap<>();
+ private static Map FOOD_POLY = new HashMap<>();
+ private static Map FOOD_CATEGORY = new HashMap<>();
+ private static Map FOOD_NUTRIENT = new HashMap<>();
+
+ @Resource
+ private RoleItemRepository roleItemRepository;
+
+ @Resource
+ private FoodMarkRepository foodMarkRepository;
+
+ @Resource
+ private FoodCategoryRepository foodCategoryRepository;
+
+ @Resource
+ private FoodNutrientRepository foodNutrientRepository;
+
+ @PostConstruct
+ @Scheduled(cron = "0 0/5 * * * *")
+ public void init() {
+ ROLE_ITEMS = roleItemRepository.findAll().stream().collect(Collectors.toConcurrentMap(RoleItem::getId, x -> x));
+ AUTH_ITEMS = ROLE_ITEMS.values().stream().map(item -> Pair.of(item.getItemType(), "/api/" + item.getItemValue().split(":", 2)[1])).collect(Collectors.toMap(Pair::getKey, v-> Sets.newHashSet(v.getValue()), Sets::union));
+ FOOD_MARK = foodMarkRepository.findAll().stream().collect(Collectors.toConcurrentMap(FoodMark::getKey, x -> x));
+ FOOD_POLY = foodPolyRepository.findAll().stream().collect(Collectors.toConcurrentMap(FoodPoly::getKey, x -> x));
+ FOOD_CATEGORY = foodCategoryRepository.findAll().stream().collect(Collectors.toConcurrentMap(FoodCategory::getKey, x -> x));
+ FOOD_NUTRIENT = foodNutrientRepository.findAll().stream().collect(Collectors.toConcurrentMap(FoodNutrient::getKey, x -> x));
+ }
+
+ public Map> getAll() {
+ Map> result = new HashMap<>();
+ result.put("mark", FOOD_MARK.values());
+ result.put("poly", FOOD_POLY.values());
+ result.put("category", FOOD_CATEGORY.values());
+ result.put("nutrient", FOOD_NUTRIENT.values());
+ result.put("venderType", Arrays.stream(VenderType.values()).map(x -> new KeyValue() {
+ @Override
+ public String getKey() {
+ return x.getType();
+ }
+
+ @Override
+ public String getValue() {
+ return x.getType();
+ }
+ }).collect(Collectors.toList()));
+ result.put("markType", Arrays.stream(MarkType.values()).map(x -> new KeyValue() {
+ @Override
+ public String getKey() {
+ return x.getType();
+ }
+
+ @Override
+ public String getValue() {
+ return x.getType();
+ }
+ }).collect(Collectors.toList()));
+ result.put("mealType", Arrays.stream(MealType.values()).map(x -> new KeyValue() {
+ @Override
+ public String getKey() {
+ return x.getType();
+ }
+
+ @Override
+ public String getValue() {
+ return x.getType();
+ }
+ }).collect(Collectors.toList()));
+ result.put("menuStatus", Arrays.stream(MenuStatus.values()).map(x -> new KeyValue() {
+ @Override
+ public Integer getKey() {
+ return x.getCode();
+ }
+
+ @Override
+ public String getValue() {
+ return x.getType();
+ }
+ }).collect(Collectors.toList()));
+ result.put("measurementType", Arrays.stream(MeasurementType.values()).map(x -> new KeyValue() {
+ @Override
+ public String getKey() {
+ return x.name();
+ }
+
+ @Override
+ public String getValue() {
+ return x.getType();
+ }
+ }).collect(Collectors.toList()));
+
+ return result;
+ }
+
+ public Set getAuthItems(AuthType authType) {
+ return AUTH_ITEMS.getOrDefault(authType, Sets.newHashSet());
+ }
+
+ public List getRoleItems(AuthType itemType) {
+ return ROLE_ITEMS.values().stream().filter(item -> item.getItemType().equals(itemType)).collect(Collectors.toList());
+ }
+
+ public List getRoleItems(List items) {
+ return ROLE_ITEMS.entrySet().stream().filter(x -> items.contains(x.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
+ }
+
+ public boolean checkMark(String mark) {
+ return FOOD_MARK.containsKey(mark);
+ }
+
+ public boolean checkPoly(String poly) {
+ return FOOD_POLY.containsKey(poly);
+ }
+
+ public boolean checkCategory(String category) {
+ return FOOD_CATEGORY.containsKey(category);
+ }
+
+ public boolean checkNutrient(String nutrient) {
+ return FOOD_NUTRIENT.containsKey(nutrient);
+ }
+
+ public FoodNutrient getNutrient(String nutrient) {
+ return FOOD_NUTRIENT.get(nutrient);
+ }
+}
\ No newline at end of file
diff --git a/diet-core/src/main/java/com/mathvision/diet/service/IngredientService.java b/diet-core/src/main/java/com/mathvision/diet/service/IngredientService.java
new file mode 100644
index 0000000..857ecb7
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/service/IngredientService.java
@@ -0,0 +1,244 @@
+package com.mathvision.diet.service;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.support.ExcelTypeEnum;
+import com.alibaba.excel.write.metadata.style.WriteCellStyle;
+import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
+import com.google.common.collect.Lists;
+import com.mathvision.diet.domian.MarkType;
+import com.mathvision.diet.entity.Ingredient;
+import com.mathvision.diet.entity.IngredientMark;
+import com.mathvision.diet.excel.IngredientModel;
+import com.mathvision.diet.excel.ResultModel;
+import com.mathvision.diet.repository.IngredientDTORepository;
+import com.mathvision.diet.repository.IngredientMarkRepository;
+import com.mathvision.diet.repository.IngredientRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import javax.annotation.Resource;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class IngredientService {
+
+ @Resource
+ private EnumService enumService;
+
+ @Resource
+ private IngredientRepository ingredientRepository;
+
+ @Resource
+ private IngredientDTORepository ingredientDTORepository;
+
+ @Resource
+ private IngredientMarkRepository ingredientMarkRepository;
+
+ public void template(OutputStream outputStream) {
+ WriteCellStyle headWriteCellStyle = new WriteCellStyle();
+ headWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
+ headWriteCellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
+
+ EasyExcel.write(outputStream).registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, new WriteCellStyle()))
+ .head(IngredientModel.class).excelType(ExcelTypeEnum.XLSX).sheet("食材导入模板").doWrite(Lists.newArrayList());
+ }
+
+ public void upload(InputStream inputStream, OutputStream outputStream, String operator) {
+ Instant dateTime = Instant.now();
+ EasyExcel.read(inputStream, IngredientModel.class, new ReadListener() {
+ final List resultModels = Lists.newArrayList();
+ final List ingredients = Lists.newArrayList();
+ final Map allItems = getByKeys();
+
+ @Override
+ public void onException(Exception exception, AnalysisContext context) {
+ if (exception != null) {
+ throw new IllegalArgumentException("导入异常:" + exception.getMessage());
+ }
+ }
+
+ @Override
+ public void invoke(IngredientModel o, AnalysisContext analysisContext) {
+ String resultKey = String.format("%s-%s-%s", o.getKey(), o.getName(), o.getType());
+
+ try {
+ Ingredient ingredient = Ingredient.builder().key(o.getKey()).name(o.getName()).type(o.getType()).nutrient(Arrays.stream(IngredientModel.class.getDeclaredFields()).filter(x -> BigDecimal.class.equals(x.getType())).peek(x -> x.setAccessible(true)).map(x -> {
+ try {
+ return Pair.of(x.getName(), (BigDecimal)x.get(o));
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }).filter(x -> x.getValue() != null).collect(Collectors.toMap(Pair::getKey, Pair::getValue))).operate(operator).created(dateTime).modify(dateTime).build();
+
+ if (StringUtils.isBlank(ingredient.getKey())) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("食物编码为空").build());
+ return;
+ }
+ if (StringUtils.isBlank(ingredient.getName())) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("食物名称为空").build());
+ return;
+ }
+ if (allItems.containsKey(ingredient.getKey()) || allItems.containsValue(ingredient.getName())) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("编号/名称已存在").build());
+ return;
+ }
+ if (ingredients.stream().anyMatch(x -> x.getKey().equals(ingredient.getKey()))) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("编号在excel文件中存在重复").build());
+ return;
+ }
+ if (StringUtils.isBlank(ingredient.getType()) || !enumService.checkCategory(ingredient.getType())) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("食物类型为空或者不支持").build());
+ return;
+ }
+ if (MapUtils.isEmpty(ingredient.getNutrient())) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("营养素内容全空").build());
+ return;
+ }
+ if (ingredient.getNutrient().entrySet().stream().anyMatch(x -> !enumService.checkNutrient(x.getKey()))) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("包含不支持的营养素").build());
+ return;
+ }
+ if (ingredient.getNutrient().entrySet().stream().anyMatch(x -> x.getValue().floatValue() < 0)) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("营养素含量不能识别").build());
+ return;
+ }
+
+ ingredients.add(ingredient);
+ resultModels.add(ResultModel.builder().key(resultKey).result("导入结果").build());
+ } catch (Exception e) {
+ resultModels.add(ResultModel.builder().key(resultKey).result("导入失败:" + e.getMessage()).build());
+ log.error(String.format("%s-%s-%s 导入失败: %s", o.getKey(), o.getName(), o.getType(), e.getMessage()), e);
+ }
+ }
+
+ @Override
+ public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+ if (!ingredients.isEmpty()) {
+ ingredientRepository.saveAll(ingredients);
+ }
+ EasyExcel.write(outputStream).head(ResultModel.class).excelType(ExcelTypeEnum.XLSX).sheet("导入结果").doWrite(resultModels);
+ }
+ }).sheet().doRead();
+ }
+
+ public void addIngredient(Ingredient ingredient, String operator) {
+ Assert.isTrue(StringUtils.isNotBlank(ingredient.getKey()) &&
+ StringUtils.isNotBlank(ingredient.getName()) &&
+ StringUtils.isNotBlank(ingredient.getType()) &&
+ MapUtils.isNotEmpty(ingredient.getNutrient()) &&
+ enumService.checkCategory(ingredient.getType()) &&
+ ingredient.getNutrient().entrySet().stream().allMatch(x -> enumService.checkNutrient(x.getKey())) &&
+ !ingredientRepository.existsByKeyOrName(ingredient.getKey(), ingredient.getName()),
+ "[参数错误]必填参数未填写,或者编号名称重复、类型和营养素不在取值范围内!");
+
+ Instant dateTime = Instant.now();
+ ingredient.setOperate(operator);
+ ingredient.setCreated(dateTime);
+ ingredient.setModify(dateTime);
+ ingredientRepository.save(ingredient);
+ log.info("[IngredientService] addIngredient name = " + ingredient.getName() + ", operator = " + operator);
+ }
+
+ public void delIngredient(List ingredients, String operator) {
+ ingredients.stream().filter(StringUtils::isNotBlank).forEach(ingredient -> {
+ ingredientRepository.deleteByKey(ingredient);
+ ingredientMarkRepository.deleteByIngredient(ingredient);
+ log.info("[IngredientService] delIngredient ingredient = " + ingredient + ", operator = " + operator);
+ });
+ }
+
+ public void modIngredient(Ingredient ingredient, String operator) {
+ Assert.isTrue(StringUtils.isNotBlank(ingredient.getKey()) &&
+ StringUtils.isNotBlank(ingredient.getName()) &&
+ StringUtils.isNotBlank(ingredient.getType()) &&
+ MapUtils.isNotEmpty(ingredient.getNutrient()) &&
+ enumService.checkCategory(ingredient.getType()) &&
+ ingredient.getNutrient().entrySet().stream().allMatch(x -> enumService.checkNutrient(x.getKey())) &&
+ !ingredientRepository.existsByIdNotAndKeyOrName(ingredient.getId(), ingredient.getKey(), ingredient.getName()),
+ "[参数错误]必填参数未填写,或者编号名称重复、类型和营养素不在取值范围内!");
+ Instant dateTime = Instant.now();
+ ingredient.setOperate(operator);
+ ingredient.setCreated(dateTime);
+ ingredient.setModify(dateTime);
+ ingredientRepository.save(ingredient);
+ log.info("[IngredientService] modIngredient name = " + ingredient.getName() + ", operator = " + operator);
+ }
+
+ public Map getByKeys() {
+ return ingredientRepository.findKeyNameMap().stream().collect(Collectors.toMap(Ingredient::getKey, Ingredient::getName));
+ }
+
+ public List getByKeys(List keys) {
+ return ingredientRepository.findByKeyInOrderByKeyAsc(keys);
+ }
+
+ public List getByKeyword(String keyword) {
+ return ingredientRepository.findByKeyLikeOrNameLikeOrderByKeyAsc(keyword);
+ }
+
+ public List getFullByKeys(Collection keys) {
+ return ingredientRepository.findByKeyIn(keys);
+ }
+
+ public Page> queryIngredientByMark(Long vender, String mark, String key, String type, PageRequest pageRequest) {
+ if (vender <= 0) {
+ if (StringUtils.isBlank(key)) {
+ return StringUtils.isBlank(type) ? ingredientRepository.findAll(pageRequest) : ingredientRepository.findByTypeOrderByIdDesc(type, pageRequest);
+ }
+ if (StringUtils.isNumeric(key)) {
+ return StringUtils.isBlank(type) ? ingredientRepository.findByKeyLikeOrderByIdDesc("%" + key + "%", pageRequest) : ingredientRepository.findByTypeAndKeyLikeOrderByIdDesc(type, "%" + key + "%", pageRequest);
+ } else {
+ return StringUtils.isBlank(type) ? ingredientRepository.findByNameLikeOrderByIdDesc("%" + key + "%", pageRequest) : ingredientRepository.findByTypeAndNameLikeOrderByIdDesc(type, "%" + key + "%", pageRequest);
+ }
+ } else {
+ return ingredientDTORepository.findByVenderAndTypeAndMarkAndKey(vender, type, mark, key, pageRequest);
+ }
+ }
+
+ public Ingredient queryIngredientByKey(String key) {
+ return ingredientRepository.findByKey(key);
+ }
+
+ public boolean existsIngredientByKey(String key) {
+ return ingredientRepository.existsByKey(key);
+ }
+
+ @Transactional
+ public void addMark(MarkType mark, String ingredient, Long vender, String operator) {
+ if (ingredientMarkRepository.updateMarkAndOperateByVenderAndIngredient(mark, operator, vender, ingredient) <= 0) {
+ Instant dateTime = Instant.now();
+ ingredientMarkRepository.save(IngredientMark.builder().mark(mark).ingredient(ingredient).vender(vender).operate(operator).created(dateTime).modify(dateTime).build());
+ }
+ log.info("[IngredientService] addMark ingredient = " + ingredient + ", mark = " + mark + ", operator = " + operator);
+ }
+
+ public void delMark(String ingredient, Long vender, String operator) {
+ ingredientMarkRepository.deleteByVenderAndIngredient(vender, ingredient);
+ log.info("[IngredientService] delMark ingredient = " + ingredient + ", operator = " + operator);
+ }
+
+ public void delMark(Long vender, String operator) {
+ ingredientMarkRepository.deleteByVender(vender);
+ log.info("[IngredientService] delMark vender = " + vender + ", operator = " + operator);
+ }
+}
\ No newline at end of file
diff --git a/diet-core/src/main/java/com/mathvision/diet/service/MenuDishService.java b/diet-core/src/main/java/com/mathvision/diet/service/MenuDishService.java
new file mode 100644
index 0000000..692eebd
--- /dev/null
+++ b/diet-core/src/main/java/com/mathvision/diet/service/MenuDishService.java
@@ -0,0 +1,273 @@
+package com.mathvision.diet.service;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.data.RowRenderData;
+import com.deepoove.poi.data.Rows;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.mathvision.diet.domian.MealType;
+import com.mathvision.diet.domian.MenuDishItemDTO;
+import com.mathvision.diet.entity.Dish;
+import com.mathvision.diet.entity.Menu;
+import com.mathvision.diet.entity.MenuDish;
+import com.mathvision.diet.repository.DishRepository;
+import com.mathvision.diet.repository.MenuDishRepository;
+import com.mathvision.diet.word.ServerTableData;
+import com.mathvision.diet.word.ServerTablePolicy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.io.*;
+import java.math.RoundingMode;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Instant;
+import java.util.*;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@Slf4j
+@Service
+public class MenuDishService {
+ private static final Lock UPDATE_LABEL_LOCK = new ReentrantLock();
+ private static Instant UPDATE_LABEL_TIME;
+
+ @Resource
+ DishRepository dishRepository;
+
+ @Resource
+ MenuDishRepository menuDishRepository;
+
+ @Resource
+ IngredientService ingredientService;
+
+ @Scheduled(cron = "0/5 * * * * *")
+ public void init() {
+ if (!UPDATE_LABEL_LOCK.tryLock()) {
+ return;
+ }
+ try {
+ List dishes = UPDATE_LABEL_TIME == null ? menuDishRepository.findAll() : menuDishRepository.findByModifyGreaterThan(UPDATE_LABEL_TIME.minusMillis(1000));
+ if (dishes.isEmpty()) {
+ return;
+ }
+ UPDATE_LABEL_TIME = Instant.now();
+ dishes.forEach(menuDish -> {
+ Dish dish = dishRepository.findByIdAndVender(menuDish.getDish(), menuDish.getVender());
+ if (dish != null && dish.getLabel() != null) {
+ menuDish.setLabel(dish.getLabel());
+ }
+ });
+ menuDishRepository.saveAll(dishes);
+ } catch (Exception e) {
+ log.error("[MenuDishService] update label exception : " + e.getMessage(), e);
+ } finally {
+ UPDATE_LABEL_LOCK.unlock();
+ }
+ }
+
+ public MenuDish add(MenuDish menuDish) {
+ return menuDishRepository.save(menuDish);
+ }
+
+ @Transactional
+ public List addAll(List menuDishes) {
+ menuDishes.forEach(menuDish -> deleteAll(menuDish.getMenu()));
+ return menuDishRepository.saveAll(menuDishes);
+ }
+
+ public void deleteAll(Long menuId) {
+ menuDishRepository.deleteByMenu(menuId);
+ }
+
+ public void delete(Long menuDishId) {
+ menuDishRepository.deleteById(menuDishId);
+ }
+
+ public MenuDish get(Long id) {
+ return menuDishRepository.findById(id).orElse(null);
+ }
+
+ public MenuDish get(Long id, Long venderId) {
+ return menuDishRepository.findByIdAndVender(id, venderId);
+ }
+
+ public List query(Long menuId) {
+ return menuDishRepository.findByMenu(menuId);
+ }
+
+ public List query(Long menuId, Long vender) {
+ return menuDishRepository.findByMenuAndVender(menuId, vender);
+ }
+
+ public List query(Long menuId, Long vender, Long day) {
+ return menuDishRepository.findByMenuAndVenderAndDay(menuId, vender, day);
+ }
+
+ public List days(Long menuId, Long vender) {
+ return menuDishRepository.distinctDaysByMenuAndVender(menuId, vender);
+ }
+
+ public void export(Menu menu, ExcelWriter excelWriter) {
+ Map>> menuDishes = menuDishRepository.findByMenu(menu.getId()).stream().collect(Collectors.groupingBy(MenuDish::getMeal, Collectors.groupingBy(MenuDish::getDay)));
+ List allMeals = new ArrayList<>(menuDishes.keySet()).stream().sorted(Comparator.comparing(MealType::toType)).collect(Collectors.toList());
+ List allDays = menuDishes.entrySet().stream().flatMap(kv -> kv.getValue().keySet().stream()).distinct().sorted().collect(Collectors.toList());
+ List allCrows = menu.getCrows();
+ if (CollectionUtils.isEmpty(allDays)) {
+ allDays = menu.getDay();
+ }
+
+ List> headers = Lists.newArrayList();
+ headers.add(Lists.newArrayList(""));
+ allDays.forEach(day -> {
+ headers.add(Lists.newArrayList(String.format("第%s天", day), "菜品名称"));
+ headers.add(Lists.newArrayList(String.format("第%s天", day), "食材名称"));
+ allCrows.forEach(crow -> headers.add(Lists.newArrayList(String.format("第%s天", day), crow)));
+ });
+
+ Map keyName = ingredientService.getByKeys();
+ List> contents = Lists.newArrayList();
+ List finalAllDays = allDays;
+ allMeals.forEach(meal -> {
+ int maxDishes = menuDishes.get(meal).values().stream().map(List::size).max(Comparator.naturalOrder()).orElse(0);
+ if (maxDishes <= 0) return;
+ IntStream.rangeClosed(1, maxDishes).forEach(dishIndex -> {
+ List dishes = finalAllDays.stream().map(day -> {
+ List dish = menuDishes.get(meal).get(day);
+ if (dish == null || dish.size() < dishIndex) {
+ return MenuDish.builder().meal(meal).day(day).ingredient(Lists.newArrayList()).build();
+ } else {
+ return dish.get(dishIndex - 1);
+ }
+ }).collect(Collectors.toList());
+
+ int maxItems = dishes.stream().map(item -> item.getIngredient().size()).max(Comparator.naturalOrder()).orElse(0);
+ if (maxItems <= 0) return;
+ IntStream.rangeClosed(1, maxItems).forEach(itemIndex -> {
+ List> items = dishes.stream().map(dish -> {
+ List item = dish.getIngredient();
+ if (item == null || item.size() < itemIndex) {
+ return Pair.of("", MenuDishItemDTO.builder().value(Maps.newHashMap()).build());
+ } else {
+ return Pair.of(dish.getName(), item.get(itemIndex - 1));
+ }
+ }).collect(Collectors.toList());
+
+ List