chenying2100 před 2 měsíci
rodič
revize
d0679498b7

+ 235 - 0
.specstory/history/2025-06-24_02-08-调整表单label宽度以完全显示.md

@@ -2411,7 +2411,242 @@ _**User**_
 
 _**Assistant**_
 
+当前端从后端(Java等)获取到 long 类型(如 Java 的 `Long`,超过 16 位数字)时,**JavaScript 的 Number 类型无法精确表示大整数**,会出现精度丢失(数值失真)问题。
 
+---
+
+## 解决方案
+
+### 1. **后端返回字符串**
+最推荐的做法是:**后端将 long 类型转为字符串返回**,前端用字符串接收和传递,只有在需要时才转为 `BigInt`。
+
+#### Java 后端示例(Jackson):
+```java
+@JsonSerialize(using = ToStringSerializer.class)
+private Long id;
+```
+这样返回的 JSON 是 `"id": "1234567890123456789"`。
+
+---
+
+### 2. **前端用 BigInt 处理**
+如果后端已经返回字符串,前端可以直接用 `BigInt` 处理:
+
+```js
+const id = BigInt(res.data.id); // 或 map(id => BigInt(id))
+```
+
+---
+
+### 3. **如果后端返回的是数字**
+如果后端返回的是数字(如 `1234567890123456789`),**前端无法避免精度丢失**,只能让后端改为返回字符串。
+
+---
+
+## 你的场景建议
+
+- **让后端返回字符串类型的 long 字段**(如 id、foodCategoryId 等)。
+- 前端接收后,转为 `BigInt`,如:
+  ```js
+  form.value.foodCategoryIds = res.data.foodCategoryId
+    ? res.data.foodCategoryId.toString().split(',').map(id => BigInt(id))
+    : [];
+  ```
+
+---
+
+## 总结
+
+- **后端 long → 字符串 → 前端 BigInt**,这样不会失真。
+- 如果后端返回的是数字,前端无法保证精度,必须让后端配合。
+
+---
+
+如需具体代码示例或后端配置方法,请告知你的后端技术栈(如 Spring Boot、MyBatis 等),我可以给出详细方案!
+
+---
+
+_**User**_
+
+为我生成 食谱分类管理 和 食谱管理   建表sql
+
+---
+
+_**Assistant**_
+
+根据你提供的字段信息,下面是“食谱分类管理”和“食谱管理”两张表的建表 SQL 示例,字段类型和约束已做合理设计,可根据实际业务需求调整。
+
+---
+
+### 1. 食谱分类管理表(recipe_category)
+
+```sql
+CREATE TABLE recipe_category (
+    id              BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    name            VARCHAR(100) NOT NULL COMMENT '食谱分类名称',
+    parent_id       BIGINT DEFAULT NULL COMMENT '上级分类ID(如有多级分类)',
+    sort            INT DEFAULT 0 COMMENT '排序',
+    status          TINYINT DEFAULT 1 COMMENT '状态(1正常 0停用)',
+    create_time     DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    update_time     DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    remark          VARCHAR(255) DEFAULT NULL COMMENT '备注'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱分类管理表';
+```
+
+---
+
+### 2. 食谱管理表(recipe)
+
+```sql
+CREATE TABLE recipe (
+    id                BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    name              VARCHAR(100) NOT NULL COMMENT '食谱名称',
+    category_id       BIGINT NOT NULL COMMENT '食谱分类ID',
+    base_diet         VARCHAR(100) DEFAULT NULL COMMENT '基本膳食',
+    meal_time         VARCHAR(100) DEFAULT NULL COMMENT '餐次',
+    price             DECIMAL(10,2) DEFAULT 0.00 COMMENT '食谱价格',
+    suitable_disease  VARCHAR(255) DEFAULT NULL COMMENT '适用疾病(可用逗号分隔多个)',
+    avoid_disease     VARCHAR(255) DEFAULT NULL COMMENT '忌食病症(可用逗号分隔多个)',
+    suitable_dept     VARCHAR(255) DEFAULT NULL COMMENT '适用科室(可用逗号分隔多个)',
+    smart_recommend   TINYINT DEFAULT 0 COMMENT '智能推荐(0否 1是)',
+    cooking_method    VARCHAR(255) DEFAULT NULL COMMENT '制作方式',
+    status            TINYINT DEFAULT 1 COMMENT '状态(1正常 0停用)',
+    create_time       DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    update_time       DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    remark            VARCHAR(255) DEFAULT NULL COMMENT '备注',
+    INDEX idx_category_id (category_id),
+    FOREIGN KEY (category_id) REFERENCES recipe_category(id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱管理表';
+```
+
+---
+
+### 字段说明
+
+- `recipe_category`:支持多级分类(如有需要),可自行扩展。
+- `recipe`:
+  - `base_diet`:基本膳食
+  - `meal_time`:餐次
+  - `suitable_disease`、`avoid_disease`、`suitable_dept`:如有多选可用逗号分隔
+  - `smart_recommend`:是否智能推荐(布尔型)
+  - `cooking_method`:制作方式
+  - 其他为常规管理字段
+
+---
+
+如需进一步细化(如多对多关系、字典表等),请补充说明!
+
+---
+
+_**User**_
+
+为我创建 sys_food_ingredient 和 sys_recipe 关联表
+
+---
+
+_**Assistant**_
+
+下面是 `sys_food_ingredient` 和 `sys_recipe` 的关联表 SQL 设计。  
+假设一个食谱可以包含多个食材,一个食材也可以被多个食谱引用(多对多关系),推荐如下设计:
+
+---
+
+```sql
+CREATE TABLE sys_recipe_food_ingredient (
+    id                BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    recipe_id         BIGINT NOT NULL COMMENT '食谱ID',
+    food_ingredient_id BIGINT NOT NULL COMMENT '食材ID',
+    quantity          DECIMAL(10,2) DEFAULT 0.00 COMMENT '用量(可选,单位自定义)',
+    unit              VARCHAR(20) DEFAULT NULL COMMENT '用量单位(如g、ml等,可选)',
+    sort              INT DEFAULT 0 COMMENT '排序(可选)',
+    create_time       DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    update_time       DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    remark            VARCHAR(255) DEFAULT NULL COMMENT '备注',
+    UNIQUE KEY uniq_recipe_food (recipe_id, food_ingredient_id),
+    INDEX idx_recipe_id (recipe_id),
+    INDEX idx_food_ingredient_id (food_ingredient_id),
+    FOREIGN KEY (recipe_id) REFERENCES sys_recipe(id),
+    FOREIGN KEY (food_ingredient_id) REFERENCES sys_food_ingredient(id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱与食材关联表';
+```
+
+---
+
+### 字段说明
+
+- `recipe_id`:关联 `sys_recipe` 主键
+- `food_ingredient_id`:关联 `sys_food_ingredient` 主键
+- `quantity`、`unit`:可选,记录该食材在该食谱中的用量及单位
+- `sort`:可选,表示在食谱中的顺序
+- `UNIQUE KEY uniq_recipe_food (recipe_id, food_ingredient_id)`:防止重复关联
+
+如需更复杂的用量单位、备注等,可继续扩展字段。  
+如有特殊需求请补充说明!
+
+---
+
+_**User**_
+
+为我生成 sys_food_ingredient 和 sys_recipe 关联表建表sql
+
+---
+
+_**Assistant**_
+
+下面是 `sys_food_ingredient` 和 `sys_recipe` 的多对多关联表建表 SQL:
+
+```sql
+CREATE TABLE sys_recipe_food_ingredient (
+    id                  BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    recipe_id           BIGINT NOT NULL COMMENT '食谱ID',
+    food_ingredient_id  BIGINT NOT NULL COMMENT '食材ID',
+    quantity            DECIMAL(10,2) DEFAULT 0.00 COMMENT '用量(可选,单位自定义)',
+    unit                VARCHAR(20) DEFAULT NULL COMMENT '用量单位(如g、ml等,可选)',
+    sort                INT DEFAULT 0 COMMENT '排序(可选)',
+    create_time         DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    update_time         DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    remark              VARCHAR(255) DEFAULT NULL COMMENT '备注',
+    UNIQUE KEY uniq_recipe_food (recipe_id, food_ingredient_id),
+    INDEX idx_recipe_id (recipe_id),
+    INDEX idx_food_ingredient_id (food_ingredient_id),
+    FOREIGN KEY (recipe_id) REFERENCES sys_recipe(id),
+    FOREIGN KEY (food_ingredient_id) REFERENCES sys_food_ingredient(id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱与食材关联表';
+```
+
+---
+
+**说明:**
+- `recipe_id` 关联 `sys_recipe` 主键
+- `food_ingredient_id` 关联 `sys_food_ingredient` 主键
+- `quantity`、`unit` 可选,记录该食材在该食谱中的用量及单位
+- `sort` 可选,表示在食谱中的顺序
+- `UNIQUE KEY` 保证同一食谱和食材不重复关联
+- `FOREIGN KEY` 保证数据完整性
+
+如需进一步扩展字段或有特殊需求,请补充说明!
+
+---
+
+_**User**_
+
+为我加一个热量字段
+
+---
+
+_**Assistant**_
+
+```diff
+      quantity            DECIMAL(10,2) DEFAULT 0.00 COMMENT '用量(可选,单位自定义)',
+      unit                VARCHAR(20) DEFAULT NULL COMMENT '用量单位(如g、ml等,可选)',
++     calories            DECIMAL(10,2) DEFAULT 0.00 COMMENT '热量(kcal)',
+      sort                INT DEFAULT 0 COMMENT '排序(可选)',
+      create_time         DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+```
+
+---
+
+已为
 
 ---
 

+ 109 - 13
info.txt

@@ -1,26 +1,123 @@
-食材分类
-  分类名称
-  上级分类
+食谱分类管理   
+  食谱分类名称: 
 
- 
+  CREATE TABLE sys_recipe_category (
+    recipe_category_id     BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    tenant_id varchar(20) default '000000' null comment '租户编号',
+    name            VARCHAR(100) NOT NULL COMMENT '食谱分类名称',     
+    sort            INT DEFAULT 0 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 '创建时间',
+    update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱分类管理表';
+
+食谱管理
+  基本膳食
+  餐次
+  食谱名称 
+  食谱分类: 
+  食谱价格: 
+  适用疾病: 
+  忌食病症: 
+  适用科室: 
+  智能推荐:
+  制作方式:  
+
+
+CREATE TABLE sys_recipe (
+    recipe_id         BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    tenant_id  varchar(20) default '000000' null comment '租户编号',
+    name              VARCHAR(100) NOT NULL COMMENT '食谱名称',
+    category_id       BIGINT NOT NULL COMMENT '食谱分类ID',
+    base_diet         VARCHAR(100) DEFAULT NULL COMMENT '基本膳食',
+    meal_time         VARCHAR(100) DEFAULT NULL COMMENT '餐次',
+    price             DECIMAL(10,2) DEFAULT 0.00 COMMENT '食谱价格',
+    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 0 COMMENT '智能推荐(0否 1是)',
+    cooking_method    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 '创建时间',
+    update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱管理表';
 
+ 
 
+CREATE TABLE sys_recipe_food_ingredient (
+    id                  BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    recipe_id           BIGINT NOT NULL COMMENT '食谱ID',
+    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 '创建时间',
+    update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱与食材关联表';
 
-CREATE TABLE sys_food_category (
-    food_category_id  BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+-- 食材管理表
+CREATE TABLE sys_food_ingredient (
+    food_ingredient_id     BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    food_category_id       BIGINT NOT NULL COMMENT '食材分类ID',
     tenant_id varchar(20) default '000000' null comment '租户编号',
-    name          VARCHAR(100) NOT NULL COMMENT '分类名称',
-    parent_id     BIGINT DEFAULT '0' COMMENT '上级分类ID',
-    sort          INT DEFAULT 0 COMMENT '排序',
+    name                  VARCHAR(100) NOT NULL COMMENT '食材名称',
+    code                  VARCHAR(50) NOT NULL COMMENT '食材编码',
+    unit                  VARCHAR(20) NOT NULL COMMENT '单位',
+    purchase_price        DECIMAL(10,2) DEFAULT 0.00 COMMENT '入货价格(元)',
+    edible_ratio          DECIMAL(5,2) DEFAULT 100.00 COMMENT '食材可食比例构成(%)',
+    shelf_life            INT DEFAULT 0 COMMENT '保质期(天)',
+    stock_warning         DECIMAL(10,2) DEFAULT 0.00 COMMENT '库存预警值(g)',
+    expiry_warning        INT DEFAULT 0 COMMENT '保质期预警(天)',
+    description           TEXT COMMENT '食材描述',
+    
+    -- 营养成分
+    calories              DECIMAL(8,2) DEFAULT 0.00 COMMENT '热量(kcal)',
+    protein               DECIMAL(8,2) DEFAULT 0.00 COMMENT '蛋白质(g)',
+    fat                   DECIMAL(8,2) DEFAULT 0.00 COMMENT '脂肪(g)',
+    carbohydrate          DECIMAL(8,2) DEFAULT 0.00 COMMENT '碳水化合物(g)',
+    water                 DECIMAL(8,2) DEFAULT 0.00 COMMENT '水分(ml)',
+    vitamin_a             DECIMAL(8,2) DEFAULT 0.00 COMMENT '维生素A(μg)',
+    vitamin_b2            DECIMAL(8,2) DEFAULT 0.00 COMMENT '维生素B2(mg)',
+    vitamin_c             DECIMAL(8,2) DEFAULT 0.00 COMMENT '维生素C(mg)',
+    sodium                DECIMAL(8,2) DEFAULT 0.00 COMMENT '钠(mg)',
+    iron                  DECIMAL(8,2) DEFAULT 0.00 COMMENT '铁(mg)',
+    phosphorus            DECIMAL(8,2) DEFAULT 0.00 COMMENT '磷(mg)',
+    dietary_fiber         DECIMAL(8,2) DEFAULT 0.00 COMMENT '膳食纤维(g)',
+    vitamin_b1            DECIMAL(8,2) DEFAULT 0.00 COMMENT '维生素B1(mg)',
+    niacin                DECIMAL(8,2) DEFAULT 0.00 COMMENT '烟酸(mg)',
+    vitamin_e             DECIMAL(8,2) DEFAULT 0.00 COMMENT '维生素E(mg)',
+    calcium               DECIMAL(8,2) DEFAULT 0.00 COMMENT '钙(mg)',
+    potassium             DECIMAL(8,2) DEFAULT 0.00 COMMENT '钾(mg)',
+    cholesterol           DECIMAL(8,2) DEFAULT 0.00 COMMENT '胆固醇(g)',
+
+    -- 系统字段
     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 '创建时间',
     update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食材分类表';
-
+    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食材管理表';
  
 
 
@@ -32,4 +129,3 @@ CREATE TABLE sys_food_category (
 
 
 
-

+ 63 - 0
src/api/system/recipe/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { RecipeVO, RecipeForm, RecipeQuery } from '@/api/system/recipe/types';
+
+/**
+ * 查询食谱管理列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listRecipe = (query?: RecipeQuery): AxiosPromise<RecipeVO[]> => {
+  return request({
+    url: '/system/recipe/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询食谱管理详细
+ * @param recipeId
+ */
+export const getRecipe = (recipeId: string | number): AxiosPromise<RecipeVO> => {
+  return request({
+    url: '/system/recipe/' + recipeId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增食谱管理
+ * @param data
+ */
+export const addRecipe = (data: RecipeForm) => {
+  return request({
+    url: '/system/recipe',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改食谱管理
+ * @param data
+ */
+export const updateRecipe = (data: RecipeForm) => {
+  return request({
+    url: '/system/recipe',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除食谱管理
+ * @param recipeId
+ */
+export const delRecipe = (recipeId: string | number | Array<string | number>) => {
+  return request({
+    url: '/system/recipe/' + recipeId,
+    method: 'delete'
+  });
+};

+ 193 - 0
src/api/system/recipe/types.ts

@@ -0,0 +1,193 @@
+export interface RecipeVO {
+  /**
+   * 主键ID
+   */
+  recipeId: string | number;
+
+  /**
+   * 食谱名称
+   */
+  name: string;
+
+  /**
+   * 食谱分类ID
+   */
+  categoryId: string | number;
+
+  /**
+   * 基本膳食
+   */
+  baseDiet: string;
+
+  /**
+   * 餐次
+   */
+  mealTime: string;
+
+  /**
+   * 食谱价格
+   */
+  price: number;
+
+  /**
+   * 适用疾病(可用逗号分隔多个)
+   */
+  suitableDisease: string;
+
+  /**
+   * 忌食病症(可用逗号分隔多个)
+   */
+  avoidDisease: string | number;
+
+  /**
+   * 适用科室(可用逗号分隔多个)
+   */
+  suitableDept: string;
+
+  /**
+   * 智能推荐(0否 1是)
+   */
+  smartRecommend: string;
+
+  /**
+   * 制作方式
+   */
+  cookingMethod: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+}
+
+export interface RecipeForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  recipeId?: string | number;
+
+  /**
+   * 食谱名称
+   */
+  name?: string;
+
+  /**
+   * 食谱分类ID
+   */
+  categoryId?: string | number;
+
+  /**
+   * 基本膳食
+   */
+  baseDiet?: string;
+
+  /**
+   * 餐次
+   */
+  mealTime?: string;
+
+  mealTimes?: Array<string>
+
+  /**
+   * 食谱价格
+   */
+  price?: number;
+
+  /**
+   * 适用疾病(可用逗号分隔多个)
+   */
+  suitableDisease?: string;
+
+  /**
+   * 忌食病症(可用逗号分隔多个)
+   */
+  avoidDisease?: string | number;
+
+  /**
+   * 适用科室(可用逗号分隔多个)
+   */
+  suitableDept?: string;
+
+  /**
+   * 智能推荐(0否 1是)
+   */
+  smartRecommend?: string;
+
+  /**
+   * 制作方式
+   */
+  cookingMethod?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+}
+
+export interface RecipeQuery extends PageQuery {
+
+  /**
+   * 食谱名称
+   */
+  name?: string;
+
+  /**
+   * 食谱分类ID
+   */
+  categoryId?: string | number;
+
+  /**
+   * 基本膳食
+   */
+  baseDiet?: string;
+
+  /**
+   * 餐次
+   */
+  mealTime?: string;
+
+  /**
+   * 食谱价格
+   */
+  price?: number;
+
+  /**
+   * 适用疾病(可用逗号分隔多个)
+   */
+  suitableDisease?: string;
+
+  /**
+   * 忌食病症(可用逗号分隔多个)
+   */
+  avoidDisease?: string | number;
+
+  /**
+   * 适用科室(可用逗号分隔多个)
+   */
+  suitableDept?: string;
+
+  /**
+   * 智能推荐(0否 1是)
+   */
+  smartRecommend?: string;
+
+  /**
+   * 制作方式
+   */
+  cookingMethod?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 3 - 2
src/views/system/dept/index.vue

@@ -278,7 +278,7 @@ const handleToggleExpandAll = () => {
 const toggleExpandAll = (data: DeptVO[], status: boolean) => {
   data.forEach((item) => {
     deptTableRef.value?.toggleRowExpansion(item, status);
-    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
+    // if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
   });
 };
 
@@ -362,7 +362,8 @@ const handleDelete = async (row: DeptVO) => {
 
 const handleExpand = () => {
   isExpandAll.value=!isExpandAll.value;  
-  expandRowKeys.value=isExpandAll.value?[]:deptOptions.value.map(item=>item.deptId);
+  toggleExpandAll(deptList.value, isExpandAll.value);
+  // expandRowKeys.value=isExpandAll.value?[]:deptOptions.value.map(item=>item.deptId);
   btnText.value=isExpandAll.value?'关闭所有':'展开所有';   
 }
 

+ 9 - 2
src/views/system/foodIngredient/add.vue

@@ -79,7 +79,7 @@
             </el-col>  
             <el-col :span="6">
               <el-form-item label="食材可食比例构成" prop="edibleRatio">
-            <el-input v-model="form.edibleRatio" placeholder="请输入" :disabled="isView">
+            <el-input v-model="form.edibleRatio" placeholder="请输入" :disabled="isView" >
               <template #append><span>%</span></template>
           </el-input>
           </el-form-item>
@@ -455,7 +455,7 @@ const initFormData: FoodIngredientForm = {
   code: undefined,
   unit: undefined,
   purchasePrice: undefined,
-  edibleRatio: undefined,
+  edibleRatio: 100,
   shelfLife: undefined,
   stockWarning: undefined,
   expiryWarning: undefined,
@@ -675,6 +675,13 @@ const handleSelect = (key: string, keyPath: string[]) => {
 onMounted(() => {
   getListTree()
   getList();
+  let timerId=setInterval(() => {   
+    if(food_unit&&food_unit.value.length>0){
+      form.value.unit=food_unit.value[0].value;      
+      clearInterval(timerId);
+    }    
+  }, 300);
+  
 });
 </script>
 

+ 426 - 0
src/views/system/recipe/add.vue

@@ -0,0 +1,426 @@
+<template>
+  <div style="overflow-y: scroll;" :style=divStyle>
+  <el-card shadow="always">
+    <el-button type="primary" plain  size="large" @click="close()">返回</el-button>
+    <span style="margin-left: 20px;">{{isView?'查看食谱':form.foodIngredientId?'编辑食谱':'食谱管理'}}</span>
+    <el-divider />
+      <div style="font-size: 14px; margin-top: -10px;margin-bottom: -10px;">基本信息</div>
+      <el-divider />
+      <div  width="1024px" >
+        <el-form ref="foodIngredientFormRef" :model="form" :rules="rules" append-to-body label-width="130px">
+          <el-row style="margin-top: 20px;">                  
+            <el-col :span="24" style="margin-left: 100px;">
+              <div><span style="color: red;">&nbsp; </span></div>    
+            </el-col>                   
+          </el-row> 
+          <el-row>            
+            <el-col :span="2" style="margin-left: -100px;">              
+            </el-col>
+            <el-col :span="9">
+              <el-form-item label="基本膳食" prop="baseDiet">                 
+                <el-radio-group v-model="form.baseDiet">
+                  <el-radio v-for="item in dietary_types" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
+               </el-radio-group>
+              </el-form-item>
+            </el-col> 
+            <el-col :span="2">
+            </el-col>  
+            <el-col :span="9">               
+            </el-col>  
+            <el-col :span="2">               
+            </el-col>              
+          </el-row>
+
+          <el-row>            
+            <el-col :span="2" style="margin-left: -100px;">              
+            </el-col>
+            <el-col :span="9">
+              <el-form-item label="餐次" prop="mealTime">            
+            <el-checkbox-group v-model="form.mealTimes">
+              <el-checkbox v-for="item in meal_times" :key="item.value" :label="item.label" :value="item.value" /> 
+           </el-checkbox-group>
+
+          </el-form-item>
+            </el-col> 
+            <el-col :span="2">               
+            </el-col>  
+            <el-col :span="9">              
+            </el-col>  
+            <el-col :span="2">               
+            </el-col>              
+          </el-row>
+
+          <el-row>            
+            <el-col :span="2" style="margin-left: -100px;">              
+            </el-col>
+            <el-col :span="9">
+              <el-form-item label="食谱名称" prop="name">
+            <el-input v-model="form.name" placeholder="请输入" :disabled="isView"/>              
+          </el-form-item>
+            </el-col> 
+            <el-col :span="2">               
+            </el-col>  
+            <el-col :span="9">
+              <el-form-item label="食谱分类" prop="edibleRatio">
+            <el-select v-model="form.unit" placeholder="请选择"   clearable :disabled="isView">
+                <el-option v-for="dict in food_unit" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+              </el-select>
+          </el-form-item>
+            </el-col>  
+            <el-col :span="2">               
+            </el-col> 
+          </el-row>
+
+          <el-row>            
+            <el-col :span="2" style="margin-left: -100px;">
+            </el-col>
+            <el-col :span="9">
+              <el-form-item label="食谱价格" prop="shelfLife">
+            <el-input v-model="form.shelfLife" placeholder="请输入" :disabled="isView"/>
+          </el-form-item>
+            </el-col> 
+            <el-col :span="2">               
+            </el-col>  
+            <el-col :span="9">
+              <el-form-item label="适用疾病" prop="stockWarning">
+            <el-input v-model="form.stockWarning" placeholder="请输入" :disabled="isView"/>               
+          </el-form-item>
+            </el-col>  
+            <el-col :span="2">               
+            </el-col> 
+          </el-row>
+
+          <el-row>            
+            <el-col :span="2" style="margin-left: -100px;">              
+            </el-col>
+            <el-col :span="9">
+              <el-form-item label="忌食病症" prop="expiryWarning">
+            <el-input v-model="form.expiryWarning" placeholder="请输入" :disabled="isView"/>              
+          </el-form-item>
+            </el-col> 
+            <el-col :span="2">               
+            </el-col>  
+            <el-col :span="9"> 
+              <el-form-item label="适用科室" prop="expiryWarning">
+            <el-input v-model="form.expiryWarning" placeholder="请输入" :disabled="isView"/>              
+          </el-form-item>   
+            </el-col>  
+            <el-col :span="2">               
+            </el-col> 
+            
+          </el-row>
+
+          <el-row>            
+            <el-col :span="2" style="margin-left: -100px;">              
+            </el-col>
+            <el-col :span="9">
+              <el-form-item label="智能推荐" prop="smartRecommend">
+            <el-radio-group v-model="form.smartRecommend" :disabled="isView">
+              <el-radio v-for="item in intelligent_recommendation" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
+            </el-radio-group>
+          </el-form-item>
+            </el-col>            
+            <el-col :span="2">               
+            </el-col> 
+            <el-col :span="2">               
+            </el-col>  
+          </el-row>
+        </el-form>
+
+      <el-divider />
+      <div style="font-size: 14px;margin-top: -10px;margin-bottom: -10px;">食材组成</div>
+      <el-divider />
+      <div style="margin-top: 10px; margin-bottom: 20px;"><span>食材总量:111.0000 g</span><span style="margin-left: 100px;">膳食总热量:410.70kcal</span></div>
+      <el-table border :data="foodIngredientList" @selection-change="handleSelectionChange">
+        <!-- <el-table-column type="selection" width="55" align="center" /> -->
+        <el-table-column label="食材名称" align="center" prop="bigCategory" />
+        <el-table-column label="食材分类" align="center" prop="subCategory" />
+        <el-table-column label="用量" align="center" prop="name" />
+        <el-table-column label="热量(kcal)" align="center" prop="name" />
+        <el-table-column label="备注" align="center" prop="name" />         
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">            
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:foodIngredient:remove']">删除</el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-row :gutter="10" class="mb8">         
+          <el-col :span="8">             
+          </el-col>
+          <el-col :span="8" align="center" style="margin-top: 30PX;">
+            <el-link type="primary" icon="Plus" @click="handleDelete()">添加食材</el-link>             
+          </el-col>          
+          <el-col :span="8">            
+          </el-col>          
+        </el-row>
+
+        <el-row :gutter="10" class="mb8">         
+          <el-col :span="24">  
+            <el-form-item label="制作方式" prop="description">
+            <el-input v-model="form.description" type="textarea" placeholder="请输入"  :disabled="isView" :rows="3" maxlength="3000" show-word-limit/>
+          </el-form-item>           
+          </el-col>                    
+        </el-row>        
+      </div>
+    </el-card>
+  </div>
+     
+
+    <el-card shadow="always" class="card-footer" v-if="!isView">
+    <div>
+        <el-button type="primary" size="large" plain @click="close" v-hasPermi="['system:hospital:add']">
+          &nbsp;&nbsp;&nbsp;营养数据分析&nbsp;&nbsp;&nbsp;
+        </el-button>
+        <el-button type="primary" size="large" @click="submitForm" v-hasPermi="['system:hospital:add']">
+          &nbsp;&nbsp;&nbsp;提交&nbsp;&nbsp;&nbsp;
+        </el-button>
+      </div> 
+    </el-card> 
+</template>
+
+<script setup name="FoodIngredient" lang="ts"> 
+import { listTree} from '@/api/system/foodCategory';
+ 
+import { listRecipe, getRecipe, delRecipe, addRecipe, updateRecipe } from '@/api/system/recipe';
+import { RecipeVO, RecipeQuery, RecipeForm } from '@/api/system/recipe/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const {  intelligent_recommendation,meal_times,dietary_types } = toRefs<any>(proxy?.useDict('intelligent_recommendation','meal_times','dietary_types'));
+
+const recipeList = ref<RecipeVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const divStyle = ref({
+  height: '755px'
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const isView  = ref<boolean>(false) 
+const route = useRoute();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: RecipeForm = {
+  recipeId: undefined,
+  name: undefined,
+  categoryId: undefined,
+  baseDiet: '1',
+  mealTime: undefined,
+  price: undefined,
+  suitableDisease: undefined,
+  avoidDisease: undefined,
+  suitableDept: undefined,
+  smartRecommend: '1',
+  cookingMethod: undefined,
+  status: undefined,
+}
+const data = reactive<PageData<RecipeForm, RecipeQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: undefined,
+    categoryId: undefined,
+    baseDiet: undefined,
+    mealTime: undefined,
+    price: undefined,
+    suitableDisease: undefined,
+    avoidDisease: undefined,
+    suitableDept: undefined,
+    smartRecommend: undefined,
+    cookingMethod: undefined,
+    status: undefined,
+    params: {
+    }
+  },
+  rules: {
+    recipeId: [
+      { required: true, message: "主键ID不能为空", trigger: "blur" }
+    ],
+    name: [
+      { required: true, message: "食谱名称不能为空", trigger: "blur" }
+    ],
+    categoryId: [
+      { required: true, message: "食谱分类ID不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+
+/** 关闭按钮 */
+const close = () => {
+  const obj: RouteLocationNormalized = {
+    fullPath: '',
+    hash: '',
+    matched: [],
+    meta: undefined,
+    name: undefined,
+    params: undefined,
+    query: undefined,
+    redirectedFrom: undefined,
+    path: '/food/recipe'
+  };
+  proxy?.$tab.closeOpenPage(obj);
+};
+
+const getListTree = async () => {   
+  const res = await listTree(queryParams.value);  
+  foodCategoryList.value = res.rows;   
+}
+
+/** 查询食材管理列表 */
+const getList = async () => {
+  const foodIngredientId = route.params && route.params.id;
+  const vfoodIngredientId = route.params && route.params.vid;
+  let id=undefined;
+  if(vfoodIngredientId){
+    isView.value=true;
+    id=vfoodIngredientId;
+  }else{
+    isView.value=false ;
+    id=foodIngredientId;
+  }
+  
+  if (id&&id!='0') {
+    loading.value = true;
+    const res = await getFoodIngredient(id as string);
+    Object.assign(form.value, res.data);
+    form.value.foodCategoryIds=res.data.foodCategoryId.toString().split(',') ;      
+    console.log(form.value.foodCategoryIds) 
+    loading.value = false;
+  }  
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  foodIngredientFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: FoodIngredientVO[]) => {
+  ids.value = selection.map(item => item.foodIngredientId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加食材管理";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: FoodIngredientVO) => {
+  reset();
+  const _foodIngredientId = row?.foodIngredientId || ids.value[0]
+  const res = await getFoodIngredient(_foodIngredientId);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改食材管理";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  foodIngredientFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      let params=ref<FoodIngredientForm>({});
+      Object.assign(params.value, form.value);
+      params.value.foodCategoryId = form.value.foodCategoryIds.join(',')
+      if (form.value.foodIngredientId) {
+        await updateFoodIngredient(params.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addFoodIngredient(params.value).then(res=>{
+          form.value.foodIngredientId=res.data;
+        }).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功"); 
+      if(currentIndex.value=='2'){
+        close()
+      }else{
+        currentIndex.value='2';   
+      }           
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: FoodIngredientVO) => {
+  const _foodIngredientIds = row?.foodIngredientId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除食材管理编号为"' + _foodIngredientIds + '"的数据项?').finally(() => loading.value = false);
+  await delFoodIngredient(_foodIngredientIds);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('system/foodIngredient/export', {
+    ...queryParams.value
+  }, `foodIngredient_${new Date().getTime()}.xlsx`)
+}
+
+
+const handleSelect = (key: string, keyPath: string[]) => {
+  currentIndex.value=key.toString()   
+  // console.log(key, keyPath,currentIndex)
+}
+
+onMounted(() => {
+  getListTree()
+  getList();
+  let timerId=setInterval(() => {   
+    if(food_unit&&food_unit.value.length>0){
+      form.value.unit=food_unit.value[0].value;      
+      clearInterval(timerId);
+    }    
+  }, 300);
+  
+});
+</script>
+
+<style lang="scss" scoped>
+.card-footer{  
+    z-index: 99;
+    bottom: 0px;
+    left: calc(var(--left-menu-max-width) + var(--app-content-padding));
+    right: 0px;
+    height: 90px;
+    display: flex;
+    justify-content: center;
+    align-items: center;     
+}
+</style>

+ 307 - 0
src/views/system/recipe/index.vue

@@ -0,0 +1,307 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="膳食类型" prop="name">
+              <el-input v-model="queryParams.name" placeholder="请输入" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="食谱分类" prop="categoryId">
+              <el-input v-model="queryParams.categoryId" placeholder="请输入" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="智能推荐" prop="smartRecommend">
+              <el-input v-model="queryParams.smartRecommend" placeholder="请输入智能推荐" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="食谱名称" prop="name">
+              <el-input v-model="queryParams.name" placeholder="请输入食谱名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary"   icon="Plus" @click="handleAdd" v-hasPermi="['system:recipe:add']">新增食谱</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button  @click="handleDelete()" v-hasPermi="['system:recipe:remove']">食谱分类</el-button>
+          </el-col>
+
+          <el-col :span="1.5">
+            <el-button type="primary"  :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:recipe:remove']">批量智能推荐</el-button>
+          </el-col>
+          
+          <el-col :span="1.5">
+            <el-button type="primary"  :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:recipe:remove']">批量取消智能推荐</el-button>
+          </el-col>
+
+          <el-col :span="1.5">
+            <el-button type="danger" icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:recipe:remove']">批量删除</el-button>
+          </el-col>
+          <!-- <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:recipe:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:recipe:export']">导出</el-button>
+          </el-col> -->
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="recipeList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="食谱编码" align="center" prop="recipeId"/>
+        <el-table-column label="膳食类型" align="center" prop="recipeId"/>
+        <el-table-column label="食谱分类" align="center" prop="categoryId" />
+        <el-table-column label="食谱名称" align="center" prop="name" />
+        <el-table-column label="食谱价格" align="center" prop="price" />
+        <el-table-column label="智能推荐" align="center" prop="smartRecommend" />
+        <!-- <el-table-column label="基本膳食" align="center" prop="baseDiet" />
+        <el-table-column label="餐次" align="center" prop="mealTime" />        
+        <el-table-column label="适用疾病" align="center" prop="suitableDisease" />
+        <el-table-column label="忌食病症" align="center" prop="avoidDisease" />
+        <el-table-column label="适用科室" align="center" prop="suitableDept" />        
+        <el-table-column label="制作方式" align="center" prop="cookingMethod" />
+        <el-table-column label="状态" align="center" prop="status" /> -->
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="详情" placement="top">
+              <el-button link type="primary" icon="View" @click="handleUpdate(false,scope.row)" v-hasPermi="['system:recipe:edit']">详情</el-button>
+            </el-tooltip>
+            <el-tooltip content="编辑" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(false,scope.row)" v-hasPermi="['system:recipe:edit']">编辑</el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(true,scope.row)" v-hasPermi="['system:recipe:remove']">删除</el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改食谱管理对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="recipeFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="食谱名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入食谱名称" />
+        </el-form-item>
+        <el-form-item label="食谱分类ID" prop="categoryId">
+          <el-input v-model="form.categoryId" placeholder="请输入食谱分类ID" />
+        </el-form-item>
+        <el-form-item label="基本膳食" prop="baseDiet">
+          <el-input v-model="form.baseDiet" placeholder="请输入基本膳食" />
+        </el-form-item>
+        <el-form-item label="餐次" prop="mealTime">
+          <el-input v-model="form.mealTime" placeholder="请输入餐次" />
+        </el-form-item>
+        <el-form-item label="食谱价格" prop="price">
+          <el-input v-model="form.price" placeholder="请输入食谱价格" />
+        </el-form-item>
+        <el-form-item label="适用疾病" prop="suitableDisease">
+          <el-input v-model="form.suitableDisease" placeholder="请输入适用疾病" />
+        </el-form-item>
+        <el-form-item label="忌食病症" prop="avoidDisease">
+          <el-input v-model="form.avoidDisease" placeholder="请输入忌食病症" />
+        </el-form-item>
+        <el-form-item label="适用科室" prop="suitableDept">
+          <el-input v-model="form.suitableDept" placeholder="请输入适用科室" />
+        </el-form-item>
+        <el-form-item label="智能推荐" prop="smartRecommend">
+          <el-input v-model="form.smartRecommend" placeholder="请输入智能推荐" />
+        </el-form-item>
+        <el-form-item label="制作方式" prop="cookingMethod">
+          <el-input v-model="form.cookingMethod" placeholder="请输入制作方式" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Recipe" lang="ts">
+import { listRecipe, getRecipe, delRecipe, addRecipe, updateRecipe } from '@/api/system/recipe';
+import { RecipeVO, RecipeQuery, RecipeForm } from '@/api/system/recipe/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const router = useRouter();
+const recipeList = ref<RecipeVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const recipeFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: RecipeForm = {
+  recipeId: undefined,
+  name: undefined,
+  categoryId: undefined,
+  baseDiet: undefined,
+  mealTime: undefined,
+  price: undefined,
+  suitableDisease: undefined,
+  avoidDisease: undefined,
+  suitableDept: undefined,
+  smartRecommend: undefined,
+  cookingMethod: undefined,
+  status: undefined,
+}
+const data = reactive<PageData<RecipeForm, RecipeQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: undefined,
+    categoryId: undefined,
+    baseDiet: undefined,
+    mealTime: undefined,
+    price: undefined,
+    suitableDisease: undefined,
+    avoidDisease: undefined,
+    suitableDept: undefined,
+    smartRecommend: undefined,
+    cookingMethod: undefined,
+    status: undefined,
+    params: {
+    }
+  },
+  rules: {
+    recipeId: [
+      { required: true, message: "主键ID不能为空", trigger: "blur" }
+    ],
+    name: [
+      { required: true, message: "食谱名称不能为空", trigger: "blur" }
+    ],
+    categoryId: [
+      { required: true, message: "食谱分类ID不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询食谱管理列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listRecipe(queryParams.value);
+  recipeList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  recipeFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: RecipeVO[]) => {
+  ids.value = selection.map(item => item.recipeId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  // reset();
+  // dialog.visible = true;
+  // dialog.title = "添加食谱管理";
+
+  router.push('/food/recipe-page/0');
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (disabled:boolean,row?: RecipeVO) => {
+  // reset();  
+  // const res = await getRecipe(_recipeId);
+  // Object.assign(form.value, res.data);
+  // dialog.visible = true;
+  // dialog.title = "修改食谱管理";
+  const _recipeId = row?.recipeId || ids.value[0]
+  if(disabled){
+    router.push('/food/recipe-view/'+_recipeId);
+  }else{
+    router.push('/food/recipe-page/'+_recipeId);
+  } 
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  recipeFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.recipeId) {
+        await updateRecipe(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addRecipe(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: RecipeVO) => {
+  const _recipeIds = row?.recipeId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除食谱管理编号为"' + _recipeIds + '"的数据项?').finally(() => loading.value = false);
+  await delRecipe(_recipeIds);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('system/recipe/export', {
+    ...queryParams.value
+  }, `recipe_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>