浏览代码

Merge branch 'dev-cy/end250630'

chenying2100 3 月之前
父节点
当前提交
f86fd1e4b2
共有 18 个文件被更改,包括 367 次插入79 次删除
  1. 10 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/BizConst.java
  2. 3 2
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDiseaseLabelController.java
  3. 22 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRecipeController.java
  4. 18 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysFoodIngredient.java
  5. 2 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRecipe.java
  6. 3 20
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRecipeFoodIngredient.java
  7. 12 4
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRecipeBo.java
  8. 4 14
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRecipeFoodIngredientBo.java
  9. 10 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysFoodIngredientVo.java
  10. 4 18
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRecipeFoodIngredientVo.java
  11. 17 6
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRecipeVo.java
  12. 4 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRecipeFoodIngredientMapper.java
  13. 5 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRecipeService.java
  14. 10 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysFoodIngredientServiceImpl.java
  15. 0 2
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRecipeFoodIngredientServiceImpl.java
  16. 237 4
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRecipeServiceImpl.java
  17. 5 1
      ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRecipeFoodIngredientMapper.xml
  18. 1 4
      script/sql/biz/create.sql

+ 10 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/BizConst.java

@@ -7,6 +7,16 @@ package org.dromara.common.core.constant;
 public interface BizConst {
     String HOSPITAL_ROLE_TYPE = "hospital_role_type";
 
+    String FOOD_UNIT = "food_unit";
+
+    String NUTRIENT_REFERENCE = "nutrient_reference";
+
+    String NUTRIENT_PROTEIN = "nutrient_protein";
+    String NUTRIENT_FAT = "nutrient_fat";
+    String NUTRIENT_CARBOHYDRATE = "nutrient_carbohydrate";
+
+    String DIETARY_TYPES = "dietary_types";
+
     String QNY_CONFIG = "qny_config";
 
     String QNY_MAX_SIZE = "max_size";

+ 3 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDiseaseLabelController.java

@@ -83,8 +83,9 @@ public class SysDiseaseLabelController extends BaseController {
     @Log(title = "疾病/部位标签", businessType = BusinessType.INSERT)
     @RepeatSubmit()
     @PostMapping()
-    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysDiseaseLabelBo bo) {
-        return toAjax(sysDiseaseLabelService.insertByBo(bo));
+    public R<String> add(@Validated(AddGroup.class) @RequestBody SysDiseaseLabelBo bo) {
+        sysDiseaseLabelService.insertByBo(bo);
+        return R.ok("成功!", String.valueOf(bo.getLabelId()));
     }
 
     /**

+ 22 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRecipeController.java

@@ -1,11 +1,17 @@
 package org.dromara.system.controller.system;
 
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
 import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.system.domain.bo.SysRoleBo;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.validation.annotation.Validated;
 import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -56,6 +62,21 @@ public class SysRecipeController extends BaseController {
         ExcelUtil.exportExcel(list, "食谱管理", SysRecipeVo.class, response);
     }
 
+    /**
+     * 状态修改
+     */
+    @SaCheckPermission("system:recipe:edit")
+    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysRecipeBo recipeBo) {
+        if (StrUtil.isBlank(recipeBo.getRecipeIds())) {
+            throw new ServiceException("id不能为空!");
+        }
+        return toAjax(sysRecipeService.updateRecipeStatus(
+            Arrays.stream(recipeBo.getRecipeIds().split(","))
+                .map(Long::valueOf).collect(Collectors.toList()), recipeBo.getStatus()));
+    }
+
     /**
      * 获取食谱管理详细信息
      *
@@ -64,7 +85,7 @@ public class SysRecipeController extends BaseController {
     @SaCheckPermission("system:recipe:query")
     @GetMapping("/{recipeId}")
     public R<SysRecipeVo> getInfo(@NotNull(message = "主键不能为空")
-                                     @PathVariable Long recipeId) {
+                                  @PathVariable Long recipeId) {
         return R.ok(sysRecipeService.queryById(recipeId));
     }
 

+ 18 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysFoodIngredient.java

@@ -184,4 +184,22 @@ public class SysFoodIngredient extends TenantEntity {
 
     @TableField(exist = false)
     private String subCategory;
+
+    /**
+     * 用量(可选,单位自定义)
+     */
+    @TableField(exist = false)
+    private BigDecimal quantity;
+
+    /**
+     * 备注
+     */
+    @TableField(exist = false)
+    private String remark;
+
+    @TableField(exist = false)
+    private BigDecimal caloriesForInput;
+
+    @TableField(exist = false)
+    private String unitName;
 }

+ 2 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRecipe.java

@@ -6,6 +6,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.io.Serial;
+import java.math.BigDecimal;
 
 /**
  * 食谱管理对象 sys_recipe
@@ -50,7 +51,7 @@ public class SysRecipe extends TenantEntity {
     /**
      * 食谱价格
      */
-    private Long price;
+    private BigDecimal price;
 
     /**
      * 适用疾病(可用逗号分隔多个)

+ 3 - 20
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRecipeFoodIngredient.java

@@ -6,6 +6,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.io.Serial;
+import java.math.BigDecimal;
 
 /**
  * 食谱与食材关联对象 sys_recipe_food_ingredient
@@ -40,33 +41,15 @@ public class SysRecipeFoodIngredient extends TenantEntity {
     /**
      * 用量(可选,单位自定义)
      */
-    private Long quantity;
+    private BigDecimal quantity;
 
     /**
      * 热量(kcal)
      */
-    private Long calories;
-
-    /**
-     * 排序(可选)
-     */
-    private Long sort;
+    private BigDecimal calories;
 
     /**
      * 备注
      */
     private String remark;
-
-    /**
-     * 状态(0正常 1停用)
-     */
-    private String status;
-
-    /**
-     * 删除标志(0代表存在 1代表删除)
-     */
-    @TableLogic
-    private String delFlag;
-
-
 }

+ 12 - 4
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRecipeBo.java

@@ -9,6 +9,9 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import jakarta.validation.constraints.*;
 
+import java.math.BigDecimal;
+import java.util.List;
+
 /**
  * 食谱管理业务对象 sys_recipe
  *
@@ -23,9 +26,10 @@ public class SysRecipeBo extends BaseEntity {
     /**
      * 主键ID
      */
-    @NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
     private Long recipeId;
 
+    private String recipeIds;
+
     /**
      * 食谱名称
      */
@@ -35,12 +39,13 @@ public class SysRecipeBo extends BaseEntity {
     /**
      * 食谱分类ID
      */
-    @NotNull(message = "食谱分类ID不能为空", groups = { AddGroup.class, EditGroup.class })
+    @NotNull(message = "食谱分类不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long categoryId;
 
     /**
      * 基本膳食
      */
+    @NotBlank(message = "基本膳食不能为空", groups = { AddGroup.class, EditGroup.class })
     private String baseDiet;
 
     /**
@@ -51,7 +56,8 @@ public class SysRecipeBo extends BaseEntity {
     /**
      * 食谱价格
      */
-    private Long price;
+    @NotNull(message = "食谱价格不能为空", groups = { AddGroup.class, EditGroup.class })
+    private BigDecimal price;
 
     /**
      * 适用疾病(可用逗号分隔多个)
@@ -71,6 +77,7 @@ public class SysRecipeBo extends BaseEntity {
     /**
      * 智能推荐(0否 1是)
      */
+    @NotBlank(message = "智能推荐不能为空", groups = { AddGroup.class, EditGroup.class })
     private String smartRecommend;
 
     /**
@@ -83,5 +90,6 @@ public class SysRecipeBo extends BaseEntity {
      */
     private String status;
 
-
+    @NotEmpty(message = "食材组成不能为空", groups = { AddGroup.class, EditGroup.class })
+    private List<SysRecipeFoodIngredientBo> foodList;
 }

+ 4 - 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRecipeFoodIngredientBo.java

@@ -9,6 +9,8 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import jakarta.validation.constraints.*;
 
+import java.math.BigDecimal;
+
 /**
  * 食谱与食材关联业务对象 sys_recipe_food_ingredient
  *
@@ -41,27 +43,15 @@ public class SysRecipeFoodIngredientBo extends BaseEntity {
     /**
      * 用量(可选,单位自定义)
      */
-    private Long quantity;
+    private BigDecimal quantity;
 
     /**
      * 热量(kcal)
      */
-    private Long calories;
-
-    /**
-     * 排序(可选)
-     */
-    private Long sort;
+    private BigDecimal calories;
 
     /**
      * 备注
      */
     private String remark;
-
-    /**
-     * 状态(0正常 1停用)
-     */
-    private String status;
-
-
 }

+ 10 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysFoodIngredientVo.java

@@ -1,5 +1,6 @@
 package org.dromara.system.domain.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import org.dromara.system.domain.SysFoodIngredient;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
@@ -62,6 +63,8 @@ public class SysFoodIngredientVo implements Serializable {
     @ExcelProperty(value = "单位")
     private String unit;
 
+    private String unitName;
+
     /**
      * 入货价格(元)
      */
@@ -237,4 +240,11 @@ public class SysFoodIngredientVo implements Serializable {
     private String status;
 
 
+    private BigDecimal quantity;
+    /**
+     * 备注
+     */
+    private String remark;
+
+    private BigDecimal caloriesForInput;
 }

+ 4 - 18
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRecipeFoodIngredientVo.java

@@ -1,5 +1,6 @@
 package org.dromara.system.domain.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import org.dromara.system.domain.SysRecipeFoodIngredient;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
@@ -10,6 +11,7 @@ import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 
 
@@ -51,34 +53,18 @@ public class SysRecipeFoodIngredientVo implements Serializable {
      */
     @ExcelProperty(value = "用量", converter = ExcelDictConvert.class)
     @ExcelDictFormat(readConverterExp = "可=选,单位自定义")
-    private Long quantity;
+    private BigDecimal quantity;
 
     /**
      * 热量(kcal)
      */
     @ExcelProperty(value = "热量", converter = ExcelDictConvert.class)
     @ExcelDictFormat(readConverterExp = "k=cal")
-    private Long calories;
-
-    /**
-     * 排序(可选)
-     */
-    @ExcelProperty(value = "排序", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "可=选")
-    private Long sort;
+    private BigDecimal calories;
 
     /**
      * 备注
      */
     @ExcelProperty(value = "备注")
     private String remark;
-
-    /**
-     * 状态(0正常 1停用)
-     */
-    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
-    private String status;
-
-
 }

+ 17 - 6
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRecipeVo.java

@@ -1,17 +1,18 @@
 package org.dromara.system.domain.vo;
 
-import org.dromara.system.domain.SysRecipe;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
-import org.dromara.common.excel.annotation.ExcelDictFormat;
-import org.dromara.common.excel.convert.ExcelDictConvert;
+import com.alibaba.fastjson.JSONObject;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysRecipe;
 
 import java.io.Serial;
 import java.io.Serializable;
-import java.util.Date;
-
+import java.math.BigDecimal;
+import java.util.List;
 
 
 /**
@@ -46,12 +47,16 @@ public class SysRecipeVo implements Serializable {
     @ExcelProperty(value = "食谱分类ID")
     private Long categoryId;
 
+    private String categoryName;
+
     /**
      * 基本膳食
      */
     @ExcelProperty(value = "基本膳食")
     private String baseDiet;
 
+    private String baseDietName;
+
     /**
      * 餐次
      */
@@ -62,7 +67,7 @@ public class SysRecipeVo implements Serializable {
      * 食谱价格
      */
     @ExcelProperty(value = "食谱价格")
-    private Long price;
+    private BigDecimal price;
 
     /**
      * 适用疾病(可用逗号分隔多个)
@@ -105,5 +110,11 @@ public class SysRecipeVo implements Serializable {
     @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
     private String status;
 
+    private List<SysDiseaseLabelVo> avoidDiseaseList;
+
+    private List<SysDiseaseLabelVo> suitableDiseaseList;
+
+    private List<SysFoodIngredientVo> foodList;
 
+    private JSONObject nutrientAnalysis;
 }

+ 4 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRecipeFoodIngredientMapper.java

@@ -1,9 +1,12 @@
 package org.dromara.system.mapper;
 
+import org.dromara.system.domain.SysFoodIngredient;
 import org.dromara.system.domain.SysRecipeFoodIngredient;
 import org.dromara.system.domain.vo.SysRecipeFoodIngredientVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
+import java.util.List;
+
 /**
  * 食谱与食材关联Mapper接口
  *
@@ -11,5 +14,5 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * @date 2025-07-01
  */
 public interface SysRecipeFoodIngredientMapper extends BaseMapperPlus<SysRecipeFoodIngredient, SysRecipeFoodIngredientVo> {
-
+    List<SysFoodIngredient> selectRecipeFood(Long recipeId);
 }

+ 5 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRecipeService.java

@@ -1,5 +1,7 @@
 package org.dromara.system.service;
 
+import com.alibaba.fastjson.JSONObject;
+import org.dromara.common.core.domain.R;
 import org.dromara.system.domain.vo.SysRecipeVo;
 import org.dromara.system.domain.bo.SysRecipeBo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -15,7 +17,7 @@ import java.util.List;
  * @date 2025-07-01
  */
 public interface ISysRecipeService {
-
+    int updateRecipeStatus(List<Long> recipeIds, String status);
     /**
      * 查询食谱管理
      *
@@ -24,6 +26,8 @@ public interface ISysRecipeService {
      */
     SysRecipeVo queryById(Long recipeId);
 
+    R<JSONObject> nutrientAnalysis(Long recipeId);
+
     /**
      * 分页查询食谱管理列表
      *

+ 10 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysFoodIngredientServiceImpl.java

@@ -20,9 +20,12 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.system.config.RedisUtil;
+import org.dromara.system.domain.SysDictData;
 import org.dromara.system.domain.SysDiseaseLabel;
 import org.dromara.system.domain.SysFoodCategory;
+import org.dromara.system.domain.vo.SysDictDataVo;
 import org.dromara.system.mapper.SysFoodCategoryMapper;
+import org.dromara.system.service.ISysDictDataService;
 import org.springframework.stereotype.Service;
 import org.dromara.system.domain.bo.SysFoodIngredientBo;
 import org.dromara.system.domain.vo.SysFoodIngredientVo;
@@ -55,6 +58,8 @@ public class SysFoodIngredientServiceImpl implements ISysFoodIngredientService {
 
     private final SysFoodCategoryMapper categoryMapper;
 
+    private final ISysDictDataService dictDataService;
+
     /**
      * 查询食材管理
      *
@@ -86,6 +91,7 @@ public class SysFoodIngredientServiceImpl implements ISysFoodIngredientService {
                 });
             });
 
+            Map<String, SysDictDataVo> dictDataMap = dictDataService.selectMapByType(BizConst.FOOD_UNIT).getData();
             List<SysFoodCategory> categoryList = categoryMapper.selectList(Wrappers.lambdaQuery(SysFoodCategory.class)
                 .in(SysFoodCategory::getFoodCategoryId, ids));
             Map<String, String> categoryMap = categoryList.stream().collect(Collectors.toMap(k1 -> String.valueOf(k1.getFoodCategoryId()), k2 -> k2.getName(), (k1, k2) -> k1));
@@ -97,6 +103,10 @@ public class SysFoodIngredientServiceImpl implements ISysFoodIngredientService {
                 if (arr.length >= 2) {
                     v.setSubCategory(categoryMap.get(arr[1]));
                 }
+                SysDictDataVo unit = dictDataMap.get(v.getUnit());
+                if (ObjUtil.isNotNull(unit)) {
+                    v.setUnitName(unit.getDictLabel());
+                }
             });
         }
 

+ 0 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRecipeFoodIngredientServiceImpl.java

@@ -78,8 +78,6 @@ public class SysRecipeFoodIngredientServiceImpl implements ISysRecipeFoodIngredi
         lqw.eq(bo.getFoodIngredientId() != null, SysRecipeFoodIngredient::getFoodIngredientId, bo.getFoodIngredientId());
         lqw.eq(bo.getQuantity() != null, SysRecipeFoodIngredient::getQuantity, bo.getQuantity());
         lqw.eq(bo.getCalories() != null, SysRecipeFoodIngredient::getCalories, bo.getCalories());
-        lqw.eq(bo.getSort() != null, SysRecipeFoodIngredient::getSort, bo.getSort());
-        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysRecipeFoodIngredient::getStatus, bo.getStatus());
         return lqw;
     }
 

+ 237 - 4
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRecipeServiceImpl.java

@@ -1,5 +1,15 @@
 package org.dromara.system.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.dromara.common.core.constant.BizConst;
+import org.dromara.common.core.constant.SystemConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -9,16 +19,43 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.system.domain.SysDiseaseLabel;
+import org.dromara.system.domain.SysFoodCategory;
+import org.dromara.system.domain.SysFoodIngredient;
+import org.dromara.system.domain.SysRecipeCategory;
+import org.dromara.system.domain.SysRecipeFoodIngredient;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.bo.SysRecipeFoodIngredientBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.domain.vo.SysDiseaseLabelVo;
+import org.dromara.system.domain.vo.SysFoodCategoryVo;
+import org.dromara.system.domain.vo.SysFoodIngredientVo;
+import org.dromara.system.domain.vo.SysRecipeFoodIngredientVo;
+import org.dromara.system.mapper.SysDiseaseLabelMapper;
+import org.dromara.system.mapper.SysFoodCategoryMapper;
+import org.dromara.system.mapper.SysFoodIngredientMapper;
+import org.dromara.system.mapper.SysRecipeCategoryMapper;
+import org.dromara.system.mapper.SysRecipeFoodIngredientMapper;
+import org.dromara.system.service.ISysDictDataService;
+import org.dromara.system.service.ISysDiseaseLabelService;
+import org.dromara.system.service.ISysRecipeCategoryService;
 import org.springframework.stereotype.Service;
 import org.dromara.system.domain.bo.SysRecipeBo;
 import org.dromara.system.domain.vo.SysRecipeVo;
 import org.dromara.system.domain.SysRecipe;
 import org.dromara.system.mapper.SysRecipeMapper;
 import org.dromara.system.service.ISysRecipeService;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.io.ObjectInput;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Collection;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * 食谱管理Service业务层处理
@@ -32,6 +69,85 @@ import java.util.Collection;
 public class SysRecipeServiceImpl implements ISysRecipeService {
 
     private final SysRecipeMapper baseMapper;
+    private final ISysDictDataService dictDataService;
+    private final SysRecipeCategoryMapper recipeCategoryMapper;
+    private final SysRecipeFoodIngredientMapper sysRecipeFoodIngredientMapper;
+    private final SysDiseaseLabelMapper diseaseLabelMapper;
+    private final SysFoodCategoryMapper foodCategoryMapper;
+    private final SysFoodIngredientMapper foodIngredientMapper;
+
+    @Override
+    public int updateRecipeStatus(List<Long> recipeIds, String status) {
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysRecipe>()
+                .set(SysRecipe::getSmartRecommend, status)
+                .in(SysRecipe::getRecipeId, recipeIds));
+    }
+
+    @Override
+    public R<com.alibaba.fastjson.JSONObject> nutrientAnalysis(Long recipeId) {
+        List<SysRecipeFoodIngredient> recipeFoodIngredientList =
+            sysRecipeFoodIngredientMapper.selectList(Wrappers.lambdaQuery(SysRecipeFoodIngredient.class)
+                .eq(SysRecipeFoodIngredient::getRecipeId, recipeId));
+        if (CollUtil.isEmpty(recipeFoodIngredientList)) {
+            return R.ok();
+        }
+
+        List<SysFoodIngredient> foodIngredientList = foodIngredientMapper.selectList(Wrappers.lambdaQuery(SysFoodIngredient.class)
+            .in(SysFoodIngredient::getFoodIngredientId, recipeFoodIngredientList.stream().map(v -> v.getFoodIngredientId()).collect(Collectors.toList())));
+
+        List<JSONObject> leftList = CollUtil.newArrayList();
+        List<JSONObject> rightList = CollUtil.newArrayList();
+        List<JSONObject> pieList = CollUtil.newArrayList();
+        List<JSONObject> pieLegendList = CollUtil.newArrayList();
+
+        JSONObject protein = new JSONObject();
+        JSONObject fat = new JSONObject();
+        JSONObject carbohydrate = new JSONObject();
+        BigDecimal treeNutrient = BigDecimal.ZERO;
+        for (SysFoodIngredient v : foodIngredientList) {
+            protein.put("val", protein.getBigDecimal("val", BigDecimal.ZERO).add(v.getProtein()).setScale(4, BigDecimal.ROUND_HALF_UP));
+            treeNutrient = treeNutrient.add(protein.getBigDecimal("val"));
+
+            fat.put("val", fat.getBigDecimal("val", BigDecimal.ZERO).add(v.getFat()).setScale(4, BigDecimal.ROUND_HALF_UP));
+            treeNutrient = treeNutrient.add(fat.getBigDecimal("val"));
+
+            carbohydrate.put("val", carbohydrate.getBigDecimal("val", BigDecimal.ZERO).add(v.getCarbohydrate()).setScale(4, BigDecimal.ROUND_HALF_UP));
+            treeNutrient = treeNutrient.add(carbohydrate.getBigDecimal("val"));
+        }
+
+        if (treeNutrient.equals(BigDecimal.ZERO)) {
+            protein.put("ratio", BigDecimal.ZERO);
+            fat.put("ratio", BigDecimal.ZERO);
+            carbohydrate.put("ratio", BigDecimal.ZERO);
+        } else {
+            protein.put("ratio", protein.getBigDecimal("val", BigDecimal.ZERO).divide(treeNutrient).setScale(2, BigDecimal.ROUND_HALF_UP));
+            fat.put("ratio", protein.getBigDecimal("val", BigDecimal.ZERO).divide(treeNutrient).setScale(2, BigDecimal.ROUND_HALF_UP));
+            carbohydrate.put("ratio", protein.getBigDecimal("val", BigDecimal.ZERO).divide(treeNutrient).setScale(2, BigDecimal.ROUND_HALF_UP));
+        }
+
+        Map<String, SysDictDataVo> dictDataVoMap = dictDataService.selectMapByType(BizConst.NUTRIENT_REFERENCE).getData();
+        SysDictDataVo nutrientProtein = dictDataVoMap.get(BizConst.NUTRIENT_PROTEIN);
+        SysDictDataVo nutrientFat = dictDataVoMap.get(BizConst.NUTRIENT_FAT);
+        SysDictDataVo nutrientCarbohydrate = dictDataVoMap.get(BizConst.NUTRIENT_CARBOHYDRATE);
+
+        protein.put("name", nutrientProtein.getRemark());
+        fat.put("name", nutrientFat.getRemark());
+        carbohydrate.put("name", nutrientCarbohydrate.getRemark());
+
+        protein.put("referenceValue", nutrientProtein.getDictValue());
+        fat.put("referenceValue", nutrientFat.getDictValue());
+        carbohydrate.put("referenceValue", nutrientCarbohydrate.getDictValue());
+
+        leftList.add(protein);
+        leftList.add(fat);
+        leftList.add(carbohydrate);
+
+        com.alibaba.fastjson.JSONObject result = new com.alibaba.fastjson.JSONObject();
+        result.put("left", leftList);
+
+        return R.ok(result);
+    }
 
     /**
      * 查询食谱管理
@@ -40,8 +156,83 @@ public class SysRecipeServiceImpl implements ISysRecipeService {
      * @return 食谱管理
      */
     @Override
-    public SysRecipeVo queryById(Long recipeId){
-        return baseMapper.selectVoById(recipeId);
+    public SysRecipeVo queryById(Long recipeId) {
+        SysRecipeVo vo = baseMapper.selectVoById(recipeId);
+        Set<String> diseaseLabelIdList = CollUtil.newHashSet();
+        Map<String, List<SysDictDataVo>> dictDataMap = dictDataService.selectGroupByType(List.of(BizConst.DIETARY_TYPES, BizConst.FOOD_UNIT)).getData();
+        Map<String, SysDictDataVo> foodUnitMap = dictDataMap.get(BizConst.FOOD_UNIT).stream().collect(Collectors.toMap(v -> v.getDictValue(), v -> v, (k, v) -> k));
+        Map<String, SysDictDataVo> dietaryTypesMap = dictDataMap.get(BizConst.DIETARY_TYPES).stream().collect(Collectors.toMap(v -> v.getDictValue(), v -> v, (k, v) -> k));
+
+        if (StrUtil.isNotBlank(vo.getAvoidDisease())) {
+            diseaseLabelIdList.addAll(Arrays.stream(vo.getAvoidDisease().split(",")).collect(Collectors.toList()));
+        }
+        if (StrUtil.isNotBlank(vo.getSuitableDisease())) {
+            diseaseLabelIdList.addAll(Arrays.stream(vo.getSuitableDisease().split(",")).collect(Collectors.toList()));
+        }
+        if (CollUtil.isNotEmpty(diseaseLabelIdList)) {
+            List<SysDiseaseLabel> diseaseLabelList = diseaseLabelMapper.selectList(Wrappers.lambdaQuery(SysDiseaseLabel.class)
+                .select(SysDiseaseLabel::getLabelId, SysDiseaseLabel::getLabelName, SysDiseaseLabel::getLabelCode, SysDiseaseLabel::getCategory)
+                .in(SysDiseaseLabel::getLabelId, diseaseLabelIdList));
+
+            Map<String, SysDiseaseLabelVo> diseaseLabelMap = diseaseLabelList
+                .stream().map(v -> MapstructUtils.convert(v, SysDiseaseLabelVo.class))
+                .collect(Collectors.toMap(k -> String.valueOf(k.getLabelId()), v -> v, (k, v) -> k));
+
+            vo.setAvoidDiseaseList(Arrays.stream(vo.getAvoidDisease().split(",")).map(v -> {
+                SysDiseaseLabelVo labelVo = diseaseLabelMap.get(v);
+                if (ObjUtil.isNotNull(labelVo)) {
+                    SysDictDataVo dataVo = dietaryTypesMap.get(labelVo.getCategory());
+                    if (ObjUtil.isNotNull(dataVo)) {
+                        labelVo.setCategoryName(dataVo.getDictLabel());
+                    }
+                }
+                return labelVo;
+            }).collect(Collectors.toList()));
+
+            vo.setSuitableDiseaseList(Arrays.stream(vo.getSuitableDisease().split(",")).map(v -> {
+                SysDiseaseLabelVo labelVo = diseaseLabelMap.get(v);
+                if (ObjUtil.isNotNull(labelVo)) {
+                    SysDictDataVo dataVo = dietaryTypesMap.get(labelVo.getCategory());
+                    if (ObjUtil.isNotNull(dataVo)) {
+                        labelVo.setCategoryName(dataVo.getDictLabel());
+                    }
+                }
+                return labelVo;
+            }).collect(Collectors.toList()));
+
+            List<SysFoodIngredient> foodIngredientList = sysRecipeFoodIngredientMapper.selectRecipeFood(recipeId);
+            if (CollUtil.isNotEmpty(foodIngredientList)) {
+                Set<String> categoryIdList = CollUtil.newHashSet();
+                foodIngredientList.forEach(foodIngredient -> {
+                    if (StrUtil.isNotBlank(foodIngredient.getFoodCategoryId())) {
+                        categoryIdList.addAll(Arrays.stream(foodIngredient.getFoodCategoryId().split(",")).collect(Collectors.toList()));
+                    }
+                });
+
+                Map<String, String> foodCategoryMap = foodCategoryMapper.selectList(Wrappers.lambdaQuery(SysFoodCategory.class)
+                        .select(SysFoodCategory::getFoodCategoryId, SysFoodCategory::getName)
+                        .in(SysFoodCategory::getFoodCategoryId, categoryIdList))
+                    .stream().collect(Collectors.toMap(k -> String.valueOf(k.getFoodCategoryId()), v -> v.getName(), (k, v) -> k));
+
+                foodIngredientList.forEach(foodIngredient -> {
+                    if (StrUtil.isNotBlank(foodIngredient.getFoodCategoryId())) {
+                        Arrays.stream(foodIngredient.getFoodCategoryId().split(",")).forEach(v -> {
+                            foodIngredient.setSubCategory(foodCategoryMap.get(v));
+                        });
+                    }
+
+                    SysDictDataVo dataVo = foodUnitMap.get(foodIngredient.getUnit());
+                    if (ObjUtil.isNotNull(dataVo)) {
+                        foodIngredient.setUnitName(dataVo.getDictLabel());
+                    }
+                });
+            }
+            vo.setFoodList(MapstructUtils.convert(foodIngredientList, SysFoodIngredientVo.class));
+        }
+
+//        vo.setNutrientAnalysis(nutrientAnalysis(recipeId).getData());
+
+        return vo;
     }
 
     /**
@@ -55,6 +246,22 @@ public class SysRecipeServiceImpl implements ISysRecipeService {
     public TableDataInfo<SysRecipeVo> queryPageList(SysRecipeBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<SysRecipe> lqw = buildQueryWrapper(bo);
         Page<SysRecipeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+
+        if (CollUtil.isNotEmpty(result.getRecords())) {
+            Map<String, SysDictDataVo> dietaryTypesMap = dictDataService.selectMapByType(BizConst.DIETARY_TYPES).getData();
+            Map<Long, String> recipeCategoryMap = recipeCategoryMapper.selectList(Wrappers.lambdaQuery(SysRecipeCategory.class)
+                    .select(SysRecipeCategory::getRecipeCategoryId, SysRecipeCategory::getName)
+                    .in(SysRecipeCategory::getRecipeCategoryId, result.getRecords().stream().map(SysRecipeVo::getCategoryId).collect(Collectors.toList())))
+                .stream().collect(Collectors.toMap(k1 -> k1.getRecipeCategoryId(), k2 -> k2.getName(), (k1, k2) -> k1));
+
+            result.getRecords().forEach(v -> {
+                SysDictDataVo dataVo = dietaryTypesMap.get(v.getBaseDiet());
+                if (ObjUtil.isNotNull(dataVo)) {
+                    v.setBaseDietName(dataVo.getDictLabel());
+                }
+                v.setCategoryName(recipeCategoryMap.get(v.getCategoryId()));
+            });
+        }
         return TableDataInfo.build(result);
     }
 
@@ -95,11 +302,21 @@ public class SysRecipeServiceImpl implements ISysRecipeService {
      * @return 是否新增成功
      */
     @Override
+    @Transactional
     public Boolean insertByBo(SysRecipeBo bo) {
         SysRecipe add = MapstructUtils.convert(bo, SysRecipe.class);
         validEntityBeforeSave(add);
         boolean flag = baseMapper.insert(add) > 0;
         if (flag) {
+            List<SysRecipeFoodIngredient> fList = bo.getFoodList().stream().map(food -> {
+                SysRecipeFoodIngredient foodIngredient = MapstructUtils.convert(food, SysRecipeFoodIngredient.class);
+                if (ObjUtil.isNull(foodIngredient.getQuantity())) {
+                    throw new ServiceException("食材用量不能为空");
+                }
+                foodIngredient.setRecipeId(add.getRecipeId());
+                return foodIngredient;
+            }).collect(Collectors.toList());
+            sysRecipeFoodIngredientMapper.insertBatch(fList);
             bo.setRecipeId(add.getRecipeId());
         }
         return flag;
@@ -112,16 +329,32 @@ public class SysRecipeServiceImpl implements ISysRecipeService {
      * @return 是否修改成功
      */
     @Override
+    @Transactional
     public Boolean updateByBo(SysRecipeBo bo) {
+        if (ObjUtil.isNull(bo.getRecipeId())) {
+            throw new ServiceException("膳食Id不能为空");
+        }
         SysRecipe update = MapstructUtils.convert(bo, SysRecipe.class);
         validEntityBeforeSave(update);
+        sysRecipeFoodIngredientMapper.delete(Wrappers.lambdaUpdate(SysRecipeFoodIngredient.class)
+            .eq(SysRecipeFoodIngredient::getRecipeId, bo.getRecipeId()));
+
+        List<SysRecipeFoodIngredient> fList = bo.getFoodList().stream().map(food -> {
+            SysRecipeFoodIngredient foodIngredient = MapstructUtils.convert(food, SysRecipeFoodIngredient.class);
+            if (ObjUtil.isNull(foodIngredient.getQuantity())) {
+                throw new ServiceException("食材用量不能为空");
+            }
+            foodIngredient.setRecipeId(bo.getRecipeId());
+            return foodIngredient;
+        }).collect(Collectors.toList());
+        sysRecipeFoodIngredientMapper.insertBatch(fList);
         return baseMapper.updateById(update) > 0;
     }
 
     /**
      * 保存前的数据校验
      */
-    private void validEntityBeforeSave(SysRecipe entity){
+    private void validEntityBeforeSave(SysRecipe entity) {
         //TODO 做一些数据校验,如唯一约束
     }
 
@@ -134,7 +367,7 @@ public class SysRecipeServiceImpl implements ISysRecipeService {
      */
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
-        if(isValid){
+        if (isValid) {
             //TODO 做一些业务上的校验,判断是否需要校验
         }
         return baseMapper.deleteByIds(ids) > 0;

+ 5 - 1
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRecipeFoodIngredientMapper.xml

@@ -3,5 +3,9 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.dromara.system.mapper.SysRecipeFoodIngredientMapper">
-
+    <select id="selectRecipeFood" resultType="org.dromara.system.domain.SysFoodIngredient">
+        select f.*, c.quantity,c.remark,c.calories caloriesForInput
+        from sys_food_ingredient f join sys_recipe_food_ingredient c on c.food_ingredient_id=f.food_ingredient_id
+        where c.recipe_id=#{recipeId} and f.del_flag='0'
+    </select>
 </mapper>

+ 1 - 4
script/sql/biz/create.sql

@@ -154,7 +154,7 @@ CREATE TABLE sys_recipe (
     suitable_disease  VARCHAR(255) DEFAULT NULL COMMENT '适用疾病(可用逗号分隔多个)',
     avoid_disease     VARCHAR(255) DEFAULT NULL COMMENT '忌食病症(可用逗号分隔多个)',
     suitable_dept     VARCHAR(255) DEFAULT NULL COMMENT '适用科室(可用逗号分隔多个)',
-    smart_recommend   char(1) DEFAULT 1 COMMENT '智能推荐(0否 1是)',
+    smart_recommend  CHAR(1)  default '0' null comment '智能推荐(1否 0是)',
     cooking_method    VARCHAR(255) DEFAULT NULL COMMENT '制作方式',
 
     -- 系统字段
@@ -176,12 +176,9 @@ CREATE TABLE sys_recipe_food_ingredient (
     food_ingredient_id  BIGINT NOT NULL COMMENT '食材ID',
     quantity            DECIMAL(10,2) DEFAULT 0.00 COMMENT '用量(可选,单位自定义)',
     calories            DECIMAL(10,2) DEFAULT 0.00 COMMENT '热量(kcal)',
-    sort                INT DEFAULT 0 COMMENT '排序(可选)',
     remark              VARCHAR(255) DEFAULT NULL COMMENT '备注',
 
     -- 系统字段
-    status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
-    del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
     create_dept  bigint null comment '创建部门',
     create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
     create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',