Kaynağa Gözat

0731营养设定 膳食治疗等

HuRongxin 4 ay önce
ebeveyn
işleme
37db79998b

+ 4 - 0
src/api/patients/diagnosis/types.ts

@@ -43,6 +43,10 @@ export interface DiagnosisVO {
 
     createTime: string;
 
+    diagnosisLabelStr: string;
+
+    consultantResultStr: string;
+
 }
 
 export interface DiagnosisForm extends BaseEntity {

+ 137 - 139
src/api/patients/hospitalMealPlan/types.ts

@@ -1,147 +1,145 @@
 export interface MealPlanVO {
-    /**
-     * 主键
-     */
-    id: string | number;
-
-    /**
-     * 看诊类型
-     */
-    type: string;
-
-    /**
-     * 患者ID
-     */
-    patientId: string | number;
-
-    /**
-     * 门诊/住院号
-     */
-    outpatientNo: string;
-
-    /**
-     * 科室ID
-     */
-    deptId: string | number;
-
-    /**
-     * 推荐/配餐开始日期
-     */
-    recommendStartDate: string;
-
-    /**
-     * 推荐/配餐结束日期
-     */
-    recommendEndDate: string;
-
-    /**
-     * 处方状态
-     */
-    status: string;
-
-    /**
-     * 备注
-     */
-    remark: string;
-
+  /**
+   * 主键
+   */
+  id: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type: string;
+
+  /**
+   * 患者ID
+   */
+  patientId: string | number;
+
+  /**
+   * 门诊/住院号
+   */
+  outpatientNo: string;
+
+  /**
+   * 科室ID
+   */
+  deptId: string | number;
+
+  /**
+   * 推荐/配餐开始日期
+   */
+  recommendStartDate: string;
+
+  /**
+   * 推荐/配餐结束日期
+   */
+  recommendEndDate: string;
+
+  /**
+   * 处方状态
+   */
+  status: string;
+
+  totalPrice: number;
+
+  /**
+   * 备注
+   */
+  remark: string;
 }
 
 export interface MealPlanForm extends BaseEntity {
-    /**
-     * 主键
-     */
-    id?: string | number;
-
-    /**
-     * 看诊类型
-     */
-    type?: string;
-
-    /**
-     * 患者ID
-     */
-    patientId?: string | number;
-
-    /**
-     * 门诊/住院号
-     */
-    outpatientNo?: string;
-
-    /**
-     * 科室ID
-     */
-    deptId?: string | number;
-
-    /**
-     * 推荐/配餐开始日期
-     */
-    recommendStartDate?: string;
-
-    /**
-     * 推荐/配餐结束日期
-     */
-    recommendEndDate?: string;
-
-    /**
-     * 处方状态
-     */
-    status?: string;
-
-    /**
-     * 备注
-     */
-    remark?: string;
-
-    mealRecipeList?: Array<JSON>
-
+  /**
+   * 主键
+   */
+  id?: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type?: string;
+
+  /**
+   * 患者ID
+   */
+  patientId?: string | number;
+
+  /**
+   * 门诊/住院号
+   */
+  outpatientNo?: string;
+
+  /**
+   * 科室ID
+   */
+  deptId?: string | number;
+
+  /**
+   * 推荐/配餐开始日期
+   */
+  recommendStartDate?: string;
+
+  /**
+   * 推荐/配餐结束日期
+   */
+  recommendEndDate?: string;
+
+  /**
+   * 处方状态
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  totalPrice?: number;
+
+  mealRecipeList?: Array<JSON>;
 }
 
 export interface MealPlanQuery extends PageQuery {
-
-    /**
-     * 看诊类型
-     */
-    type?: string;
-
-    /**
-     * 患者ID
-     */
-    patientId?: string | number;
-
-    /**
-     * 门诊/住院号
-     */
-    outpatientNo?: string;
-
-    /**
-     * 科室ID
-     */
-    deptId?: string | number;
-
-    /**
-     * 推荐/配餐开始日期
-     */
-    recommendStartDate?: string;
-
-    /**
-     * 推荐/配餐结束日期
-     */
-    recommendEndDate?: string;
-
-    /**
-     * 处方状态
-     */
-    status?: string;
-
-    searchValue?: string;
-
-    dateRange?: string[];
-
-    /**
-     * 日期范围参数
-     */
-    params?: any;
+  /**
+   * 看诊类型
+   */
+  type?: string;
+
+  /**
+   * 患者ID
+   */
+  patientId?: string | number;
+
+  /**
+   * 门诊/住院号
+   */
+  outpatientNo?: string;
+
+  /**
+   * 科室ID
+   */
+  deptId?: string | number;
+
+  /**
+   * 推荐/配餐开始日期
+   */
+  recommendStartDate?: string;
+
+  /**
+   * 推荐/配餐结束日期
+   */
+  recommendEndDate?: string;
+
+  /**
+   * 处方状态
+   */
+  status?: string;
+
+  searchValue?: string;
+
+  dateRange?: string[];
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
 }
-
-
-

+ 526 - 537
src/api/patients/nutritionSetting/types.ts

@@ -1,571 +1,560 @@
 export interface NutritionSettingVO {
-    /**
-     * 主键
-     */
-    id: string | number;
-
-    /**
-     * 所需热量
-     */
-    caloriesKcalPerDay: number;
-
-    /**
-     * 所需热量
-     */
-    caloriesKcalPerKgDay: number;
-
-    /**
-     * 所需热量
-     */
-    caloriesKjPerDay: number;
-
-    /**
-     * 蛋白质热量占比
-     */
-    proteinCaloriePercentage: number;
-
-    /**
-     * 脂肪热量占比
-     */
-    fatCaloriePercentage: number;
-
-    /**
-     * 碳水化合物热量占比
-     */
-    carbohydrateCaloriePercentage: number;
-
-    /**
-     * 所需蛋白质
-     */
-    proteinGPerKgDay: number;
-
-    /**
-     * 所需蛋白质
-     */
-    proteinGPerDay: number;
-
-    /**
-     * 所需脂肪
-     */
-    fatGPerKgDay: number;
-
-    /**
-     * 所需脂肪
-     */
-    fatGPerDay: number;
-
-    /**
-     * 所需碳水化合物
-     */
-    carbohydrateGPerKgDay: number;
-
-    /**
-     * 所需碳水化合物
-     */
-    carbohydrateGPerDay: number;
-
-    /**
-     * 钙
-     */
-    calcium: number;
-
-    /**
-     * 钾
-     */
-    potassium: number;
-
-    /**
-     * 钠
-     */
-    sodium: number;
-
-    /**
-     * 镁
-     */
-    magnesium: number;
-
-    /**
-     * 磷
-     */
-    phosphorus: number;
-
-    /**
-     * 氯
-     */
-    chloride: string | number;
-
-    /**
-     * 铁
-     */
-    iron: number;
-
-    /**
-     * 硒
-     */
-    selenium: number;
-
-    /**
-     * 锰
-     */
-    manganese: number;
-
-    /**
-     * 氟
-     */
-    fluoride: string | number;
-
-    /**
-     * 钼
-     */
-    molybdenum: number;
-
-    /**
-     * 锌
-     */
-    zinc: number;
-
-    /**
-     * 铜
-     */
-    copper: number;
-
-    /**
-     * 碘
-     */
-    iodine: number;
-
-    /**
-     * 铬
-     */
-    chromium: number;
-
-    /**
-     * 维生素A
-     */
-    vitaminA: number;
-
-    /**
-     * 维生素D
-     */
-    vitaminD: number;
-
-    /**
-     * 维生素E
-     */
-    vitaminE: number;
-
-    /**
-     * 维生素K
-     */
-    vitaminK: number;
-
-    /**
-     * 维生素B1
-     */
-    vitaminBOne: number;
-
-    /**
-     * 维生素B2
-     */
-    vitaminBTwo: number;
-
-    /**
-     * 维生素B6
-     */
-    vitaminBSix: number;
-
-    /**
-     * 维生素B12
-     */
-    vitaminBTwelve: number;
-
-    /**
-     * 烟酸(尼克酸)
-     */
-    niacin: number;
-
-    /**
-     * 维生素C
-     */
-    vitaminC: number;
-
-    /**
-     * 叶酸
-     */
-    folicAcid: string | number;
-
-    /**
-     * 胆碱
-     */
-    choline: number;
-
-    /**
-     * 生物素
-     */
-    biotin: number;
-
-    /**
-     * 泛酸
-     */
-    pantothenicAcid: string | number;
-
-    /**
-     * 膳食纤维
-     */
-    dietaryFiber: number;
-
-    /**
-     * 设定方式
-     */
-    settingType: string;
-
-    /**
-     * 患者id
-     */
-    patientId: string | number;
-
-    /**
-     * 看诊类型
-     */
-    type: string;
-
-    /**
-     * 科室
-     */
-    deptId: string | number;
-
-    /**
-     * 门诊号
-     */
-    outpatientNo: string;
+  /**
+   * 主键
+   */
+  id: string | number;
+
+  /**
+   * 所需热量
+   */
+  caloriesKcalPerDay: number;
+
+  /**
+   * 所需热量
+   */
+  caloriesKcalPerKgDay: number;
+
+  /**
+   * 所需热量
+   */
+  caloriesKjPerDay: number;
+
+  /**
+   * 蛋白质热量占比
+   */
+  proteinCaloriePercentage: number;
+
+  /**
+   * 脂肪热量占比
+   */
+  fatCaloriePercentage: number;
+
+  /**
+   * 碳水化合物热量占比
+   */
+  carbohydrateCaloriePercentage: number;
+
+  /**
+   * 所需蛋白质
+   */
+  proteinGPerKgDay: number;
+
+  /**
+   * 所需蛋白质
+   */
+  proteinGPerDay: number;
+
+  /**
+   * 所需脂肪
+   */
+  fatGPerKgDay: number;
+
+  /**
+   * 所需脂肪
+   */
+  fatGPerDay: number;
+
+  /**
+   * 所需碳水化合物
+   */
+  carbohydrateGPerKgDay: number;
+
+  /**
+   * 所需碳水化合物
+   */
+  carbohydrateGPerDay: number;
 
+  /**
+   * 钙
+   */
+  calcium: number;
+
+  /**
+   * 钾
+   */
+  potassium: number;
+
+  /**
+   * 钠
+   */
+  sodium: number;
+
+  /**
+   * 镁
+   */
+  magnesium: number;
+
+  /**
+   * 磷
+   */
+  phosphorus: number;
+
+  /**
+   * 氯
+   */
+  chloride: string | number;
+
+  /**
+   * 铁
+   */
+  iron: number;
+
+  /**
+   * 硒
+   */
+  selenium: number;
+
+  /**
+   * 锰
+   */
+  manganese: number;
+
+  /**
+   * 氟
+   */
+  fluoride: string | number;
+
+  /**
+   * 钼
+   */
+  molybdenum: number;
+
+  /**
+   * 锌
+   */
+  zinc: number;
+
+  /**
+   * 铜
+   */
+  copper: number;
+
+  /**
+   * 碘
+   */
+  iodine: number;
+
+  /**
+   * 铬
+   */
+  chromium: number;
+
+  /**
+   * 维生素A
+   */
+  vitaminA: number;
+
+  /**
+   * 维生素D
+   */
+  vitaminD: number;
+
+  /**
+   * 维生素E
+   */
+  vitaminE: number;
+
+  /**
+   * 维生素K
+   */
+  vitaminK: number;
+
+  /**
+   * 维生素B1
+   */
+  vitaminBOne: number;
+
+  /**
+   * 维生素B2
+   */
+  vitaminBTwo: number;
+
+  /**
+   * 维生素B6
+   */
+  vitaminBSix: number;
+
+  /**
+   * 维生素B12
+   */
+  vitaminBTwelve: number;
+
+  /**
+   * 烟酸(尼克酸)
+   */
+  niacin: number;
+
+  /**
+   * 维生素C
+   */
+  vitaminC: number;
+
+  /**
+   * 叶酸
+   */
+  folicAcid: string | number;
+
+  /**
+   * 胆碱
+   */
+  choline: number;
+
+  /**
+   * 生物素
+   */
+  biotin: number;
+
+  /**
+   * 泛酸
+   */
+  pantothenicAcid: string | number;
+
+  /**
+   * 膳食纤维
+   */
+  dietaryFiber: number;
+
+  /**
+   * 设定方式
+   */
+  settingType: string;
+
+  /**
+   * 患者id
+   */
+  patientId: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type: string;
+
+  /**
+   * 科室
+   */
+  deptId: string | number;
+
+  /**
+   * 门诊号
+   */
+  outpatientNo: string;
 }
 
 export interface NutritionSettingForm extends BaseEntity {
-    /**
-     * 主键
-     */
-    id?: string | number;
-
-    /**
-     * 所需热量
-     */
-    caloriesKcalPerDay?: number;
-
-    /**
-     * 所需热量
-     */
-    caloriesKcalPerKgDay?: number;
-
-    /**
-     * 所需热量
-     */
-    caloriesKjPerDay?: number;
-
-    /**
-     * 蛋白质热量占比
-     */
-    proteinCaloriePercentage?: number;
-
-    /**
-     * 脂肪热量占比
-     */
-    fatCaloriePercentage?: number;
-
-    /**
-     * 碳水化合物热量占比
-     */
-    carbohydrateCaloriePercentage?: number;
-
-    /**
-     * 所需蛋白质
-     */
-    proteinGPerKgDay?: number;
-
-    /**
-     * 所需蛋白质
-     */
-    proteinGPerDay?: number;
-
-    /**
-     * 所需脂肪
-     */
-    fatGPerKgDay?: number;
-
-    /**
-     * 所需脂肪
-     */
-    fatGPerDay?: number;
-
-    /**
-     * 所需碳水化合物
-     */
-    carbohydrateGPerKgDay?: number;
-
-    /**
-     * 所需碳水化合物
-     */
-    carbohydrateGPerDay?: number;
-
-    /**
-     * 钙
-     */
-    calcium?: number;
-
-    /**
-     * 钾
-     */
-    potassium?: number;
-
-    /**
-     * 钠
-     */
-    sodium?: number;
-
-    /**
-     * 镁
-     */
-    magnesium?: number;
-
-    /**
-     * 磷
-     */
-    phosphorus?: number;
-
-    /**
-     * 氯
-     */
-    chloride?: string | number;
-
-    /**
-     * 铁
-     */
-    iron?: number;
-
-    /**
-     * 硒
-     */
-    selenium?: number;
-
-    /**
-     * 锰
-     */
-    manganese?: number;
-
-    /**
-     * 氟
-     */
-    fluoride?: string | number;
-
-    /**
-     * 钼
-     */
-    molybdenum?: number;
-
-    /**
-     * 锌
-     */
-    zinc?: number;
-
-    /**
-     * 铜
-     */
-    copper?: number;
-
-    /**
-     * 碘
-     */
-    iodine?: number;
-
-    /**
-     * 铬
-     */
-    chromium?: number;
-
-    /**
-     * 维生素A
-     */
-    vitaminA?: number;
-
-    /**
-     * 维生素D
-     */
-    vitaminD?: number;
-
-    /**
-     * 维生素E
-     */
-    vitaminE?: number;
-
-    /**
-     * 维生素K
-     */
-    vitaminK?: number;
-
-    /**
-     * 维生素B1
-     */
-    vitaminBOne?: number;
-
-    /**
-     * 维生素B2
-     */
-    vitaminBTwo?: number;
-
-    /**
-     * 维生素B6
-     */
-    vitaminBSix?: number;
-
-    /**
-     * 维生素B12
-     */
-    vitaminBTwelve?: number;
-
-    /**
-     * 烟酸(尼克酸)
-     */
-    niacin?: number;
-
-    /**
-     * 维生素C
-     */
-    vitaminC?: number;
-
-    /**
-     * 叶酸
-     */
-    folicAcid?: string | number;
-
-    /**
-     * 胆碱
-     */
-    choline?: number;
-
-    /**
-     * 生物素
-     */
-    biotin?: number;
-
-    /**
-     * 泛酸
-     */
-    pantothenicAcid?: string | number;
-
-    /**
-     * 膳食纤维
-     */
-    dietaryFiber?: number;
-
-    /**
-     * 设定方式
-     */
-    settingType?: string;
-
-    deptName?: string;
-
-    /**
-     * 患者id
-     */
-    patientId?: string | number;
-
-    /**
-     * 看诊类型
-     */
-    type?: string;
-
-    /**
-     * 科室
-     */
-    deptId?: string | number;
-
-    /**
-     * 门诊号
-     */
-    outpatientNo?: string;
-
-    /**
-   * 身高
+  /**
+   * 主键
+   */
+  id?: string | number;
+
+  /**
+   * 所需热量
+   */
+  caloriesKcalPerDay?: number;
+
+  /**
+   * 所需热量
    */
-    height?: number;
+  caloriesKcalPerKgDay?: number;
 
+  /**
+   * 所需热量
+   */
+  caloriesKjPerDay?: number;
 
-    /**
-     * 体重
-     */
-    weight?: number;
+  /**
+   * 蛋白质热量占比
+   */
+  proteinCaloriePercentage?: number;
 
+  /**
+   * 脂肪热量占比
+   */
+  fatCaloriePercentage?: number;
 
-    /**
-     * 体力活动
-     */
-    activity?: number;
+  /**
+   * 碳水化合物热量占比
+   */
+  carbohydrateCaloriePercentage?: number;
 
+  /**
+   * 所需蛋白质
+   */
+  proteinGPerKgDay?: number;
 
-    /**
-     * 应激状态
-     */
-    stressType?: number;
+  /**
+   * 所需蛋白质
+   */
+  proteinGPerDay?: number;
 
+  /**
+   * 所需脂肪
+   */
+  fatGPerKgDay?: number;
 
-    /**
-     * 上臀围
-     */
-    highHip?: number;
+  /**
+   * 所需脂肪
+   */
+  fatGPerDay?: number;
 
-    /**
-     * 下臀围
-     */
-    lowHip?: number;
+  /**
+   * 所需碳水化合物
+   */
+  carbohydrateGPerKgDay?: number;
 
-    /*烧伤面积*/
-    burnArea?: number;
+  /**
+   * 所需碳水化合物
+   */
+  carbohydrateGPerDay?: number;
 
-    bmi?: number;
+  /**
+   * 钙
+   */
+  calcium?: number;
 
-    gender?: string;
+  /**
+   * 钾
+   */
+  potassium?: number;
 
-    age?: number;
+  /**
+   * 钠
+   */
+  sodium?: number;
 
-}
+  /**
+   * 镁
+   */
+  magnesium?: number;
 
-export interface NutritionSettingQuery extends PageQuery {
+  /**
+   * 磷
+   */
+  phosphorus?: number;
+
+  /**
+   * 氯
+   */
+  chloride?: string | number;
+
+  /**
+   * 铁
+   */
+  iron?: number;
+
+  /**
+   * 硒
+   */
+  selenium?: number;
+
+  /**
+   * 锰
+   */
+  manganese?: number;
 
+  /**
+   * 氟
+   */
+  fluoride?: string | number;
 
-    /**
-     * 设定方式
-     */
-    settingType?: string;
+  /**
+   * 钼
+   */
+  molybdenum?: number;
 
-    /**
-     * 患者id
-     */
-    patientId?: string | number;
+  /**
+   * 锌
+   */
+  zinc?: number;
 
-    /**
-     * 看诊类型
-     */
-    type?: string;
+  /**
+   * 铜
+   */
+  copper?: number;
 
-    /**
-     * 科室
-     */
-    deptId?: string | number;
+  /**
+   * 碘
+   */
+  iodine?: number;
 
-    /**
-     * 门诊号
-     */
-    outpatientNo?: string;
+  /**
+   * 铬
+   */
+  chromium?: number;
 
-    searchValue?: string;
+  /**
+   * 维生素A
+   */
+  vitaminA?: number;
 
-    dateRange?: string[];
+  /**
+   * 维生素D
+   */
+  vitaminD?: number;
+
+  /**
+   * 维生素E
+   */
+  vitaminE?: number;
 
-    /**
-     * 日期范围参数
-     */
-    params?: any;
+  /**
+   * 维生素K
+   */
+  vitaminK?: number;
+
+  /**
+   * 维生素B1
+   */
+  vitaminBOne?: number;
+
+  /**
+   * 维生素B2
+   */
+  vitaminBTwo?: number;
+
+  /**
+   * 维生素B6
+   */
+  vitaminBSix?: number;
+
+  /**
+   * 维生素B12
+   */
+  vitaminBTwelve?: number;
+
+  /**
+   * 烟酸(尼克酸)
+   */
+  niacin?: number;
+
+  /**
+   * 维生素C
+   */
+  vitaminC?: number;
+
+  /**
+   * 叶酸
+   */
+  folicAcid?: string | number;
+
+  /**
+   * 胆碱
+   */
+  choline?: number;
+
+  /**
+   * 生物素
+   */
+  biotin?: number;
+
+  /**
+   * 泛酸
+   */
+  pantothenicAcid?: string | number;
+
+  /**
+   * 膳食纤维
+   */
+  dietaryFiber?: number;
+
+  /**
+   * 设定方式
+   */
+  settingType?: string;
+
+  deptName?: string;
+
+  /**
+   * 患者id
+   */
+  patientId?: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type?: string;
+
+  /**
+   * 科室
+   */
+  deptId?: string | number;
+
+  /**
+   * 门诊号
+   */
+  outpatientNo?: string;
+
+  /**
+   * 身高
+   */
+  height?: number;
+
+  /**
+   * 体重
+   */
+  weight?: number;
+
+  /**
+   * 体力活动
+   */
+  activity?: number;
+
+  /**
+   * 应激状态
+   */
+  stressType?: number;
+
+  /**
+   * 上臀围
+   */
+  highHip?: number;
+
+  /**
+   * 下臀围
+   */
+  lowHip?: number;
+
+  /*烧伤面积*/
+  burnArea?: number;
+
+  bmi?: number;
+
+  gender?: string;
+
+  age?: number;
 }
 
+export interface NutritionSettingQuery extends PageQuery {
+  /**
+   * 设定方式
+   */
+  settingType?: string;
+
+  /**
+   * 患者id
+   */
+  patientId?: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type?: string;
+
+  /**
+   * 科室
+   */
+  deptId?: string | number;
+
+  /**
+   * 门诊号
+   */
+  outpatientNo?: string;
 
+  searchValue?: string;
 
+  dateRange?: string[];
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

BIN
src/assets/images/no_pay.png


+ 21 - 0
src/store/modules/diagnosis.ts

@@ -0,0 +1,21 @@
+import {defineStore} from 'pinia';
+import {DiagnosisVO} from '@/api/patients/diagnosis/types';
+
+export const useNutritionDiagnosisStore = defineStore('diagnosis', () => {
+  const diagnosisList = ref<DiagnosisVO[]>([]);
+  const diagnosisInfo = ref<DiagnosisVO>();
+  const setDiagnosisList = (val) => {
+    diagnosisList.value = val;
+  };
+
+  const setDiagnosisInfo = (val: DiagnosisVO) => {
+    diagnosisInfo.value = val;
+  };
+
+  return {
+    diagnosisList,
+    diagnosisInfo,
+    setDiagnosisList,
+    setDiagnosisInfo
+  };
+});

+ 15 - 0
src/store/modules/hospital.ts

@@ -0,0 +1,15 @@
+import {defineStore} from 'pinia';
+import {reactive} from 'vue';
+import {MealPlanVO} from '@/api/patients/hospitalMealPlan/types';
+
+export const useHospitalStore = defineStore('hospital', () => {
+  const hospitalList = ref<MealPlanVO[]>([]);
+  const setHospitalList = (val) => {
+    hospitalList.value = val;
+  };
+
+  return {
+    hospitalList,
+    setHospitalList
+  };
+});

+ 104 - 90
src/views/patients/dietTherapy/addDaily.vue

@@ -29,7 +29,6 @@
                 <el-button v-for="(recipe, index) in allTableData" :key="index" :type="currentRecipe === index ? 'success' : 'info'" plain icon="Document" class="tab-btn" :class="{active: currentRecipe === index}" @click="switchRecipe(index)">
                     食谱{{ index + 1 }}
                     <el-icon class="close-icon" @click.stop="deleteRecipe(index)" v-if="allTableData.length > 1">
-
                         <Close />
                     </el-icon>
                 </el-button>
@@ -37,7 +36,6 @@
             <el-alert title="周食谱模板的食谱数量小于7时,食谱可循环使用" type="warning" show-icon class="mb-2 info-alert" :closable="false" style="background: transparent; border: none; color: #ff9900" />
 
             <el-table :data="tableData" class="diet-table" border>
-
                 <el-table-column prop="meal" label="餐次" width="200px" align="center" />
                 <el-table-column prop="time" label="用餐时间" width="260px" align="center">
                     <template #default="{row}">
@@ -66,7 +64,7 @@
                 </el-table-column>
                 <el-table-column prop="categoryName" label="食谱分类" width="220px" align="center">
                     <template #default="{row}">
-                        <div v-for="(recipe) in row.recipes" :key="recipe.id" class="recipe-item">
+                        <div v-for="recipe in row.recipes" :key="recipe.id" class="recipe-item">
                             <div class="recipe-input-one">
                                 {{ recipe.categoryName }}
                             </div>
@@ -78,11 +76,11 @@
                         <el-input-number v-model="row.count" :min="1" :max="99" @change="updateRowData(row)" size="small" />
                     </template>
                 </el-table-column>
-               <el-table-column label="食材重量" align="center">
-                    <template #default="{ row }">
+                <el-table-column label="食材重量" align="center">
+                    <template #default="{row}">
                         <div v-if="row.recipes && row.recipes.length">
-                            <div v-for="(recipe) in row.recipes" :key="recipe.id">
-                                {{ getRecipeWeight(recipe,row.count) }}
+                            <div v-for="recipe in row.recipes" :key="recipe.id">
+                                {{ getRecipeWeight(recipe, row.count) }}
                             </div>
                         </div>
                         <span v-else>-</span>
@@ -90,75 +88,16 @@
                 </el-table-column>
                 <el-table-column prop="calorie" label="热量" align="center">
                     <template #default="{row}">
-                        <span>{{ row.calorie }}</span>
+                        <div v-if="row.recipes && row.recipes.length">
+                            <div v-for="recipe in row.recipes" :key="recipe.id">
+                                {{ getRecipeCalorie(recipe, row.calorie) }}
+                            </div>
+                        </div>
+                        <span v-else>-</span>
                     </template>
                 </el-table-column>
             </el-table>
-
         </div>
-        <!-- 饼状图表卡片 -->
-        <el-card>
-            <el-tabs v-model="activeTab" class="mt-4">
-                <el-tab-pane label="三大营养分析" name="nutrition">
-                    <div class="nutrition-analysis">
-                        <div class="nutrition-header">
-                            <div class="nutrition-target">
-                                <span>营养设定:</span>
-                                <span class="value">{{ nutritionTarget }}kcal/d</span>
-                            </div>
-                            <div class="nutrition-actual">
-                                <span>实际热量:</span>
-                                <span class="value">{{ actualCalories }}kcal/d</span>
-                            </div>
-                        </div>
-
-                        <el-row :gutter="24">
-                            <el-col :span="14">
-                                <el-table :data="nutritionData" border class="mt-4">
-                                    <el-table-column prop="name" label="三大营养素" width="180" />
-                                    <el-table-column prop="weight" label="质量(g)" width="180" />
-                                    <el-table-column prop="ratio" label="热量占比">
-                                        <template #default="{row}">
-                                            <span>{{ row.ratio }}%</span>
-                                        </template>
-                                    </el-table-column>
-                                    <el-table-column prop="reference" label="参考值">
-                                        <template #default="{row}">
-                                            <span>{{ row.reference }}</span>
-                                        </template>
-                                    </el-table-column>
-                                </el-table>
-                            </el-col>
-
-                            <el-col :span="10">
-                                <div class="chart-container">
-                                    <div class="chart-title">三大营养素元素质量占比</div>
-                                    <div id="nutritionChart" class="chart-content"></div>
-                                    <div class="chart-legend">
-                                        <span class="legend-item">
-                                            <span class="color-block protein"></span>
-                                            蛋白质 {{ proteinRatio }}%
-                                        </span>
-                                        <span class="legend-item">
-                                            <span class="color-block fat"></span>
-                                            脂肪 {{ fatRatio }}%
-                                        </span>
-                                        <span class="legend-item">
-                                            <span class="color-block carbs"></span>
-                                            碳水化合物 {{ carbsRatio }}%
-                                        </span>
-                                    </div>
-                                </div>
-                            </el-col>
-                        </el-row>
-                    </div>
-                </el-tab-pane>
-
-                <el-tab-pane label="营养数据分析" name="data">
-                    <!-- 营养数据分析内容 -->
-                </el-tab-pane>
-            </el-tabs>
-        </el-card>
 
         <!-- 底部按钮卡片 -->
         <div class="bottom-btn-card">
@@ -180,8 +119,9 @@
     import CommonDialog from './components/CommonDialog.vue';
     import RecipeTemplate from './components/RecipeTemplate.vue';
     const emit = defineEmits(['goBack', 'submitDaily']);
-    import { MealRecipeVO, MealRecipeQuery, MealRecipeForm } from '@/api/patients/dailyMealRecipe/types';
+    import { MealRecipeForm } from '@/api/patients/dailyMealRecipe/types';
     import { ElMessage } from 'element-plus';
+    import { MealPlanVO } from '@/api/patients/dailyMealPlan/types';
 
     const props = defineProps({
         patientInfo: {
@@ -193,6 +133,10 @@
                 age: '',
                 gender: ''
             })
+        },
+        rowData: {
+            type: Object as PropType < MealPlanVO | null > ,
+            default: null
         }
     });
     const DRAFT_KEY = computed(() => 'addHospitalDraft_' + props.patientInfo.id);
@@ -226,8 +170,6 @@
         recipes ? : Recipe[];
     }
 
-
-
     // 定义食谱模板数据结构
     interface RecipeTemplateItem {
         name: string;
@@ -264,12 +206,13 @@
         { meal: '晚加', time: '18:30', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', recipes: [] }
     ];
 
-
     const allTableData = ref < TableRow[][] > ([JSON.parse(JSON.stringify(initialTableData))]);
     const currentRecipe = ref(0);
     const tableData = computed({
         get: () => allTableData.value[currentRecipe.value],
-        set: (val) => { allTableData.value[currentRecipe.value] = val; }
+        set: (val) => {
+            allTableData.value[currentRecipe.value] = val;
+        }
     });
 
     const recipes = ref([0]); // 食谱列表
@@ -278,14 +221,14 @@
     // 新增食谱,最多7个
     const addRecipe = () => {
         if (allTableData.value.length >= 7) {
-            ElMessage.warning('最多只能添加7个食谱');
+            openRecipeTemplate();
             return;
         }
         allTableData.value.push(JSON.parse(JSON.stringify(initialTableData)));
         currentRecipe.value = allTableData.value.length - 1;
     };
 
-      function convertTableDataToMealRecipeList(tableData: TableRow[], tabNo: number): MealRecipeForm[] {
+    function convertTableDataToMealRecipeList(tableData: TableRow[], tabNo: number): MealRecipeForm[] {
         const result: MealRecipeForm[] = [];
         tableData.forEach((row) => {
             if (row.recipes && row.recipes.length > 0) {
@@ -302,7 +245,7 @@
                         foodWeight: singleWeight * row.count, // 这里乘以份数
                         calorie: recipe.calorie ? Number(recipe.calorie) : undefined,
                         amount: row.count,
-                        foodCategoryName: recipe.categoryName,
+                        foodCategoryName: recipe.categoryName
                     });
                 });
             }
@@ -326,6 +269,15 @@
         return (weight * count).toFixed(4);
     }
 
+    function getRecipeCalorie(recipe, count = 1) {
+        // 如果有 recipe.calorie 字段
+        let calorie = 0;
+        if (recipe.calorie) {
+            calorie = parseFloat(recipe.calorie) || 0;
+        }
+        return (calorie * count).toFixed(2);
+    }
+
     function parseRecipeWeight(recipe) {
         let weight = 0;
         if (recipe.weight) {
@@ -354,7 +306,6 @@
             mealRecipeList
         };
 
-
         emit('submitDaily', mealPlanForm);
         emit('goBack'); // 让父组件切换回 hospitalIndex
         localStorage.removeItem(DRAFT_KEY.value); // 提交成功后清除缓存
@@ -364,7 +315,7 @@
         const draft = {
             mealTimeRange: mealTimeRange.value,
             allTableData: allTableData.value,
-            currentRecipe: currentRecipe.value,
+            currentRecipe: currentRecipe.value
             // 你还可以加其它需要缓存的字段
         };
         localStorage.setItem(DRAFT_KEY.value, JSON.stringify(draft));
@@ -386,9 +337,12 @@
     }
 
     // 监听患者切换自动加载草稿
-    watch(() => props.patientInfo.id, () => {
-        loadDraft();
-    }, { immediate: true });
+    watch(
+        () => props.patientInfo.id,
+        () => {
+            loadDraft();
+        }, { immediate: true }
+    );
 
     // 切换食谱
     const switchRecipe = (index: number) => {
@@ -397,7 +351,6 @@
 
     // 删除食谱
     const deleteRecipe = (index: number) => {
-
         if (allTableData.value.length === 1) return;
         allTableData.value.splice(index, 1);
         if (currentRecipe.value >= allTableData.value.length) {
@@ -469,7 +422,6 @@
     const total = ref(1869);
     const selectedRecipes = ref < Recipe[] > ([]);
 
-
     const currentRow = ref < TableRow | null > (null);
     const currentIndex = ref < number > (-1);
     const dialogRef = ref < InstanceType < typeof CommonDialog > | null > (null);
@@ -539,7 +491,6 @@
 
     // 更新行数据的逻辑优化
     const updateRowData = (row: TableRow) => {
-
         if (row.recipes ?.length) {
             // 更新菜品名称
             row.menuName = row.recipes.map((recipe) => recipe.name).join('、');
@@ -607,11 +558,75 @@
         recipeTemplateRef.value ?.openDialog();
     };
 
+    watch(
+        () => props.rowData,
+        (newVal) => {
+            if (newVal ?.mealRecipeList) {
+                // 1. 清空现有数据
+                allTableData.value = [];
+                // 2. 按 recipeNo 分组
+                const recipesByNo: Record < number, MealRecipeForm[] > = {};
+                newVal.mealRecipeList.forEach((recipe) => {
+                    if (!recipesByNo[recipe.recipeNo]) {
+                        recipesByNo[recipe.recipeNo] = [];
+                    }
+                    recipesByNo[recipe.recipeNo].push(recipe);
+                });
+
+                // 3. 为每个 recipeNo 创建对应的食谱 tab
+                Object.keys(recipesByNo).forEach((no) => {
+                    const recipeNo = parseInt(no, 10);
+                    const recipes = recipesByNo[recipeNo];
+
+                    // 初始化一个新的食谱 tab
+                    const newTableData = JSON.parse(JSON.stringify(initialTableData));
+
+                    // 填充数据
+                    recipes.forEach((recipe) => {
+                        const targetRow = newTableData.find((row) => row.meal === recipe.mealTime);
+                        if (targetRow) {
+                            if (!targetRow.recipes) {
+                                targetRow.recipes = [];
+                            }
+
+                            targetRow.recipes.push({
+                                id: recipe.foodId,
+                                name: recipe.foodName,
+                                categoryId: recipe.foodCategoryId,
+                                categoryName: recipe.foodCategoryName,
+                                weight: `${recipe.foodWeight}g`,
+                                calorie: recipe.calorie ?.toString()
+                            });
+
+                            // 更新用餐时间
+                            if (recipe.eatTime) {
+                                const time = new Date(recipe.eatTime);
+                                const hours = time.getHours().toString().padStart(2, '0');
+                                const minutes = time.getMinutes().toString().padStart(2, '0');
+                                targetRow.time = `${hours}:${minutes}`;
+                            }
+
+                            // 更新份数
+                            targetRow.count = recipe.amount || 1;
+                        }
+                    });
+
+                    // 添加到 allTableData
+                    allTableData.value.push(newTableData);
+                });
+
+                // 4. 如果没有数据,至少保留一个空 tab
+                if (allTableData.value.length === 0) {
+                    allTableData.value = [JSON.parse(JSON.stringify(initialTableData))];
+                }
+            }
+        }, { immediate: true }
+    );
+
     onMounted(() => {
         initChart();
         loadDraft();
     });
-
 </script>
 <style lang="scss" scoped>
     .container {
@@ -933,7 +948,6 @@
                     line-height: 32px;
                     padding: 0 1px;
                     border: 1px solid #dcdfe6;
-
                 }
             }
 

+ 1053 - 925
src/views/patients/dietTherapy/addHospital.vue

@@ -1,992 +1,1120 @@
 <template>
-    <div class="container" @keydown.enter.prevent>
-        <!-- 中间卡片 -->
-        <div class="add-hospital-wrapper">
-            <div class="header-bar">
-                <el-button @click="goBack" type="default" icon="ArrowLeft" class="back-btn">返回</el-button>
-                <span class="title">院内膳食</span>
-            </div>
-            <div class="form-bar">
-                <el-row :gutter="20" align="middle">
-                    <el-col :span="3">
-                        <span>配餐日期:</span>
-                    </el-col>
-                    <el-col :span="8">
-                        <el-date-picker v-model="mealTimeRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" style="width: 100%" @keydown.enter.prevent />
-                    </el-col>
-                    <el-col :span="3">
-                        <el-button type="primary" @click.prevent="addRecipe">新增食谱</el-button>
-                    </el-col>
-                    <el-col :span="3">
-                        <el-button @click.prevent="openRecipeTemplate">食谱模板</el-button>
-                    </el-col>
-                    <el-col :span="3">
-                        <el-button type="danger" @click.prevent="deleteAllRecipes">全部删除</el-button>
-                    </el-col>
-                </el-row>
-            </div>
-            <div class="tab-bar">
-                <el-button v-for="(recipe, index) in allTableData" :key="index" :type="currentRecipe === index ? 'success' : 'info'" plain icon="Document" class="tab-btn" :class="{active: currentRecipe === index}" @click="switchRecipe(index)">
-                    食谱{{ index + 1 }}
-                    <el-icon class="close-icon" @click.stop="deleteRecipe(index)" v-if="allTableData.length > 1">
-
-                        <Close />
+  <div class="container" @keydown.enter.prevent>
+    <!-- 中间卡片 -->
+    <div class="add-hospital-wrapper">
+      <div class="header-bar">
+        <el-button @click="goBack" type="default" icon="ArrowLeft" class="back-btn">返回</el-button>
+        <span class="title">院内膳食</span>
+      </div>
+      <div class="form-bar">
+        <el-row :gutter="20" align="middle">
+          <el-col :span="3">
+            <span>配餐日期:</span>
+          </el-col>
+          <el-col :span="8">
+            <el-date-picker
+              v-model="mealTimeRange"
+              type="daterange"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              style="width: 100%"
+              @keydown.enter.prevent
+            />
+          </el-col>
+          <el-col :span="3">
+            <el-button type="primary" @click.prevent="addRecipe">新增食谱</el-button>
+          </el-col>
+          <el-col :span="3">
+            <el-button @click.prevent="openRecipeTemplate">食谱模板</el-button>
+          </el-col>
+          <el-col :span="3">
+            <el-button type="danger" @click.prevent="deleteAllRecipes">全部删除</el-button>
+          </el-col>
+        </el-row>
+      </div>
+      <div class="tab-bar">
+        <el-button
+          v-for="(recipe, index) in allTableData"
+          :key="index"
+          :type="currentRecipe === index ? 'success' : 'info'"
+          plain
+          icon="Document"
+          class="tab-btn"
+          :class="{active: currentRecipe === index}"
+          @click="switchRecipe(index)"
+        >
+          食谱{{ index + 1 }}
+          <el-icon class="close-icon" @click.stop="deleteRecipe(index)" v-if="allTableData.length > 1">
+            <Close />
+          </el-icon>
+        </el-button>
+      </div>
+      <el-alert
+        title="周食谱模板的食谱数量小于7时,食谱可循环使用"
+        type="warning"
+        show-icon
+        class="mb-2 info-alert"
+        :closable="false"
+        style="background: transparent; border: none; color: #ff9900"
+      />
+
+      <el-table :data="tableData" class="diet-table" border>
+        <el-table-column prop="meal" label="餐次" width="200px" align="center" />
+        <el-table-column prop="time" label="用餐时间" width="260px" align="center">
+          <template #default="{row}">
+            <el-time-select v-model="row.time" start="06:00" step="00:30" end="22:00" placeholder="选择时间" />
+          </template>
+        </el-table-column>
+        <el-table-column prop="menuName" label="食谱名称" width="350px" align="center">
+          <template #default="{row}">
+            <div class="recipe-list">
+              <div v-if="!row.recipes?.length" class="recipe-input" @click.stop.prevent="openRecipeDialog(row)">请选择</div>
+              <template v-else>
+                <div v-for="(recipe, index) in row.recipes" :key="recipe.id" class="recipe-item">
+                  <div class="recipe-input" @click.stop.prevent="openRecipeDialog(row, index)">
+                    {{ recipe.name }}
+                  </div>
+                  <el-button type="danger" link class="delete-btn" @click.stop="removeRecipe(row, index)">
+                    <el-icon>
+                      <Delete />
                     </el-icon>
-                </el-button>
+                  </el-button>
+                </div>
+                <!-- <div class="recipe-input add-more" @click.stop.prevent="openRecipeDialog(row)">请选择</div> -->
+              </template>
             </div>
-            <el-alert title="周食谱模板的食谱数量小于7时,食谱可循环使用" type="warning" show-icon class="mb-2 info-alert" :closable="false" style="background: transparent; border: none; color: #ff9900" />
-
-            <el-table :data="tableData" class="diet-table" border>
-
-                <el-table-column prop="meal" label="餐次" width="200px" align="center" />
-                <el-table-column prop="time" label="用餐时间" width="260px" align="center">
-                    <template #default="{row}">
-                        <el-time-select v-model="row.time" start="06:00" step="00:30" end="22:00" placeholder="选择时间" />
-                    </template>
-                </el-table-column>
-                <el-table-column prop="menuName" label="食谱名称" width="350px" align="center">
-                    <template #default="{row}">
-                        <div class="recipe-list">
-                            <div v-if="!row.recipes?.length" class="recipe-input" @click.stop.prevent="openRecipeDialog(row)">请选择</div>
-                            <template v-else>
-                                <div v-for="(recipe, index) in row.recipes" :key="recipe.id" class="recipe-item">
-                                    <div class="recipe-input" @click.stop.prevent="openRecipeDialog(row, index)">
-                                        {{ recipe.name }}
-                                    </div>
-                                    <el-button type="danger" link class="delete-btn" @click.stop="removeRecipe(row, index)">
-                                        <el-icon>
-                                            <Delete />
-                                        </el-icon>
-                                    </el-button>
-                                </div>
-                                <!-- <div class="recipe-input add-more" @click.stop.prevent="openRecipeDialog(row)">请选择</div> -->
-                            </template>
-                        </div>
-                    </template>
-                </el-table-column>
-                <el-table-column prop="categoryName" label="食谱分类" width="220px" align="center">
-                    <template #default="{row}">
-                        <div v-for="(recipe) in row.recipes" :key="recipe.id" class="recipe-item">
-                            <div class="recipe-input-one">
-                                {{ recipe.categoryName }}
-                            </div>
-                        </div>
-                    </template>
-                </el-table-column>
-                <el-table-column prop="count" label="份数" width="220px" align="center">
-                    <template #default="{row}">
-                        <el-input-number v-model="row.count" :min="1" :max="99" @change="updateRowData(row)" size="small" />
-                    </template>
-                </el-table-column>
-                <!-- <el-table-column prop="weight" label="食材重量" align="center">
+          </template>
+        </el-table-column>
+        <el-table-column prop="categoryName" label="食谱分类" width="220px" align="center">
+          <template #default="{row}">
+            <div v-for="recipe in row.recipes" :key="recipe.id" class="recipe-item">
+              <div class="recipe-input-one">
+                {{ recipe.categoryName }}
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="count" label="份数" width="220px" align="center">
+          <template #default="{row}">
+            <el-input-number v-model="row.count" :min="1" :max="99" @change="updateRowData(row)" size="small" />
+          </template>
+        </el-table-column>
+        <!-- <el-table-column prop="weight" label="食材重量" align="center">
                     <template #default="{row}">
                         <span>{{ row.weight || '-' }}</span>
                     </template>
                 </el-table-column> -->
-                <el-table-column label="食材重量" align="center">
-                    <template #default="{ row }">
-                        <div v-if="row.recipes && row.recipes.length">
-                            <div v-for="(recipe) in row.recipes" :key="recipe.id">
-                                {{ getRecipeWeight(recipe,row.count) }}
-                            </div>
-                        </div>
-                        <span v-else>-</span>
-                    </template>
-                </el-table-column>
-                <el-table-column prop="calorie" label="热量" align="center">
-                    <template #default="{row}">
-                        <span>{{ row.calorie }}</span>
-                    </template>
-                </el-table-column>
-                <el-table-column prop="amount" label="金额" align="center">
-                    <template #default="{row}">
-                        <span>{{ row.amount || '0.00' }}</span>
-                    </template>
-                </el-table-column>
-            </el-table>
-
-            <div class="footer-bar">
-                <span>费用:</span>
-                <span class="amount">0.00元</span>
+        <el-table-column label="食材重量" align="center">
+          <template #default="{row}">
+            <div v-if="row.recipes && row.recipes.length">
+              <div v-for="recipe in row.recipes" :key="recipe.id">
+                {{ getRecipeWeight(recipe, row.count) }}
+              </div>
+            </div>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="calorie" label="热量" align="center">
+          <template #default="{row}">
+            <div v-if="row.recipes && row.recipes.length">
+              <div v-for="recipe in row.recipes" :key="recipe.id">
+                {{ getRecipeCalorie(recipe, row.calorie) }}
+              </div>
             </div>
-        </div>
-        <!-- 饼状图表卡片 -->
-        <el-card>
-            <el-tabs v-model="activeTab" class="mt-4">
-                <el-tab-pane label="三大营养分析" name="nutrition">
-                    <div class="nutrition-analysis">
-                        <div class="nutrition-header">
-                            <div class="nutrition-target">
-                                <span>营养设定:</span>
-                                <span class="value">{{ nutritionTarget }}kcal/d</span>
-                            </div>
-                            <div class="nutrition-actual">
-                                <span>实际热量:</span>
-                                <span class="value">{{ actualCalories }}kcal/d</span>
-                            </div>
-                        </div>
-
-                        <el-row :gutter="24">
-                            <el-col :span="14">
-                                <el-table :data="nutritionData" border class="mt-4">
-                                    <el-table-column prop="name" label="三大营养素" width="180" />
-                                    <el-table-column prop="weight" label="质量(g)" width="180" />
-                                    <el-table-column prop="ratio" label="热量占比">
-                                        <template #default="{row}">
-                                            <span>{{ row.ratio }}%</span>
-                                        </template>
-                                    </el-table-column>
-                                    <el-table-column prop="reference" label="参考值">
-                                        <template #default="{row}">
-                                            <span>{{ row.reference }}</span>
-                                        </template>
-                                    </el-table-column>
-                                </el-table>
-                            </el-col>
-
-                            <el-col :span="10">
-                                <div class="chart-container">
-                                    <div class="chart-title">三大营养素元素质量占比</div>
-                                    <div id="nutritionChart" class="chart-content"></div>
-                                    <div class="chart-legend">
-                                        <span class="legend-item">
-                                            <span class="color-block protein"></span>
-                                            蛋白质 {{ proteinRatio }}%
-                                        </span>
-                                        <span class="legend-item">
-                                            <span class="color-block fat"></span>
-                                            脂肪 {{ fatRatio }}%
-                                        </span>
-                                        <span class="legend-item">
-                                            <span class="color-block carbs"></span>
-                                            碳水化合物 {{ carbsRatio }}%
-                                        </span>
-                                    </div>
-                                </div>
-                            </el-col>
-                        </el-row>
-                    </div>
-                </el-tab-pane>
-
-                <el-tab-pane label="营养数据分析" name="data">
-                    <!-- 营养数据分析内容 -->
-                </el-tab-pane>
-            </el-tabs>
-        </el-card>
-
-        <!-- 底部按钮卡片 -->
-        <div class="bottom-btn-card">
-            <div class="btn-wrapper">
-                <el-button type="info" plain @click="saveDraft">存为草稿</el-button>
-                <el-button type="primary" @click="handleSubmit">提交</el-button>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="金额" align="center">
+          <template #default="{row}">
+            <div v-if="row.recipes && row.recipes.length">
+              <div v-for="recipe in row.recipes" :key="recipe.id">
+                {{ getRecipeAmount(recipe, row.count) }}
+              </div>
             </div>
-        </div>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="footer-bar">
+        <span>费用:</span>
+        <span class="amount">{{ totalPrice }}</span>
+      </div>
+    </div>
+
+    <!-- 底部按钮卡片 -->
+    <div class="bottom-btn-card">
+      <div class="btn-wrapper">
+        <el-button type="info" plain @click="saveDraft">存为草稿</el-button>
+        <el-button type="primary" @click="handleSubmit">提交</el-button>
+      </div>
     </div>
+  </div>
 
-    <!-- 添加弹窗组件 -->
-    <CommonDialog ref="dialogRef" @confirm="handleRecipeConfirm" @cancel="handleRecipeCancel" />
-    <!-- 食谱模板弹窗组件 -->
-    <RecipeTemplate ref="recipeTemplateRef" @confirm="handleRecipeTemplateConfirm" />
+  <!-- 添加弹窗组件 -->
+  <CommonDialog ref="dialogRef" @confirm="handleRecipeConfirm" @cancel="handleRecipeCancel" />
+  <!-- 食谱模板弹窗组件 -->
+  <RecipeTemplate ref="recipeTemplateRef" @confirm="handleRecipeTemplateConfirm" />
 </template>
 <script setup lang="ts">
-    import { ref, onMounted, computed, watch } from 'vue';
-    import * as echarts from 'echarts';
-    import CommonDialog from './components/CommonDialog.vue';
-    import RecipeTemplate from './components/RecipeTemplate.vue';
-    const emit = defineEmits(['goBack', 'submitHospital']);
-    import { MealRecipeForm } from '@/api/patients/hospitalMealRecipe/types';
-    import { ElMessage } from 'element-plus';
-
-
-
-    const props = defineProps({
-        patientInfo: {
-            type: Object,
-            required: true,
-            default: () => ({
-                id: '',
-                name: '',
-                age: '',
-                gender: ''
-            })
-        }
+import {ref, onMounted, computed, watch, nextTick} from 'vue';
+import {MealPlanVO} from '@/api/patients/hospitalMealPlan/types';
+
+import * as echarts from 'echarts';
+import CommonDialog from './components/CommonDialog.vue';
+import RecipeTemplate from './components/RecipeTemplate.vue';
+const emit = defineEmits(['goBack', 'submitHospital']);
+import {MealRecipeForm} from '@/api/patients/hospitalMealRecipe/types';
+import {ElMessage} from 'element-plus';
+import {useHospitalStore} from '@/store/modules/hospital';
+
+const useStore = useHospitalStore();
+
+const props = defineProps({
+  patientInfo: {
+    type: Object,
+    required: true,
+    default: () => ({
+      id: '',
+      name: '',
+      age: '',
+      gender: ''
+    })
+  },
+  rowData: {
+    type: Object as PropType<MealPlanVO | null>,
+    default: null
+  }
+});
+const DRAFT_KEY = computed(() => 'addHospitalDraft_' + props.patientInfo.id);
+interface Recipe {
+  id: number;
+  name: string;
+  categoryId: number;
+  categoryName: string;
+  ingredients: string;
+  selected?: boolean;
+  weight?: string; // 添加可选的weight属性
+  calorie?: string; // 添加可选的calorie属性
+}
+
+interface Category {
+  id: string;
+  name: string;
+}
+
+interface TableRow {
+  meal: string;
+  time: string;
+  foodId: string;
+  menuName: string;
+  categoryId: string;
+  categoryName: string;
+  count: number;
+  weight: string;
+  calorie: string;
+  amount: string;
+  recipes?: Recipe[];
+}
+
+// 定义食谱模板数据结构
+interface RecipeTemplateItem {
+  name: string;
+  categoryId: number;
+  categoryName: string;
+  meals: Array<{
+    meal: string;
+    dish: string;
+    weight: string;
+    kcal: string;
+  }>;
+}
+
+const mealTimeRange = ref([new Date(), new Date()]);
+const activeTab = ref('nutrition');
+const totalPrice = ref(0.0);
+
+// 计算总价格
+const calculateTotalPrice = () => {
+  let total = 0;
+  allTableData.value.forEach((tableData) => {
+    tableData.forEach((row) => {
+      // 直接使用行的总金额,因为 row.amount 已经包含了该行所有食谱的总金额
+      if (row.amount) {
+        total += parseFloat(row.amount) || 0;
+      }
     });
-    const DRAFT_KEY = computed(() => 'addHospitalDraft_' + props.patientInfo.id);
-    interface Recipe {
-        id: number;
-        name: string;
-        categoryId: number;
-        categoryName: string;
-        ingredients: string;
-        selected ? : boolean;
-        weight ? : string; // 添加可选的weight属性
-        calorie ? : string; // 添加可选的calorie属性
+  });
+  totalPrice.value = total;
+};
+
+const nutritionData = ref([
+  {name: '蛋白质', weight: '', ratio: 0, reference: '10% - 15%'},
+  {name: '脂肪', weight: '', ratio: 0, reference: '20% - 30%'},
+  {name: '碳水化合物', weight: '', ratio: 0, reference: '50% - 65%'}
+]);
+
+const initialTableData: TableRow[] = [
+  {
+    meal: '早餐',
+    time: '08:00',
+    foodId: '',
+    menuName: '',
+    categoryId: '',
+    categoryName: '',
+    count: 1,
+    weight: '',
+    calorie: '',
+    amount: '',
+    recipes: []
+  },
+  {
+    meal: '早加',
+    time: '08:30',
+    foodId: '',
+    menuName: '',
+    categoryId: '',
+    categoryName: '',
+    count: 1,
+    weight: '',
+    calorie: '',
+    amount: '',
+    recipes: []
+  },
+  {
+    meal: '中餐',
+    time: '12:00',
+    foodId: '',
+    menuName: '',
+    categoryId: '',
+    categoryName: '',
+    count: 1,
+    weight: '',
+    calorie: '',
+    amount: '',
+    recipes: []
+  },
+  {
+    meal: '中加',
+    time: '12:30',
+    foodId: '',
+    menuName: '',
+    categoryId: '',
+    categoryName: '',
+    count: 1,
+    weight: '',
+    calorie: '',
+    amount: '',
+    recipes: []
+  },
+  {
+    meal: '晚餐',
+    time: '18:00',
+    foodId: '',
+    menuName: '',
+    categoryId: '',
+    categoryName: '',
+    count: 1,
+    weight: '',
+    calorie: '',
+    amount: '',
+    recipes: []
+  },
+  {
+    meal: '晚加',
+    time: '18:30',
+    foodId: '',
+    menuName: '',
+    categoryId: '',
+    categoryName: '',
+    count: 1,
+    weight: '',
+    calorie: '',
+    amount: '',
+    recipes: []
+  }
+];
+
+const allTableData = ref<TableRow[][]>([JSON.parse(JSON.stringify(initialTableData))]);
+const currentRecipe = ref(0);
+const tableData = computed({
+  get: () => allTableData.value[currentRecipe.value],
+  set: (val) => {
+    allTableData.value[currentRecipe.value] = val;
+  }
+});
+
+const recipes = ref([0]); // 食谱列表
+
+// 添加食谱
+// 新增食谱,最多7个
+const addRecipe = () => {
+  if (allTableData.value.length >= 7) {
+    openRecipeTemplate();
+    return;
+  }
+  allTableData.value.push(JSON.parse(JSON.stringify(initialTableData)));
+  currentRecipe.value = allTableData.value.length - 1;
+};
+
+function convertTableDataToMealRecipeList(tableData: TableRow[], tabNo: number): MealRecipeForm[] {
+  const result: MealRecipeForm[] = [];
+  tableData.forEach((row) => {
+    if (row.recipes && row.recipes.length > 0) {
+      row.recipes.forEach((recipe) => {
+        // 计算单个食谱的重量并乘以份数
+        const singleWeight = parseRecipeWeight(recipe);
+        result.push({
+          recipeNo: tabNo,
+          mealTime: row.meal,
+          eatTime: row.time,
+          foodId: recipe.id,
+          foodName: recipe.name,
+          foodCategoryId: recipe.categoryId,
+          foodWeight: singleWeight * row.count, // 这里乘以份数
+          calorie: recipe.calorie ? Number(recipe.calorie) : undefined,
+          amount: row.count,
+          foodCategoryName: recipe.categoryName,
+          price: row.amount ? Number(row.amount) : undefined
+        });
+      });
     }
-
-    interface Category {
-        id: string;
-        name: string;
+  });
+  return result;
+}
+
+function getRecipeWeight(recipe, count = 1) {
+  let weight = 0;
+  if (recipe.weight) {
+    weight = parseFloat(recipe.weight.replace(/[^\d.]/g, '') || '0');
+  } else if (recipe.ingredients) {
+    const matches = recipe.ingredients.match(/([\d.]+)g/g);
+    if (matches) {
+      weight = matches.reduce((sum, item) => {
+        const num = parseFloat(item.replace('g', ''));
+        return sum + (isNaN(num) ? 0 : num);
+      }, 0);
     }
-
-    interface TableRow {
-        meal: string;
-        time: string;
-        foodId: string;
-        menuName: string;
-        categoryId: string;
-        categoryName: string;
-        count: number;
-        weight: string;
-        calorie: string;
-        amount: string;
-        recipes ? : Recipe[];
+  }
+  return (weight * count).toFixed(4);
+}
+
+function getRecipeAmount(recipe, count = 1) {
+  // 如果有 recipe.price 字段
+  let price = 0;
+  if (recipe.amount) {
+    price = parseFloat(recipe.amount) || 0;
+  }
+  return (price * count).toFixed(2);
+}
+
+function getRecipeCalorie(recipe, count = 1) {
+  // 如果有 recipe.calorie 字段
+  let calorie = 0;
+  if (recipe.calorie) {
+    calorie = parseFloat(recipe.calorie) || 0;
+  }
+  return (calorie * count).toFixed(2);
+}
+
+function parseRecipeWeight(recipe) {
+  let weight = 0;
+  if (recipe.weight) {
+    weight = parseFloat(recipe.weight.replace(/[^\d.]/g, '') || '0');
+  } else if (recipe.ingredients) {
+    const matches = recipe.ingredients.match(/([\d.]+)g/g);
+    if (matches) {
+      weight = matches.reduce((sum, item) => {
+        const num = parseFloat(item.replace('g', ''));
+        return sum + (isNaN(num) ? 0 : num);
+      }, 0);
     }
-
-
-
-    // 定义食谱模板数据结构
-    interface RecipeTemplateItem {
-        name: string;
-        categoryId: number;
-        categoryName: string;
-        meals: Array < {
-            meal: string;
-            dish: string;
-            weight: string;
-            kcal: string;
-        } > ;
+  }
+  return weight;
+}
+
+const handleSubmit = () => {
+  // 合并所有食谱tab下的明细
+  let mealRecipeList: MealRecipeForm[] = [];
+  allTableData.value.forEach((table, tabIdx) => {
+    mealRecipeList = mealRecipeList.concat(convertTableDataToMealRecipeList(table, tabIdx + 1));
+  });
+  const mealPlanForm = {
+    // ...其它表单字段
+    mealTimeRange: mealTimeRange.value,
+    totalPrice: totalPrice.value,
+    mealRecipeList
+  };
+
+  emit('submitHospital', mealPlanForm);
+  emit('goBack'); // 让父组件切换回 hospitalIndex
+  localStorage.removeItem(DRAFT_KEY.value); // 提交成功后清除缓存
+};
+
+function saveDraft() {
+  const draft = {
+    mealTimeRange: mealTimeRange.value,
+    allTableData: allTableData.value,
+    currentRecipe: currentRecipe.value,
+    totalPrice: totalPrice.value
+    // 你还可以加其它需要缓存的字段
+  };
+  localStorage.setItem(DRAFT_KEY.value, JSON.stringify(draft));
+  ElMessage.success('操作成功');
+}
+
+function loadDraft() {
+  const draftStr = localStorage.getItem(DRAFT_KEY.value);
+  if (draftStr) {
+    try {
+      const draft = JSON.parse(draftStr);
+      if (draft.mealTimeRange) mealTimeRange.value = draft.mealTimeRange;
+      if (draft.allTableData) allTableData.value = draft.allTableData;
+      if (draft.totalPrice) totalPrice.value = draft.totalPrice;
+      if (draft.currentRecipe !== undefined) currentRecipe.value = draft.currentRecipe;
+    } catch (e) {
+      // 解析失败可忽略
     }
-
-    const mealTimeRange = ref([new Date(), new Date()]);
-    const activeTab = ref('nutrition');
-    const nutritionTarget = ref(897.3);
-    const actualCalories = ref(0.0);
-    const proteinRatio = ref(0);
-    const fatRatio = ref(0);
-    const carbsRatio = ref(0);
-
-    const nutritionData = ref([
-        { name: '蛋白质', weight: '', ratio: 0, reference: '10% - 15%' },
-        { name: '脂肪', weight: '', ratio: 0, reference: '20% - 30%' },
-        { name: '碳水化合物', weight: '', ratio: 0, reference: '50% - 65%' }
-    ]);
-
-    const initialTableData: TableRow[] = [
-        { meal: '早餐', time: '08:00', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', amount: '', recipes: [] },
-        { meal: '早加', time: '08:30', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', amount: '', recipes: [] },
-        { meal: '中餐', time: '12:00', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', amount: '', recipes: [] },
-        { meal: '中加', time: '12:30', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', amount: '', recipes: [] },
-        { meal: '晚餐', time: '18:00', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', amount: '', recipes: [] },
-        { meal: '晚加', time: '18:30', foodId: '', menuName: '', categoryId: '', categoryName: '', count: 1, weight: '', calorie: '', amount: '', recipes: [] }
-    ];
-
-
-    const allTableData = ref < TableRow[][] > ([JSON.parse(JSON.stringify(initialTableData))]);
-    const currentRecipe = ref(0);
-    const tableData = computed({
-        get: () => allTableData.value[currentRecipe.value],
-        set: (val) => { allTableData.value[currentRecipe.value] = val; }
-    });
-
-    const recipes = ref([0]); // 食谱列表
-
-    // 添加食谱
-    // 新增食谱,最多7个
-    const addRecipe = () => {
-        if (allTableData.value.length >= 7) {
-            ElMessage.warning('最多只能添加7个食谱');
-            return;
-        }
-        allTableData.value.push(JSON.parse(JSON.stringify(initialTableData)));
-        currentRecipe.value = allTableData.value.length - 1;
-    };
-
-    function convertTableDataToMealRecipeList(tableData: TableRow[], tabNo: number): MealRecipeForm[] {
-        const result: MealRecipeForm[] = [];
-        tableData.forEach((row) => {
-            if (row.recipes && row.recipes.length > 0) {
-                row.recipes.forEach((recipe) => {
-                    // 计算单个食谱的重量并乘以份数
-                    const singleWeight = parseRecipeWeight(recipe);
-                    result.push({
-                        recipeNo: tabNo,
-                        mealTime: row.meal,
-                        eatTime: row.time,
-                        foodId: recipe.id,
-                        foodName: recipe.name,
-                        foodCategoryId: recipe.categoryId,
-                        foodWeight: singleWeight * row.count, // 这里乘以份数
-                        calorie: recipe.calorie ? Number(recipe.calorie) : undefined,
-                        amount: row.count,
-                        foodCategoryName: recipe.categoryName,
-                        price: row.amount ? Number(row.amount) : undefined,
-                    });
-                });
-            }
-        });
-        return result;
+  }
+}
+
+// 切换食谱
+const switchRecipe = (index: number) => {
+  currentRecipe.value = index;
+};
+
+// 删除食谱
+const deleteRecipe = (index: number) => {
+  if (allTableData.value.length === 1) return;
+  allTableData.value.splice(index, 1);
+  if (currentRecipe.value >= allTableData.value.length) {
+    currentRecipe.value = allTableData.value.length - 1;
+  }
+};
+
+// 删除所有食谱
+const deleteAllRecipes = () => {
+  allTableData.value = [JSON.parse(JSON.stringify(initialTableData))];
+  currentRecipe.value = 0;
+};
+
+// 返回上一页按钮
+const goBack = () => {
+  emit('goBack');
+};
+
+// 食谱选择对话框
+
+const searchKeyword = ref('');
+const currentCategory = ref('');
+const currentPage = ref(1);
+const pageSize = ref(10);
+const total = ref(1869);
+const selectedRecipes = ref<Recipe[]>([]);
+
+const currentRow = ref<TableRow | null>(null);
+const currentIndex = ref<number>(-1);
+const dialogRef = ref<InstanceType<typeof CommonDialog> | null>(null);
+
+// 处理食谱确认
+const handleRecipeConfirm = (selectedRecipes: Recipe[]) => {
+  if (currentRow.value && selectedRecipes.length > 0) {
+    if (!currentRow.value.recipes) {
+      currentRow.value.recipes = [];
     }
 
-    function getRecipeWeight(recipe, count = 1) {
-        let weight = 0;
-        if (recipe.weight) {
-            weight = parseFloat(recipe.weight.replace(/[^\d.]/g, '') || '0');
-        } else if (recipe.ingredients) {
-            const matches = recipe.ingredients.match(/([\d.]+)g/g);
-            if (matches) {
-                weight = matches.reduce((sum, item) => {
-                    const num = parseFloat(item.replace('g', ''));
-                    return sum + (isNaN(num) ? 0 : num);
-                }, 0);
-            }
-        }
-        return (weight * count).toFixed(4);
+    if (currentIndex.value >= 0) {
+      // 更新已有食谱
+      currentRow.value.recipes[currentIndex.value] = selectedRecipes[0];
+    } else {
+      // 添加新食谱
+      currentRow.value.recipes.push(...selectedRecipes);
     }
 
-    function parseRecipeWeight(recipe) {
-        let weight = 0;
-        if (recipe.weight) {
-            weight = parseFloat(recipe.weight.replace(/[^\d.]/g, '') || '0');
-        } else if (recipe.ingredients) {
-            const matches = recipe.ingredients.match(/([\d.]+)g/g);
-            if (matches) {
-                weight = matches.reduce((sum, item) => {
-                    const num = parseFloat(item.replace('g', ''));
-                    return sum + (isNaN(num) ? 0 : num);
-                }, 0);
-            }
+    updateRowData(currentRow.value);
+  }
+};
+
+// 处理食谱取消
+const handleRecipeCancel = () => {};
+
+// 移除食谱
+const removeRecipe = (row: TableRow, index: number) => {
+  row.recipes?.splice(index, 1);
+  updateRowData(row);
+};
+
+// 处理食谱模板确认选择
+const handleRecipeTemplateConfirm = (selectedRecipes: RecipeTemplateItem[]) => {
+  // 遍历选中的食谱
+  selectedRecipes.forEach((recipe) => {
+    // 遍历食谱中的每一餐
+    recipe.meals.forEach((mealData) => {
+      // 找到对应的表格行
+      const targetRow = tableData.value.find((row) => row.meal === mealData.meal);
+      if (targetRow) {
+        // 如果没有recipes数组,创建一个
+        if (!targetRow.recipes) {
+          targetRow.recipes = [];
         }
-        return weight;
-    }
 
-    const handleSubmit = () => {
-        // 合并所有食谱tab下的明细
-        let mealRecipeList: MealRecipeForm[] = [];
-        allTableData.value.forEach((table, tabIdx) => {
-            mealRecipeList = mealRecipeList.concat(convertTableDataToMealRecipeList(table, tabIdx + 1));
+        // 添加新的食谱项
+        targetRow.recipes.push({
+          id: Date.now(), // 临时ID
+          name: mealData.dish,
+          categoryId: mealData.categoryId,
+          categoryName: mealData.categoryName,
+          ingredients: `${mealData.weight}; ${mealData.kcal}`,
+          weight: mealData.weight,
+          calorie: mealData.kcal
         });
-        const mealPlanForm = {
-            // ...其它表单字段
-            mealTimeRange: mealTimeRange.value,
-            mealRecipeList
-        };
-
-        emit('submitHospital', mealPlanForm);
-        emit('goBack'); // 让父组件切换回 hospitalIndex
-        localStorage.removeItem(DRAFT_KEY.value); // 提交成功后清除缓存
-
-    };
-
-    function saveDraft() {
-        const draft = {
-            mealTimeRange: mealTimeRange.value,
-            allTableData: allTableData.value,
-            currentRecipe: currentRecipe.value,
-            // 你还可以加其它需要缓存的字段
-        };
-        localStorage.setItem(DRAFT_KEY.value, JSON.stringify(draft));
-        ElMessage.success('操作成功');
-    }
 
-    function loadDraft() {
-        const draftStr = localStorage.getItem(DRAFT_KEY.value);
-        if (draftStr) {
-            try {
-                const draft = JSON.parse(draftStr);
-                if (draft.mealTimeRange) mealTimeRange.value = draft.mealTimeRange;
-                if (draft.allTableData) allTableData.value = draft.allTableData;
-                if (draft.currentRecipe !== undefined) currentRecipe.value = draft.currentRecipe;
-            } catch (e) {
-                // 解析失败可忽略
-            }
+        // 更新行数据
+        updateRowData(targetRow);
+      }
+    });
+  });
+};
+
+function sumIngredientsWeight(ingredients) {
+  if (!ingredients) return 0;
+  // 匹配所有形如 50.0000g 的数字
+  const matches = ingredients.match(/([\d.]+)g/g);
+  if (!matches) return 0;
+  return matches.reduce((sum, item) => {
+    const num = parseFloat(item.replace('g', ''));
+    return sum + (isNaN(num) ? 0 : num);
+  }, 0);
+}
+
+// 更新行数据的逻辑优化
+const updateRowData = (row: TableRow) => {
+  if (row.recipes?.length) {
+    // 更新菜品名称
+    row.menuName = row.recipes.map((recipe) => recipe.name).join('、');
+    // row.foodId = row.recipes.map((recipe) => recipe.id).join('、');
+
+    // 计算总重量和热量
+    let totalCalorie = 0;
+    let totalWeight = 0;
+    let totalAmount = 0;
+    row.recipes.forEach((recipe) => {
+      // 如果有 recipe.weight 字段优先用,否则解析 ingredients
+      const weight = parseFloat(recipe.weight?.replace(/[^\d.]/g, '') || '0');
+      totalWeight += weight;
+
+      const calorie = parseFloat(recipe.calorie || '0');
+      totalCalorie += calorie;
+
+      const amount = parseFloat(recipe.amount || '0');
+      totalAmount += amount;
+    });
+    totalWeight = totalWeight * row.count;
+    row.weight = totalWeight.toFixed(4);
+
+    totalCalorie = totalCalorie * row.count;
+    row.calorie = totalCalorie.toFixed(4);
+
+    totalAmount = totalAmount * row.count;
+    row.amount = totalAmount.toFixed(2);
+
+    // 金额也乘以份数
+    row.amount = (0.01 * row.recipes.length * row.count).toFixed(2);
+  } else {
+    // 清空数据
+    row.foodId = '';
+    row.menuName = '';
+    row.categoryId = '';
+    row.weight = '';
+    row.calorie = '';
+    row.amount = '0.00';
+    row.recipes = [];
+  }
+
+  // 更新总价格
+  calculateTotalPrice();
+};
+
+// 监听患者切换自动加载草稿
+watch(
+  () => props.patientInfo.id,
+  () => {
+    loadDraft();
+  },
+  {immediate: true}
+);
+
+// 监听食谱数据变化,重新计算总价格
+watch(
+  allTableData,
+  () => {
+    calculateTotalPrice();
+  },
+  {deep: true}
+);
+
+// 监听当前食谱切换,重新计算总价格
+watch(currentRecipe, () => {
+  calculateTotalPrice();
+});
+
+// 分页相关
+const handleSizeChange = (val: number) => {
+  pageSize.value = val;
+  // TODO: 重新加载数据
+};
+
+const handleCurrentChange = (val: number) => {
+  currentPage.value = val;
+  // TODO: 重新加载数据
+};
+
+// 处理 select 显示状态变化
+const handleSelectVisibleChange = (visible: boolean, row: any) => {
+  if (visible) {
+  }
+};
+
+// 打开食谱选择弹窗
+const openRecipeDialog = (row: TableRow, index?: number) => {
+  currentRow.value = row;
+  currentIndex.value = index ?? -1;
+
+  // 传递当前行的所有食谱给弹窗
+  if (row.recipes?.length) {
+    dialogRef.value?.openDialog('recipe', row.recipes);
+  } else {
+    dialogRef.value?.openDialog('recipe');
+  }
+};
+const recipeTemplateRef = ref<InstanceType<typeof RecipeTemplate> | null>(null);
+// 打开食谱模板弹窗
+const openRecipeTemplate = () => {
+  recipeTemplateRef.value?.openDialog();
+};
+
+watch(
+  () => props.rowData,
+  (newVal) => {
+    if (newVal?.mealRecipeList) {
+      // 1. 清空现有数据
+      allTableData.value = [];
+
+      // 2. 按 recipeNo 分组
+      const recipesByNo: Record<number, MealRecipeForm[]> = {};
+      newVal.mealRecipeList.forEach((recipe) => {
+        if (!recipesByNo[recipe.recipeNo]) {
+          recipesByNo[recipe.recipeNo] = [];
         }
-    }
-
+        recipesByNo[recipe.recipeNo].push(recipe);
+      });
+
+      // 3. 为每个 recipeNo 创建对应的食谱 tab
+      Object.keys(recipesByNo).forEach((no) => {
+        const recipeNo = parseInt(no, 10);
+        const recipes = recipesByNo[recipeNo];
+
+        // 初始化一个新的食谱 tab
+        const newTableData = JSON.parse(JSON.stringify(initialTableData));
+
+        // 填充数据
+        recipes.forEach((recipe) => {
+          const targetRow = newTableData.find((row) => row.meal === recipe.mealTime);
+          if (targetRow) {
+            if (!targetRow.recipes) {
+              targetRow.recipes = [];
+            }
 
+            targetRow.recipes.push({
+              id: recipe.foodId,
+              name: recipe.foodName,
+              categoryId: recipe.foodCategoryId,
+              categoryName: recipe.foodCategoryName,
+              weight: `${recipe.foodWeight}g`,
+              calorie: recipe.calorie?.toString(),
+              amount: recipe.price?.toString()
+            });
 
-    // 切换食谱
-    const switchRecipe = (index: number) => {
-        currentRecipe.value = index;
-    };
+            // 更新用餐时间
+            if (recipe.eatTime) {
+              const time = new Date(recipe.eatTime);
+              const hours = time.getHours().toString().padStart(2, '0');
+              const minutes = time.getMinutes().toString().padStart(2, '0');
+              targetRow.time = `${hours}:${minutes}`;
+            }
 
-    // 删除食谱
-    const deleteRecipe = (index: number) => {
-        if (allTableData.value.length === 1) return;
-        allTableData.value.splice(index, 1);
-        if (currentRecipe.value >= allTableData.value.length) {
-            currentRecipe.value = allTableData.value.length - 1;
-        }
-    };
+            // 更新份数
+            targetRow.count = recipe.amount || 1;
+          }
+        });
 
-    // 删除所有食谱
-    const deleteAllRecipes = () => {
+        // 添加到 allTableData
+        allTableData.value.push(newTableData);
+      });
 
+      // 4. 如果没有数据,至少保留一个空 tab
+      if (allTableData.value.length === 0) {
         allTableData.value = [JSON.parse(JSON.stringify(initialTableData))];
-        currentRecipe.value = 0;
-    };
-
-    // 初始化图表
-    const initChart = () => {
-        const chartDom = document.getElementById('nutritionChart');
-        if (!chartDom) return;
-
-        const myChart = echarts.init(chartDom);
-        const option = {
-            tooltip: {
-                trigger: 'item'
-            },
-            legend: {
-                show: false
-            },
-            color: ['#00D1D1', '#FFC53D', '#2F54EB'],
-            series: [{
-                name: '营养元素',
-                type: 'pie',
-                radius: ['60%', '80%'],
-                avoidLabelOverlap: false,
-                itemStyle: {
-                    borderRadius: 0,
-                    borderColor: '#fff',
-                    borderWidth: 2
-                },
-                label: {
-                    show: false
-                },
-                emphasis: {
-                    disabled: true
-                },
-                labelLine: {
-                    show: false
-                },
-                data: [
-                    { value: proteinRatio.value || 1, name: '蛋白质' },
-                    { value: fatRatio.value || 1, name: '脂肪' },
-                    { value: carbsRatio.value || 1, name: '碳水化合物' }
-                ]
-            }]
-        };
-
-        option && myChart.setOption(option);
-    };
-
-    // 返回上一页按钮
-    const goBack = () => {
-        emit('goBack');
-    };
-
-    // 食谱选择对话框
-
-    const searchKeyword = ref('');
-    const currentCategory = ref('');
-    const currentPage = ref(1);
-    const pageSize = ref(10);
-    const total = ref(1869);
-    const selectedRecipes = ref < Recipe[] > ([]);
-
-    const currentRow = ref < TableRow | null > (null);
-    const currentIndex = ref < number > (-1);
-    const dialogRef = ref < InstanceType < typeof CommonDialog > | null > (null);
-
-    // 处理食谱确认
-    const handleRecipeConfirm = (selectedRecipes: Recipe[]) => {
-        if (currentRow.value && selectedRecipes.length > 0) {
-            if (!currentRow.value.recipes) {
-                currentRow.value.recipes = [];
-            }
+      }
 
-            if (currentIndex.value >= 0) {
-                // 更新已有食谱
-                currentRow.value.recipes[currentIndex.value] = selectedRecipes[0];
-            } else {
-                // 添加新食谱
-                currentRow.value.recipes.push(...selectedRecipes);
-            }
-
-            updateRowData(currentRow.value);
-        }
-    };
-
-    // 处理食谱取消
-    const handleRecipeCancel = () => {
-    };
-
-    // 移除食谱
-    const removeRecipe = (row: TableRow, index: number) => {
-        row.recipes ?.splice(index, 1);
-        updateRowData(row);
-    };
-
-    // 处理食谱模板确认选择
-    const handleRecipeTemplateConfirm = (selectedRecipes: RecipeTemplateItem[]) => {
-        // 遍历选中的食谱
-        selectedRecipes.forEach((recipe) => {
-            // 遍历食谱中的每一餐
-            recipe.meals.forEach((mealData) => {
-                // 找到对应的表格行
-                const targetRow = tableData.value.find((row) => row.meal === mealData.meal);
-                if (targetRow) {
-                    // 如果没有recipes数组,创建一个
-                    if (!targetRow.recipes) {
-                        targetRow.recipes = [];
-                    }
-
-                    // 添加新的食谱项
-                    targetRow.recipes.push({
-                        id: Date.now(), // 临时ID
-                        name: mealData.dish,
-                        categoryId: mealData.categoryId,
-                        categoryName: mealData.categoryName,
-                        ingredients: `${mealData.weight}; ${mealData.kcal}`,
-                        weight: mealData.weight,
-                        calorie: mealData.kcal
-                    });
-
-                    // 更新行数据
-                    updateRowData(targetRow);
-                }
-            });
-        });
-    };
-
-    function sumIngredientsWeight(ingredients) {
-        if (!ingredients) return 0;
-        // 匹配所有形如 50.0000g 的数字
-        const matches = ingredients.match(/([\d.]+)g/g);
-        if (!matches) return 0;
-        return matches.reduce((sum, item) => {
-            const num = parseFloat(item.replace('g', ''));
-            return sum + (isNaN(num) ? 0 : num);
-        }, 0);
+      // 5. 数据填充完成后,设置总价格(使用 nextTick 确保在 DOM 更新后执行)
+      nextTick(() => {
+        totalPrice.value = Number(newVal.totalPrice) || 0;
+      });
     }
-
-    // 更新行数据的逻辑优化
-    const updateRowData = (row: TableRow) => {
-
-        if (row.recipes ?.length) {
-            // 更新菜品名称
-            row.menuName = row.recipes.map((recipe) => recipe.name).join('、');
-            // row.foodId = row.recipes.map((recipe) => recipe.id).join('、');
-
-            // 计算总重量和热量
-            let totalCalorie = 0;
-
-            let totalWeight = 0;
-            row.recipes.forEach((recipe) => {
-                // 如果有 recipe.weight 字段优先用,否则解析 ingredients
-                let weight = 0;
-                if (recipe.weight) {
-                    weight = parseFloat(recipe.weight.replace(/[^\d.]/g, '') || '0');
-                } else if (recipe.ingredients) {
-                    weight = sumIngredientsWeight(recipe.ingredients);
-                }
-                totalWeight += weight;
-            });
-            totalWeight = totalWeight * row.count;
-            row.weight = totalWeight.toFixed(4) + 'g';
-
-            row.calorie = totalCalorie.toFixed(4) ;
-            // 金额也乘以份数
-            row.amount = (0.01 * row.recipes.length * row.count).toFixed(2);
-        } else {
-            // 清空数据
-            row.foodId = '';
-            row.menuName = '';
-            row.categoryId = '';
-            row.weight = '';
-            row.calorie = '';
-            row.amount = '0.00';
-            row.recipes = [];
-        }
-    };
-
-    // 监听患者切换自动加载草稿
-    watch(() => props.patientInfo.id, () => {
-        loadDraft();
-    }, { immediate: true });
-
-    // 分页相关
-    const handleSizeChange = (val: number) => {
-        pageSize.value = val;
-        // TODO: 重新加载数据
-    };
-
-    const handleCurrentChange = (val: number) => {
-        currentPage.value = val;
-        // TODO: 重新加载数据
-    };
-
-    // 处理 select 显示状态变化
-    const handleSelectVisibleChange = (visible: boolean, row: any) => {
-        if (visible) {}
-    };
-
-    // 打开食谱选择弹窗
-    const openRecipeDialog = (row: TableRow, index ? : number) => {
-        currentRow.value = row;
-        currentIndex.value = index ?? -1;
-
-        // 传递当前行的所有食谱给弹窗
-        if (row.recipes ?.length) {
-            dialogRef.value ?.openDialog('recipe', row.recipes);
-        } else {
-            dialogRef.value ?.openDialog('recipe');
-        }
-    };
-    const recipeTemplateRef = ref < InstanceType < typeof RecipeTemplate > | null > (null);
-    // 打开食谱模板弹窗
-    const openRecipeTemplate = () => {
-        recipeTemplateRef.value ?.openDialog();
-    };
-
-    onMounted(() => {
-        initChart();
-        loadDraft();
-    });
+  },
+  {immediate: true}
+);
+
+onMounted(() => {
+  loadDraft();
+  calculateTotalPrice();
+});
 </script>
 <style lang="scss" scoped>
-    .container {
-        position: relative;
-
-        min-height: 90vh;
-        padding-bottom: 76px; // 底部按钮的高度 + padding
-
-        .el-card {
-            margin-top: 16px;
-            height: 500px;
-            width: 100vw;
-        }
-    }
-
-    .add-hospital-wrapper {
-        width: 89vw;
-        background: #fff;
-        border-radius: 12px;
-        padding: 20px 24px 12px 24px;
-        box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
-    }
-
-    .header-bar {
-        display: flex;
-        align-items: center;
-        margin-bottom: 16px;
-
-        .back-btn {
-            margin-right: 16px;
-        }
-
-        .title {
-            font-size: 20px;
-            font-weight: 600;
-        }
-    }
-
-    .form-bar {
-        width: 100vm;
-        display: flex;
-        align-items: center;
-        margin-bottom: 12px;
-
-        .ml-2 {
-            margin-left: 12px;
-        }
+.container {
+  position: relative;
+
+  min-height: 90vh;
+  padding-bottom: 76px; // 底部按钮的高度 + padding
+
+  .el-card {
+    margin-top: 16px;
+    height: 500px;
+    width: 100vw;
+  }
+}
+
+.add-hospital-wrapper {
+  width: 89vw;
+  background: #fff;
+  border-radius: 12px;
+  padding: 20px 24px 12px 24px;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
+}
+
+.header-bar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+
+  .back-btn {
+    margin-right: 16px;
+  }
+
+  .title {
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+
+.form-bar {
+  width: 100vm;
+  display: flex;
+  align-items: center;
+  margin-bottom: 12px;
+
+  .ml-2 {
+    margin-left: 12px;
+  }
+}
+
+.tab-bar {
+  margin-bottom: 8px;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+
+  .tab-btn {
+    position: relative;
+    padding-right: 32px;
+
+    &.active {
+      background: #4cd964;
+      color: #fff;
+      border: none;
     }
 
-    .tab-bar {
-        margin-bottom: 8px;
-        display: flex;
-        flex-wrap: wrap;
-        gap: 8px;
-
-        .tab-btn {
-            position: relative;
-            padding-right: 32px;
+    &:not(.active) {
+      background: #f5f7fa;
+      color: #909399;
+      border-color: #dcdfe6;
 
-            &.active {
-                background: #4cd964;
-                color: #fff;
-                border: none;
-            }
-
-            &:not(.active) {
-                background: #f5f7fa;
-                color: #909399;
-                border-color: #dcdfe6;
-
-                .close-icon {
-                    color: #909399;
-                }
-            }
-
-            .close-icon {
-                position: absolute;
-                right: 8px;
-                top: 50%;
-                transform: translateY(-50%);
-                cursor: pointer;
-                font-size: 14px;
-                border-radius: 50%;
-                padding: 2px;
-
-                &:hover {
-                    background-color: rgba(0, 0, 0, 0.1);
-                }
-            }
-        }
+      .close-icon {
+        color: #909399;
+      }
     }
 
-    .info-alert {
-        margin-bottom: 8px;
-        font-size: 14px;
+    .close-icon {
+      position: absolute;
+      right: 8px;
+      top: 50%;
+      transform: translateY(-50%);
+      cursor: pointer;
+      font-size: 14px;
+      border-radius: 50%;
+      padding: 2px;
+
+      &:hover {
+        background-color: rgba(0, 0, 0, 0.1);
+      }
     }
-
-    .diet-table {
-        margin-bottom: 12px;
-    }
-
-    .footer-bar {
-        display: flex;
-        justify-content: flex-end;
-        align-items: center;
-        font-size: 16px;
+  }
+}
+
+.info-alert {
+  margin-bottom: 8px;
+  font-size: 14px;
+}
+
+.diet-table {
+  margin-bottom: 12px;
+}
+
+.footer-bar {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  font-size: 16px;
+  font-weight: 600;
+  margin: 8px 0;
+
+  .amount {
+    color: #ff3a00;
+    margin-left: 8px;
+  }
+}
+
+.nutrition-analysis {
+  padding: 12px;
+
+  .nutrition-header {
+    display: flex;
+    gap: 24px;
+    margin-bottom: 12px;
+    font-size: 14px;
+
+    .nutrition-target,
+    .nutrition-actual {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .value {
+        color: #409eff;
         font-weight: 600;
-        margin: 8px 0;
-
-        .amount {
-            color: #ff3a00;
-            margin-left: 8px;
-        }
-    }
-
-    .nutrition-analysis {
-        padding: 12px;
-
-        .nutrition-header {
-            display: flex;
-            gap: 24px;
-            margin-bottom: 12px;
-            font-size: 14px;
-
-            .nutrition-target,
-            .nutrition-actual {
-                display: flex;
-                align-items: center;
-                gap: 8px;
-
-                .value {
-                    color: #409eff;
-                    font-weight: 600;
-                }
-            }
-        }
+      }
     }
-
-    .chart-container {
-        margin-top: 16px;
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        text-align: center;
-
-        .chart-title {
-            font-size: 16px;
-            font-weight: 600;
-            margin-bottom: 16px;
-            color: #333;
+  }
+}
+
+.chart-container {
+  margin-top: 16px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  text-align: center;
+
+  .chart-title {
+    font-size: 16px;
+    font-weight: 600;
+    margin-bottom: 16px;
+    color: #333;
+  }
+
+  .chart-content {
+    height: 200px;
+    width: 200px;
+  }
+
+  .chart-legend {
+    display: flex;
+    justify-content: center;
+    gap: 24px;
+    margin-top: 16px;
+
+    .legend-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #666;
+      font-size: 14px;
+
+      .color-block {
+        width: 12px;
+        height: 12px;
+        border-radius: 2px;
+
+        &.protein {
+          background-color: #00d1d1;
         }
 
-        .chart-content {
-            height: 200px;
-            width: 200px;
+        &.fat {
+          background-color: #ffc53d;
         }
 
-        .chart-legend {
-            display: flex;
-            justify-content: center;
-            gap: 24px;
-            margin-top: 16px;
-
-            .legend-item {
-                display: flex;
-                align-items: center;
-                gap: 8px;
-                color: #666;
-                font-size: 14px;
-
-                .color-block {
-                    width: 12px;
-                    height: 12px;
-                    border-radius: 2px;
-
-                    &.protein {
-                        background-color: #00d1d1;
-                    }
-
-                    &.fat {
-                        background-color: #ffc53d;
-                    }
-
-                    &.carbs {
-                        background-color: #2f54eb;
-                    }
-                }
-            }
+        &.carbs {
+          background-color: #2f54eb;
         }
+      }
     }
-
-    .mt-4 {
-        margin-top: 12px;
+  }
+}
+
+.mt-4 {
+  margin-top: 12px;
+}
+
+.bottom-btn-card {
+  position: fixed;
+  left: 228px; // 左侧菜单的宽度
+  right: 0;
+  bottom: 50px;
+  padding: 8px 16px;
+  background: #fff;
+  box-shadow: 0 -2px 8px rgba(64, 158, 255, 0.08);
+  z-index: 2000;
+
+  .btn-wrapper {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .el-button {
+      margin-top: 30px;
+      min-width: 120px;
+      height: 44px;
+      padding: 0 24px;
     }
-
-    .bottom-btn-card {
-        position: fixed;
-        left: 228px; // 左侧菜单的宽度
-        right: 0;
-        bottom: 50px;
-        padding: 8px 16px;
-        background: #fff;
-        box-shadow: 0 -2px 8px rgba(64, 158, 255, 0.08);
-        z-index: 2000;
-
-        .btn-wrapper {
-            display: flex;
-            justify-content: center;
-            align-items: center;
-
-            .el-button {
-                margin-top: 30px;
-                min-width: 120px;
-                height: 44px;
-                padding: 0 24px;
-            }
-        }
+  }
+}
+
+:deep(.el-main) {
+  overflow-x: hidden;
+}
+
+:deep(.hidden-popper) {
+  display: none !important;
+}
+
+.recipe-input {
+  width: 100%;
+  height: 32px;
+  line-height: 32px;
+  padding: 0 12px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  cursor: pointer;
+  color: #606266;
+  background-color: #fff;
+  position: relative;
+  user-select: none; // 防止文本被选中
+
+  &:hover {
+    border-color: #409eff;
+  }
+
+  &::after {
+    content: '';
+    position: absolute;
+    right: 8px;
+    top: 14px;
+    width: 0;
+    height: 0;
+    border: 6px solid transparent;
+    border-top-color: #c0c4cc;
+    pointer-events: none; // 防止箭头影响点击
+  }
+
+  &.add-more {
+    margin-top: 8px;
+    color: #909399;
+    border-style: dashed;
+  }
+}
+
+.recipe-list {
+  .recipe-input {
+    width: 100%;
+    height: 32px;
+    line-height: 32px;
+    padding: 0 12px;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    cursor: pointer;
+    color: #606266;
+    background-color: #fff;
+    position: relative;
+    user-select: none;
+
+    &:hover {
+      border-color: #409eff;
     }
 
-    :deep(.el-main) {
-        overflow-x: hidden;
+    &::after {
+      content: '';
+      position: absolute;
+      right: 8px;
+      top: 14px;
+      width: 0;
+      height: 0;
+      border: 6px solid transparent;
+      border-top-color: #c0c4cc;
+      pointer-events: none;
     }
+  }
 
-    :deep(.hidden-popper) {
-        display: none !important;
-    }
+  .recipe-item {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    margin-bottom: 8px;
 
     .recipe-input {
-        width: 100%;
+      flex: 1;
+      height: 32px;
+      line-height: 32px;
+      padding: 0 12px;
+      border: 1px solid #dcdfe6;
+      border-radius: 4px;
+      background: #fff;
+      color: #606266;
+      cursor: pointer;
+
+      &:hover {
+        border-color: #409eff;
+      }
+
+      .recipe-input-one {
+        flex: 1;
         height: 32px;
         line-height: 32px;
-        padding: 0 12px;
+        padding: 0 1px;
         border: 1px solid #dcdfe6;
-        border-radius: 4px;
-        cursor: pointer;
-        color: #606266;
-        background-color: #fff;
-        position: relative;
-        user-select: none; // 防止文本被选中
-
-        &:hover {
-            border-color: #409eff;
-        }
-
-        &::after {
-            content: '';
-            position: absolute;
-            right: 8px;
-            top: 14px;
-            width: 0;
-            height: 0;
-            border: 6px solid transparent;
-            border-top-color: #c0c4cc;
-            pointer-events: none; // 防止箭头影响点击
-        }
-
-        &.add-more {
-            margin-top: 8px;
-            color: #909399;
-            border-style: dashed;
-        }
+      }
     }
 
-    .recipe-list {
-        .recipe-input {
-            width: 100%;
-            height: 32px;
-            line-height: 32px;
-            padding: 0 12px;
-            border: 1px solid #dcdfe6;
-            border-radius: 4px;
-            cursor: pointer;
-            color: #606266;
-            background-color: #fff;
-            position: relative;
-            user-select: none;
-
-            &:hover {
-                border-color: #409eff;
-            }
-
-            &::after {
-                content: '';
-                position: absolute;
-                right: 8px;
-                top: 14px;
-                width: 0;
-                height: 0;
-                border: 6px solid transparent;
-                border-top-color: #c0c4cc;
-                pointer-events: none;
-            }
-        }
-
-        .recipe-item {
-            display: flex;
-            align-items: center;
-            gap: 8px;
-            margin-bottom: 8px;
-
-            .recipe-input {
-                flex: 1;
-                height: 32px;
-                line-height: 32px;
-                padding: 0 12px;
-                border: 1px solid #dcdfe6;
-                border-radius: 4px;
-                background: #fff;
-                color: #606266;
-                cursor: pointer;
-
-                &:hover {
-                    border-color: #409eff;
-                }
-
-                .recipe-input-one {
-                    flex: 1;
-                    height: 32px;
-                    line-height: 32px;
-                    padding: 0 1px;
-                    border: 1px solid #dcdfe6;
-
-                }
-            }
-
-            .delete-btn {
-                flex: none;
-                padding: 8px;
-                color: #f56c6c;
+    .delete-btn {
+      flex: none;
+      padding: 8px;
+      color: #f56c6c;
 
-                &:hover {
-                    color: #ff4d4f;
-                }
-            }
-        }
+      &:hover {
+        color: #ff4d4f;
+      }
+    }
+  }
 
-        .add-more {
-            margin-top: 8px;
-            border-style: dashed;
-            color: #909399;
+  .add-more {
+    margin-top: 8px;
+    border-style: dashed;
+    color: #909399;
 
-            &:hover {
-                border-color: #409eff;
-                color: #409eff;
-            }
-        }
+    &:hover {
+      border-color: #409eff;
+      color: #409eff;
     }
-</style>
+  }
+}
+</style>

+ 1366 - 0
src/views/patients/dietTherapy/dailyDetail.vue

@@ -0,0 +1,1366 @@
+<template>
+  <div class="container">
+    <!-- 食谱卡片 -->
+    <el-card class="recipe-card">
+      <img src="../../../assets/images/no_pay.png" alt="待支付" class="pay-status-icon" />
+      <!-- 返回按钮和标题 -->
+      <div class="card-header">
+        <el-button plain @click="goBack" class="back">返回</el-button>
+        <span class="title">日常膳食</span>
+      </div>
+
+      <!-- 日期和操作栏 -->
+      <div class="date-operation-bar">
+        <div class="date-picker">
+          <span>配餐日期:</span>
+          <el-date-picker
+            v-model="dateRange"
+            type="daterange"
+            disabled
+            range-separator="-"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            size="default"
+            class="date-input"
+          />
+        </div>
+        <div class="operation-btns">
+          <el-button type="primary" plain size="default">打印</el-button>
+          <el-button type="success" plain size="default" @click="quoteMealPlan">引用处方</el-button>
+          <el-button type="danger" plain size="default" @click="deleteMealPlan">作废</el-button>
+        </div>
+      </div>
+
+      <!-- 食谱标题区域 -->
+      <div class="recipe-header">
+        <div class="recipe-title-wrapper">
+          <div class="recipe-buttons">
+            <el-button
+              v-for="(recipe, index) in allRecipesData"
+              :key="index"
+              :type="currentRecipeIndex === index ? 'success' : 'default'"
+              plain
+              class="recipe-btn"
+              @click="switchToRecipe(index)"
+            >
+              食谱{{ index + 1 }}
+            </el-button>
+          </div>
+          <span class="recipe-tip">周食谱模板的食谱数量小于7时,食谱可循环使用</span>
+        </div>
+      </div>
+
+      <!-- 营养警告 -->
+      <div class="nutrition-warning">
+        <el-alert
+          :title="'当前处方中的热量、蛋白质、脂肪、碳水化合物、钙、铁、维生素A、维生素B2、维生素C、维生素E元素可能过量'"
+          type="warning"
+          show-icon
+          :closable="false"
+        />
+      </div>
+
+      <!-- 食谱表格 -->
+      <div class="table-wrapper">
+        <table style="text-align: center" class="recipe-table">
+          <thead>
+            <tr>
+              <th>餐次</th>
+              <th>用餐时间</th>
+              <th>食谱名称</th>
+              <th>食谱分类</th>
+              <th>份数</th>
+              <th>食材重量</th>
+              <th>热量</th>
+            </tr>
+          </thead>
+          <tbody>
+            <template v-for="(meal, mealIndex) in tableData" :key="mealIndex">
+              <tr v-for="(recipe, recipeIndex) in meal.recipes" :key="recipeIndex" :class="{'row-even': recipeIndex % 2 === 1}">
+                <td v-if="recipeIndex === 0" :rowspan="meal.recipes.length" class="text-center">{{ meal.meal }}</td>
+                <td v-if="recipeIndex === 0" :rowspan="meal.recipes.length" class="text-center">{{ meal.time }}</td>
+                <td>{{ recipe.name }}</td>
+                <td>{{ recipe.category }}</td>
+                <td class="text-center">{{ recipe.count }}</td>
+                <td class="text-center">{{ recipe.weight }}</td>
+                <td class="text-center">{{ recipe.calorie }}</td>
+              </tr>
+            </template>
+          </tbody>
+        </table>
+      </div>
+    </el-card>
+
+    <!-- 营养分析卡片 -->
+    <el-card v-if="false" class="analysis-card">
+      <el-tabs v-model="activeTab">
+        <el-tab-pane label="三大营养分析" name="nutrition">
+          <div class="nutrition-header">
+            <div class="nutrition-target">
+              营养设定:<span>{{ nutritionTarget }}kcal/d</span>
+            </div>
+            <div class="nutrition-actual">
+              实际热量:<span>{{ actualCalories }}kcal/d</span>
+            </div>
+          </div>
+          <div class="nutrition-content">
+            <!-- 左侧表格 -->
+            <div class="table-section">
+              <table class="nutrition-table">
+                <thead>
+                  <tr>
+                    <th>三大营养素</th>
+                    <th>质量(g)</th>
+                    <th>热量占比</th>
+                    <th>参考值</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr v-for="item in nutritionData" :key="item.name">
+                    <td>{{ item.name }}</td>
+                    <td>{{ item.weight }}</td>
+                    <td>{{ item.ratio }}%</td>
+                    <td>{{ item.reference }}</td>
+                  </tr>
+                </tbody>
+              </table>
+            </div>
+            <!-- 右侧图表 -->
+            <div class="chart-section">
+              <div class="chart-title">三大营养素元素质量占比</div>
+              <div ref="chartRef" class="chart-container"></div>
+              <div class="chart-legend">
+                <div class="legend-item">
+                  <span class="color-dot protein"></span>
+                  <span>蛋白质 26.14%</span>
+                </div>
+                <div class="legend-item">
+                  <span class="color-dot fat"></span>
+                  <span>脂肪 11.64%</span>
+                </div>
+                <div class="legend-item">
+                  <span class="color-dot carbs"></span>
+                  <span>碳水化合物 62.02%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="营养数据分析" name="data">
+          <div style="text-align: center" class="table-wrapper">
+            <table class="nutrition-analysis-table">
+              <thead>
+                <tr>
+                  <th rowspan="2">元素类型</th>
+                  <th rowspan="2">元素名称</th>
+                  <th rowspan="2">单位</th>
+                  <th colspan="2">膳食营养含量/天</th>
+                  <th rowspan="2">肠外营养含量/天</th>
+                  <th rowspan="2">肠内营养含量/天</th>
+                  <th rowspan="2">营养设定</th>
+                </tr>
+                <tr>
+                  <th>当前处方</th>
+                  <th>历史处方</th>
+                </tr>
+              </thead>
+              <tbody>
+                <template v-for="group in groupedNutritionData" :key="group.type">
+                  <template v-for="(item, itemIndex) in group.items" :key="item.name">
+                    <tr>
+                      <td v-if="itemIndex === 0" :rowspan="group.items.length" class="type-cell">{{ group.type }}</td>
+                      <td class="name-cell">{{ item.name }}</td>
+                      <td class="unit-cell">{{ item.unit }}</td>
+                      <td :class="{highlight: item.current > item.target}">{{ item.current }}</td>
+                      <td>{{ item.history || '--' }}</td>
+                      <td>{{ item.external || '--' }}</td>
+                      <td>{{ item.internal || '--' }}</td>
+                      <td>{{ item.target }}</td>
+                    </tr>
+                  </template>
+                </template>
+              </tbody>
+            </table>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref, onMounted, computed, watch} from 'vue';
+import * as echarts from 'echarts';
+import {ArrowLeft} from '@element-plus/icons-vue';
+const emit = defineEmits(['change', 'del', 'add']);
+
+import {getMealPlan} from '@/api/patients/dailyMealPlan';
+import {MealPlanVO, MealPlanQuery, MealPlanForm} from '@/api/patients/dailyMealPlan/types';
+
+interface NutritionItem {
+  type: string;
+  name: string;
+  unit: string;
+  current: string;
+  history: string;
+  external: string; // 肠外营养含量
+  internal: string; // 肠内营养含量
+  target: string;
+}
+// 表格数据
+const tableData = ref([]);
+const activeTab = ref('nutrition');
+const mealPlanVo = ref();
+const dateRange = ref(['2025-07-16', '2025-07-16']);
+const currentRecipeIndex = ref(0); // 当前显示的食谱索引
+const allRecipesData = ref([]); // 存储所有食谱数据
+
+// 切换食谱
+const switchRecipe = (direction: number) => {
+  const newIndex = currentRecipeIndex.value + direction;
+  if (newIndex >= 0 && newIndex < allRecipesData.value.length) {
+    currentRecipeIndex.value = newIndex;
+    tableData.value = allRecipesData.value[currentRecipeIndex.value] || [];
+  }
+};
+
+// 直接切换到指定食谱
+const switchToRecipe = (index: number) => {
+  if (index >= 0 && index < allRecipesData.value.length) {
+    currentRecipeIndex.value = index;
+    tableData.value = allRecipesData.value[currentRecipeIndex.value] || [];
+  }
+};
+
+// 营养数据
+const nutritionData = ref([
+  {name: '蛋白质', weight: '71.4860', ratio: '23.74', reference: '10% - 15%'},
+  {name: '脂肪', weight: '32.3765', ratio: '24.19', reference: '20% - 30%'},
+  {name: '碳水化合物', weight: '169.6211', ratio: '56.32', reference: '50% - 65%'}
+]);
+
+// 图表引用
+const chartRef = ref<HTMLElement | null>(null);
+// 声明接收的 props
+const props = defineProps({
+  infoId: {
+    type: [Number, String],
+    required: true
+  }
+});
+// 修改图表配置
+const initChart = () => {
+  if (!chartRef.value) return;
+
+  const chart = echarts.init(chartRef.value);
+  const option = {
+    tooltip: {
+      trigger: 'item',
+      formatter: '{b}: {c}%'
+    },
+    legend: {
+      show: false
+    },
+    series: [
+      {
+        type: 'pie',
+        radius: ['50%', '70%'],
+        center: ['50%', '50%'],
+        avoidLabelOverlap: false,
+        label: {
+          show: false
+        },
+        labelLine: {
+          show: false
+        },
+        emphasis: {
+          scale: false,
+          scaleSize: 0
+        },
+        data: [
+          {
+            value: 26.14,
+            name: '蛋白质',
+            itemStyle: {
+              color: '#36cfc9',
+              borderWidth: 0
+            }
+          },
+          {
+            value: 11.64,
+            name: '脂肪',
+            itemStyle: {
+              color: '#ffd666',
+              borderWidth: 0
+            }
+          },
+          {
+            value: 62.02,
+            name: '碳水化合物',
+            itemStyle: {
+              color: '#85a5ff',
+              borderWidth: 0
+            }
+          }
+        ]
+      }
+    ]
+  };
+
+  chart.setOption(option);
+
+  // 监听窗口大小变化
+  window.addEventListener('resize', () => {
+    chart.resize();
+  });
+};
+
+// 返回上一页
+const goBack = async () => {
+  emit('change', 'dailyIndex');
+};
+
+// 添加响应式数据
+const nutritionTarget = ref('1035.35');
+const actualCalories = ref('1204.60');
+
+// 按元素类型分组的数据
+const groupedNutritionData = computed(() => {
+  const groups: {
+    [key: string]: any[];
+  } = {};
+  nutritionAnalysisData.forEach((item) => {
+    if (!groups[item.type]) {
+      groups[item.type] = [];
+    }
+    groups[item.type].push(item);
+  });
+  return Object.entries(groups).map(([type, items]) => ({
+    type,
+    items
+  }));
+});
+
+// 营养数据分析数据
+const nutritionAnalysisData: NutritionItem[] = [
+  {
+    type: '热能及三大营养素',
+    name: '热量',
+    unit: 'kcal',
+    current: '1204.5965',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1035.35'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '蛋白质',
+    unit: 'g',
+    current: '71.486',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '50'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '脂肪',
+    unit: 'g',
+    current: '32.3765',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '23.01'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '碳水化合物',
+    unit: 'g',
+    current: '169.6211',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '129.42'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '热能-kilojoules',
+    unit: 'kj',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '4331.9'
+  },
+  {
+    type: '常量元素',
+    name: '钠',
+    unit: 'mg',
+    current: '1026.8556',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1500'
+  },
+  {
+    type: '常量元素',
+    name: '磷',
+    unit: 'mg',
+    current: '331.8685',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '720'
+  },
+  {
+    type: '常量元素',
+    name: '钙',
+    unit: 'mg',
+    current: '862.651',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '800'
+  },
+  {
+    type: '常量元素',
+    name: '钾',
+    unit: 'mg',
+    current: '439.089',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '2000'
+  },
+  {
+    type: '常量元素',
+    name: '镁',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '530'
+  },
+  {
+    type: '常量元素',
+    name: '氯',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '2300'
+  },
+  {
+    type: '微量元素',
+    name: '铁',
+    unit: 'mg',
+    current: '20.6671',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '20'
+  },
+  {
+    type: '微量元素',
+    name: '锌',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '7.5'
+  },
+  {
+    type: '微量元素',
+    name: '硒',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '60'
+  },
+  {
+    type: '微量元素',
+    name: '铜',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '0.8'
+  },
+  {
+    type: '微量元素',
+    name: '锰',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '4.5'
+  },
+  {
+    type: '微量元素',
+    name: '碘',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '120'
+  },
+  {
+    type: '微量元素',
+    name: '氟',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.5'
+  },
+  {
+    type: '微量元素',
+    name: '铬',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '30'
+  },
+  {
+    type: '维生素',
+    name: '维生素B2',
+    unit: 'mg',
+    current: '1.9407',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.2'
+  },
+  {
+    type: '维生素',
+    name: '维生素C',
+    unit: 'mg',
+    current: '166.742',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '100'
+  },
+  {
+    type: '维生素',
+    name: '维生素B1',
+    unit: 'mg',
+    current: '1.1105',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.2'
+  },
+  {
+    type: '维生素',
+    name: '烟酸',
+    unit: 'mg',
+    current: '10.396',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '12'
+  },
+  {
+    type: '维生素',
+    name: '维生素E',
+    unit: 'mg',
+    current: '20.4819',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '14'
+  },
+  {
+    type: '维生素',
+    name: '维生素D',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '10'
+  },
+  {
+    type: '维生素',
+    name: '维生素K',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '80'
+  },
+  {
+    type: '维生素',
+    name: '维生素B6',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.4'
+  },
+  {
+    type: '维生素',
+    name: '维生素B12',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '2.4'
+  },
+  {
+    type: '维生素',
+    name: '叶酸',
+    unit: 'μgDFE',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '400'
+  },
+  {
+    type: '维生素',
+    name: '胆碱',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '400'
+  },
+  {
+    type: '维生素',
+    name: '生物素',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '40'
+  },
+  {
+    type: '维生素',
+    name: '泛醇',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '5'
+  },
+  {
+    type: '脂类',
+    name: '胆固醇',
+    unit: 'g',
+    current: '0.6345',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '--'
+  },
+  {
+    type: '其他',
+    name: '水分',
+    unit: 'ml',
+    current: '1147.0572',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '--'
+  },
+  {
+    type: '其他',
+    name: '膳食纤维',
+    unit: 'g',
+    current: '10.7333',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '25'
+  }
+];
+
+/** 查询日常膳食主列表 */
+const getDetail = async () => {
+  if (props.infoId && (typeof props.infoId === 'number' || typeof props.infoId === 'string')) {
+    try {
+      const res = await getMealPlan(props.infoId);
+
+      if (res.code === 200 && res.data) {
+        const data = res.data as any;
+        mealPlanVo.value = res.data;
+        // 更新日期范围
+        if (data.recommendStartDate && data.recommendEndDate) {
+          dateRange.value = [data.recommendStartDate, data.recommendEndDate];
+        }
+
+        // 更新表格数据
+        if (data.mealRecipeList && data.mealRecipeList.length > 0) {
+          // 按食谱编号分组数据
+          const recipeGroups = {};
+
+          data.mealRecipeList.forEach((recipe) => {
+            const recipeNo = recipe.recipeNo;
+            if (!recipeGroups[recipeNo]) {
+              recipeGroups[recipeNo] = [];
+            }
+
+            // 按餐次分组
+            const mealTime = recipe.mealTime;
+            let mealGroup = recipeGroups[recipeNo].find((group) => group.meal === mealTime);
+
+            if (!mealGroup) {
+              mealGroup = {
+                meal: mealTime,
+                time: recipe.eatTime ? recipe.eatTime.split(' ')[1] : '08:00',
+                recipes: []
+              };
+              recipeGroups[recipeNo].push(mealGroup);
+            }
+
+            mealGroup.recipes.push({
+              name: recipe.foodName,
+              category: recipe.foodCategoryName,
+              count: recipe.amount,
+              weight: recipe.foodWeight ? recipe.foodWeight.toString() : '0',
+              calorie: recipe.calorie ? recipe.calorie.toString() : '0'
+            });
+          });
+
+          // 存储所有食谱数据
+          allRecipesData.value = Object.values(recipeGroups) as any[];
+          // 设置当前显示的食谱
+          tableData.value = allRecipesData.value[currentRecipeIndex.value] || [];
+
+          // 如果有多个食谱,可以在这里添加食谱切换功能
+        }
+      }
+    } catch (error) {
+      console.error('获取详情失败:', error);
+    }
+  }
+};
+
+const quoteMealPlan = async () => {
+  emit('add', 'dailyDetail', mealPlanVo.value);
+};
+
+const deleteMealPlan = async () => {
+  emit('del', 'dailyDetail', props.infoId);
+};
+
+// 监听 infoId 变化,当有值时执行 getDetail
+watch(
+  () => props.infoId,
+  (newVal) => {
+    if (newVal) {
+      getDetail();
+    }
+  }
+);
+
+onMounted(() => {
+  initChart();
+  // 如果 onMounted 时已经有 infoId,也执行一次
+  if (props.infoId) {
+    getDetail();
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+  background: #f5f7fa;
+  min-height: 100vh;
+}
+
+.recipe-card {
+  background: #fff;
+  border-radius: 4px;
+  padding: 20px;
+  margin-bottom: 16px;
+  position: relative;
+  width: 89vw;
+
+  .pay-status-icon {
+    position: absolute;
+    top: -2px;
+    right: -4px;
+    width: 100px;
+    /* 调整为更合适的大小 */
+    height: 100px;
+    transform: rotate(10deg);
+    /* 添加轻微旋转以匹配设计 */
+    z-index: 1;
+  }
+
+  .card-header {
+    margin-bottom: 20px;
+
+    .back {
+      margin-right: 20px;
+    }
+
+    .header-left {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+
+      .back-btn {
+        border-radius: 4px;
+        padding: 8px 16px;
+      }
+
+      .title {
+        font-size: 16px;
+        font-weight: 500;
+        color: #303133;
+      }
+    }
+  }
+
+  .date-operation-bar {
+    display: flex;
+    align-items: center;
+    margin-bottom: 16px;
+    border-bottom: 1px solid #ebeef5;
+    padding-bottom: 16px;
+
+    .date-picker {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #606266;
+      margin-right: 20px;
+
+      .date-input {
+        width: 240px;
+      }
+    }
+
+    .operation-btns {
+      display: flex;
+      gap: 12px;
+    }
+  }
+
+  .recipe-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .recipe-title-wrapper {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      width: 100%;
+      gap: 12px;
+
+      .recipe-buttons {
+        display: flex;
+        gap: 8px;
+        flex-wrap: wrap;
+
+        .recipe-btn {
+          font-size: 14px;
+          padding: 8px 16px;
+          min-width: 80px;
+          transition: all 0.3s;
+
+          &:hover {
+            transform: translateY(-1px);
+          }
+        }
+      }
+
+      .recipe-tip {
+        color: #ff9900;
+        font-size: 14px;
+      }
+    }
+  }
+
+  .nutrition-warning {
+    margin-bottom: 16px;
+
+    :deep(.el-alert) {
+      background: #fff9ed;
+      border: 1px solid #faecd8;
+      padding: 8px 16px;
+
+      .el-alert__icon {
+        font-size: 16px;
+        color: #e6a23c;
+      }
+
+      .el-alert__title {
+        font-size: 14px;
+        color: #e6a23c;
+      }
+    }
+  }
+
+  .recipe-table {
+    margin-bottom: 16px;
+
+    :deep(.el-table) {
+      &::before {
+        display: none;
+      }
+
+      .el-table__header {
+        th {
+          background-color: #f5f7fa;
+          color: #606266;
+          font-weight: 500;
+          padding: 8px 0;
+        }
+      }
+
+      .el-table__body {
+        td {
+          padding: 8px;
+        }
+      }
+
+      .cell {
+        color: #606266;
+      }
+    }
+  }
+}
+
+.nutrition-analysis {
+  background: #fff;
+  border-radius: 8px;
+  padding: 20px;
+
+  .nutrition-content {
+    .nutrition-header {
+      display: flex;
+      gap: 24px;
+      margin-bottom: 20px;
+
+      .nutrition-target,
+      .nutrition-actual {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        color: #606266;
+
+        .value {
+          color: #409eff;
+          font-weight: 600;
+        }
+      }
+    }
+  }
+
+  .chart-container {
+    text-align: center;
+    padding: 20px;
+
+    .chart-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 20px;
+    }
+
+    .chart-content {
+      height: 300px;
+      margin-bottom: 20px;
+    }
+
+    .chart-legend {
+      display: flex;
+      justify-content: center;
+      gap: 24px;
+
+      .legend-item {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        color: #606266;
+        font-size: 14px;
+
+        .color-block {
+          width: 12px;
+          height: 12px;
+          border-radius: 2px;
+
+          &.protein {
+            background-color: #36cfc9;
+          }
+
+          &.fat {
+            background-color: #ffa940;
+          }
+
+          &.carbs {
+            background-color: #2f54eb;
+          }
+        }
+      }
+    }
+  }
+}
+
+:deep(.el-table) {
+  .el-table__header {
+    th {
+      background-color: #f5f7fa;
+      color: #606266;
+      font-weight: 500;
+    }
+  }
+
+  .cell {
+    white-space: pre-line;
+  }
+}
+
+.table-wrapper {
+  width: 100%;
+  overflow-x: auto;
+  margin-bottom: 16px;
+}
+
+.recipe-table {
+  width: 100%;
+  border-collapse: collapse;
+  border: 1px solid #ebeef5;
+
+  th,
+  td {
+    border: 1px solid #ebeef5;
+    padding: 12px 8px;
+    font-size: 14px;
+    line-height: 1.5;
+  }
+
+  th {
+    background-color: #e8f4ff;
+    color: #333;
+    font-weight: normal;
+    text-align: center;
+  }
+
+  td {
+    background-color: #fff;
+    color: #606266;
+  }
+
+  .text-center {
+    text-align: center;
+  }
+
+  tbody {
+    tr {
+      &.row-even {
+        td {
+          background-color: #f5f7fa;
+        }
+      }
+
+      &:hover td {
+        background-color: #f5f7fa;
+      }
+    }
+  }
+}
+
+// 设置列宽
+.recipe-table {
+  th,
+  td {
+    &:nth-child(1) {
+      width: 80px;
+    }
+
+    // 餐次
+    &:nth-child(2) {
+      width: 120px;
+    }
+
+    // 用餐时间
+    &:nth-child(3) {
+      min-width: 180px;
+    }
+
+    // 食谱名称
+    &:nth-child(4) {
+      width: 160px;
+    }
+
+    // 食谱分类
+    &:nth-child(5) {
+      width: 80px;
+    }
+
+    // 份数
+    &:nth-child(6) {
+      width: 120px;
+    }
+
+    // 食材重量
+    &:nth-child(7) {
+      width: 120px;
+    }
+
+    // 热量
+    &:nth-child(7) {
+      width: 100px;
+    }
+  }
+}
+
+.analysis-card {
+  margin-top: 16px;
+
+  .nutrition-header {
+    display: flex;
+    gap: 32px;
+    margin-bottom: 16px;
+    font-size: 14px;
+    color: #606266;
+
+    span {
+      color: #409eff;
+      margin-left: 4px;
+    }
+  }
+
+  .nutrition-content {
+    display: flex;
+    gap: 24px;
+  }
+
+  .table-section {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .nutrition-table {
+    width: 100%;
+    border-collapse: collapse;
+
+    th,
+    td {
+      padding: 12px;
+      text-align: left;
+      border: 1px solid #ebeef5;
+      font-size: 14px;
+    }
+
+    th {
+      background-color: #f5f7fa;
+      color: #606266;
+      font-weight: normal;
+    }
+
+    td {
+      background: #fff;
+      color: #606266;
+    }
+  }
+
+  .chart-section {
+    width: 400px;
+    flex-shrink: 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  .chart-title {
+    font-size: 14px;
+    color: #303133;
+    margin-bottom: 16px;
+    text-align: center;
+  }
+
+  .chart-container {
+    width: 100%;
+    height: 220px;
+  }
+
+  .chart-legend {
+    margin-top: 16px;
+    display: flex;
+    gap: 16px;
+    justify-content: center;
+
+    .legend-item {
+      display: flex;
+      align-items: center;
+      gap: 4px;
+      font-size: 12px;
+      color: #606266;
+    }
+
+    .color-dot {
+      width: 8px;
+      height: 8px;
+      border-radius: 50%;
+
+      &.protein {
+        background-color: #36cfc9;
+      }
+
+      &.fat {
+        background-color: #ffd666;
+      }
+
+      &.carbs {
+        background-color: #85a5ff;
+      }
+    }
+  }
+}
+
+.nutrition-analysis-table {
+  width: 100%;
+  border-collapse: collapse;
+  text-align: center;
+
+  thead {
+    position: sticky;
+    top: 0;
+    z-index: 1;
+    background-color: #fff;
+
+    th {
+      background-color: #e8f4ff;
+      border: 1px solid #ebeef5;
+      padding: 12px 8px;
+      font-size: 14px;
+      line-height: 1.5;
+      text-align: center;
+      vertical-align: middle;
+      color: #606266;
+      font-weight: normal;
+      height: 44px;
+      white-space: nowrap;
+    }
+  }
+
+  td {
+    padding: 12px 8px;
+    border: 1px solid #ebeef5;
+    font-size: 14px;
+    line-height: 1.5;
+    text-align: center;
+    vertical-align: middle;
+    color: #606266;
+    height: 44px;
+    white-space: nowrap;
+    background-color: #fff; // 内容单元格统一使用白色背景
+
+    &.highlight {
+      color: #ff4d4f; // 保持高亮数字的红色
+    }
+
+    &.type-cell {
+      text-align: center;
+      background-color: #fff; // 类型单元格也使用白色背景
+      display: table-cell;
+    }
+  }
+
+  tbody {
+    tr {
+      background-color: #fff; // 所有行使用白色背景
+    }
+  }
+}
+
+.table-wrapper {
+  height: 500px;
+  overflow-y: auto;
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #c0c4cc;
+    border-radius: 3px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f5f7fa;
+  }
+
+  table {
+    width: 100%;
+    border-collapse: collapse;
+
+    thead {
+      position: sticky;
+      top: 0;
+      z-index: 1;
+      background-color: #e8f4ff;
+
+      th {
+        background-color: #e8f4ff;
+        border: 1px solid #ebeef5;
+        padding: 12px 8px;
+        font-size: 14px;
+        line-height: 1.5;
+        text-align: center;
+        vertical-align: middle;
+        color: #606266;
+        font-weight: normal;
+        height: 44px;
+        white-space: nowrap;
+      }
+    }
+
+    tbody {
+      td {
+        border: 1px solid #ebeef5;
+        padding: 12px 8px;
+        font-size: 14px;
+        line-height: 1.5;
+        text-align: center;
+        vertical-align: middle;
+        color: #606266;
+        height: 44px;
+        white-space: nowrap;
+        background-color: #fff;
+
+        &.highlight {
+          color: #ff4d4f;
+        }
+
+        &.type-cell {
+          text-align: center;
+          background-color: #fff;
+          display: table-cell;
+        }
+      }
+
+      tr {
+        background-color: #fff;
+      }
+    }
+  }
+}
+</style>

+ 234 - 251
src/views/patients/dietTherapy/dailyIndex.vue

@@ -1,256 +1,239 @@
 <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" label-width="120px">
-                        <el-form-item label="推荐时间:">
-                            <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
-                        </el-form-item>
-                        <el-form-item label="看诊类型:">
-                            <el-select v-model="queryParams.type" class="spec-unit-select">
-                                <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-                            </el-select>
-                        </el-form-item>
-                        <el-form-item>
-                            <el-input v-model="queryParams.searchValue" placeholder="门诊号/住院号/医生" style="width: 240px; " clearable />
-                        </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" plain icon="Plus" @click="emit('addDaily')" v-hasPermi="['patients:dailyMealPlan:add']">新增日常膳食</el-button>
-                    </el-col>
-                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-                </el-row>
-            </template>
-
-            <el-table v-loading="loading" border :data="mealPlanList" @selection-change="handleSelectionChange">
-                <el-table-column type="selection" width="55" align="center" />
-                <el-table-column label="推荐时间" align="center" prop="createTime" />
-                <el-table-column label="看诊类型" align="center" prop="type">
-                    <template #default="scope">
-                        <span>{{getDictLabel(treatment_user_type ,scope.row.type )|| '--' }}</span>
-                    </template>
-                </el-table-column>
-                <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
-                <el-table-column label="推荐医生" align="center" prop="createByUser" />
-                <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="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['patients:dailyMealPlan:edit']"></el-button>
-                        </el-tooltip>
-                        <el-tooltip content="删除" placement="top">
-                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['patients:dailyMealPlan: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" />
+  <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" label-width="120px">
+            <el-form-item label="推荐时间:">
+              <el-date-picker
+                v-model="queryParams.dateRange"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+              />
+            </el-form-item>
+            <el-form-item label="看诊类型:">
+              <el-select v-model="queryParams.type" class="spec-unit-select">
+                <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-input v-model="queryParams.searchValue" placeholder="门诊号/住院号/医生" style="width: 240px" clearable />
+            </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>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="emit('addDaily')" v-hasPermi="['patients:dailyMealPlan:add']">新增日常膳食</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="mealPlanList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="推荐时间" align="center" prop="createTime" />
+        <el-table-column label="看诊类型" align="center" prop="type">
+          <template #default="scope">
+            <span>{{ getDictLabel(treatment_user_type, scope.row.type) || '--' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
+        <el-table-column label="推荐医生" align="center" prop="createByUser" />
+        <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="handleView(scope.row)">详情</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>
+  </div>
 </template>
 
 <script setup name="MealPlan" lang="ts">
-    import { listDailyMealPlan, getMealPlan, delMealPlan, addMealPlan, updateMealPlan } from '@/api/patients/dailyMealPlan';
-    import { MealPlanVO, MealPlanQuery, MealPlanForm } from '@/api/patients/dailyMealPlan/types';
-
-    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-    const { treatment_user_type } = toRefs < any > (proxy ?.useDict('treatment_user_type'));
-
-    const mealPlanList = ref < MealPlanVO[] > ([]);
-    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 emit = defineEmits(['addDaily']);
-
-    const queryFormRef = ref < ElFormInstance > ();
-    const mealPlanFormRef = ref < ElFormInstance > ();
-
-    const dialog = reactive < DialogOption > ({
-        visible: false,
-        title: ''
-    });
-    const props = defineProps({
-        patientInfo: {
-            type: Object,
-            required: true,
-            default: () => ({
-                id: '',
-                name: '',
-                age: '',
-                gender: ''
-            })
-        }
-    });
-
-    const initFormData: MealPlanForm = {
-        id: undefined,
-        type: props.patientInfo.type,
-        patientId: props.patientInfo.id,
-        outpatientNo: props.patientInfo.outpatientNo,
-        deptId: props.patientInfo.deptId,
-        recommendStartDate: undefined,
-        recommendEndDate: undefined,
-        status: undefined,
-        remark: undefined,
-        mealRecipeList: [],
-    }
-    const data = reactive < PageData < MealPlanForm,
-        MealPlanQuery >> ({
-            form: { ...initFormData },
-            queryParams: {
-                pageNum: 1,
-                pageSize: 10,
-                type: undefined,
-                patientId: props.patientInfo.id,
-                outpatientNo: undefined,
-                deptId: undefined,
-                dateRange: [],
-                searchValue: undefined,
-                params: {}
-            },
-            rules: {
-                id: [
-                    { required: true, message: "主键不能为空", trigger: "blur" }
-                ],
-                patientId: [
-                    { required: true, message: "患者ID不能为空", trigger: "blur" }
-                ],
-            }
-        });
-
-    const { queryParams, form, rules } = toRefs(data);
-
-    /** 查询日常膳食主列表 */
-    const getList = async () => {
-        loading.value = true;
-        const res = await listDailyMealPlan(queryParams.value);
-        mealPlanList.value = res.rows;
-        total.value = res.total;
-        loading.value = false;
-    }
-
-    // 字典label工具
-    function getDictLabel(dictList: any[], value: string) {
-        if (!dictList || !Array.isArray(dictList)) return value || '--';
-        const found = dictList.find(item => item.value === value);
-        return found ? found.label : value || '--';
-    }
-
-    /** 取消按钮 */
-    const cancel = () => {
-        reset();
-        dialog.visible = false;
-    }
-
-    /** 表单重置 */
-    const reset = () => {
-        form.value = { ...initFormData };
-        mealPlanFormRef.value ?.resetFields();
-        queryParams.value.dateRange = undefined;
-        queryParams.value.type = undefined;
-        queryParams.value.searchValue = undefined;
-        queryParams.value.pageNum = 1;
-        queryParams.value.pageSize = 10;
-    }
-
-    /** 搜索按钮操作 */
-    const handleQuery = () => {
-        queryParams.value.pageNum = 1;
-        getList();
-    }
-
-    /** 重置按钮操作 */
-    const resetQuery = () => {
-        queryFormRef.value ?.resetFields();
-        queryParams.value.dateRange = undefined;
-        queryParams.value.type = undefined;
-        queryParams.value.searchValue = undefined;
-        queryParams.value.pageNum = 1;
-        queryParams.value.pageSize = 10;
-        handleQuery();
-    }
-
-    /** 多选框选中数据 */
-    const handleSelectionChange = (selection: MealPlanVO[]) => {
-        ids.value = selection.map(item => item.id);
-        single.value = selection.length != 1;
-        multiple.value = !selection.length;
-    }
-
-    /** 新增按钮操作 */
-    const handleAdd = () => {
-        reset();
-        dialog.visible = true;
-        dialog.title = "添加日常膳食";
-    }
-
-    /** 修改按钮操作 */
-    const handleUpdate = async (row ? : MealPlanVO) => {
-        reset();
-        const _id = row ?.id || ids.value[0]
-        const res = await getMealPlan(_id);
-        Object.assign(form.value, res.data);
-        dialog.visible = true;
-        dialog.title = "修改日常膳食";
-    }
-
-    /** 提交按钮 */
-    const submitForm = (mealPlanForm) => {
-
-        console.log('------' + mealPlanForm);
-
-        form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
-        form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
-        form.value.mealRecipeList = mealPlanForm.mealRecipeList;
-        addMealPlan(form.value).finally(() => buttonLoading.value = false);
-        getList();
-        mealPlanFormRef.value ?.validate(async (valid: boolean) => {
-            if (true) {
-                form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
-                form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
-                form.value.mealRecipeList = mealPlanForm.mealRecipeList;
-                buttonLoading.value = true;
-                if (form.value.id) {
-                    await updateMealPlan(form.value).finally(() => buttonLoading.value = false);
-                } else {
-                    await addMealPlan(form.value).finally(() => buttonLoading.value = false);
-                }
-                proxy ?.$modal.msgSuccess("操作成功");
-                dialog.visible = false;
-                await getList();
-            }
-        });
-    }
-
-    defineExpose({ submitForm });
-
-    /** 删除按钮操作 */
-    const handleDelete = async (row ? : MealPlanVO) => {
-        const _ids = row ?.id || ids.value;
-        await proxy ?.$modal.confirm('是否确认删除日常膳食主编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
-        await delMealPlan(_ids);
-        proxy ?.$modal.msgSuccess("删除成功");
-        await getList();
-    }
-
-    onMounted(() => {
-        getList();
-    });
-</script>
+import {listDailyMealPlan, getMealPlan, delMealPlan, addMealPlan, updateMealPlan} from '@/api/patients/dailyMealPlan';
+import {MealPlanVO, MealPlanQuery, MealPlanForm} from '@/api/patients/dailyMealPlan/types';
+
+const {proxy} = getCurrentInstance() as ComponentInternalInstance;
+const {treatment_user_type} = toRefs<any>(proxy?.useDict('treatment_user_type'));
+
+const mealPlanList = ref<MealPlanVO[]>([]);
+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 emit = defineEmits(['change', 'addDaily', 'back']);
+
+const queryFormRef = ref<ElFormInstance>();
+const mealPlanFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+const props = defineProps({
+  patientInfo: {
+    type: Object,
+    required: true,
+    default: () => ({
+      id: '',
+      name: '',
+      age: '',
+      gender: ''
+    })
+  }
+});
+
+const initFormData: MealPlanForm = {
+  id: undefined,
+  type: props.patientInfo.type,
+  patientId: props.patientInfo.id,
+  outpatientNo: props.patientInfo.outpatientNo,
+  deptId: props.patientInfo.deptId,
+  recommendStartDate: undefined,
+  recommendEndDate: undefined,
+  status: undefined,
+  remark: undefined,
+  mealRecipeList: []
+};
+const data = reactive<PageData<MealPlanForm, MealPlanQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    type: undefined,
+    patientId: props.patientInfo.id,
+    outpatientNo: undefined,
+    deptId: undefined,
+    dateRange: [],
+    searchValue: undefined,
+    params: {}
+  },
+  rules: {
+    id: [{required: true, message: '主键不能为空', trigger: 'blur'}],
+    patientId: [{required: true, message: '患者ID不能为空', trigger: 'blur'}]
+  }
+});
+
+const {queryParams, form, rules} = toRefs(data);
+
+/** 查询日常膳食主列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listDailyMealPlan(queryParams.value);
+  mealPlanList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+// 字典label工具
+function getDictLabel(dictList: any[], value: string) {
+  if (!dictList || !Array.isArray(dictList)) return value || '--';
+  const found = dictList.find((item) => item.value === value);
+  return found ? found.label : value || '--';
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  mealPlanFormRef.value?.resetFields();
+  queryParams.value.dateRange = undefined;
+  queryParams.value.type = undefined;
+  queryParams.value.searchValue = undefined;
+  queryParams.value.pageNum = 1;
+  queryParams.value.pageSize = 10;
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+const handleView = async (row?: MealPlanVO) => {
+  emit('change', 'dailyIndex', row);
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  queryParams.value.dateRange = undefined;
+  queryParams.value.type = undefined;
+  queryParams.value.searchValue = undefined;
+  queryParams.value.pageNum = 1;
+  queryParams.value.pageSize = 10;
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: MealPlanVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加日常膳食';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: MealPlanVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getMealPlan(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改日常膳食';
+};
+
+/** 提交按钮 */
+const submitForm = (mealPlanForm) => {
+  form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
+  form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
+  form.value.mealRecipeList = mealPlanForm.mealRecipeList;
+  addMealPlan(form.value).finally(() => (buttonLoading.value = false));
+  getList();
+};
+const handleDelete = async (id?: number) => {
+  const _ids = id;
+  await proxy?.$modal.confirm('是否确认作废日常膳食主编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delMealPlan(_ids);
+  proxy?.$modal.msgSuccess('作废成功');
+  emit('back', 'dailyIndex');
+  await getList();
+};
+
+defineExpose({submitForm, handleDelete});
+
+/** 删除按钮操作 */
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 1393 - 0
src/views/patients/dietTherapy/hospitalDetail.vue

@@ -0,0 +1,1393 @@
+<template>
+  <div class="container">
+    <!-- 食谱卡片 -->
+    <el-card class="recipe-card">
+      <img src="../../../assets/images/no_pay.png" alt="待支付" class="pay-status-icon" />
+      <!-- 返回按钮和标题 -->
+      <div class="card-header">
+        <el-button plain @click="goBack" class="back">返回</el-button>
+        <span class="title">院内膳食</span>
+      </div>
+
+      <!-- 日期和操作栏 -->
+      <div class="date-operation-bar">
+        <div class="date-picker">
+          <span>配餐日期:</span>
+          <el-date-picker
+            v-model="dateRange"
+            type="daterange"
+            disabled
+            range-separator="-"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            size="default"
+            class="date-input"
+          />
+        </div>
+        <div class="operation-btns">
+          <el-button type="primary" plain size="default">打印</el-button>
+          <el-button type="success" plain size="default" @click="quoteMealPlan">引用处方</el-button>
+          <el-button type="danger" plain size="default" @click="deleteMealPlan">作废</el-button>
+        </div>
+      </div>
+
+      <!-- 食谱标题区域 -->
+      <div class="recipe-header">
+        <div class="recipe-title-wrapper">
+          <div class="recipe-buttons">
+            <el-button
+              v-for="(recipe, index) in allRecipesData"
+              :key="index"
+              :type="currentRecipeIndex === index ? 'success' : 'default'"
+              plain
+              class="recipe-btn"
+              @click="switchToRecipe(index)"
+            >
+              食谱{{ index + 1 }}
+            </el-button>
+          </div>
+          <span class="recipe-tip">周食谱模板的食谱数量小于7时,食谱可循环使用</span>
+        </div>
+      </div>
+
+      <!-- 营养警告 -->
+      <div class="nutrition-warning">
+        <el-alert
+          :title="'当前处方中的热量、蛋白质、脂肪、碳水化合物、钙、铁、维生素A、维生素B2、维生素C、维生素E元素可能过量'"
+          type="warning"
+          show-icon
+          :closable="false"
+        />
+      </div>
+
+      <!-- 食谱表格 -->
+      <div class="table-wrapper">
+        <table style="text-align: center" class="recipe-table">
+          <thead>
+            <tr>
+              <th>餐次</th>
+              <th>用餐时间</th>
+              <th>食谱名称</th>
+              <th>食谱分类</th>
+              <th>份数</th>
+              <th>食材重量</th>
+              <th>热量</th>
+              <th>金额</th>
+            </tr>
+          </thead>
+          <tbody>
+            <template v-for="(meal, mealIndex) in tableData" :key="mealIndex">
+              <tr v-for="(recipe, recipeIndex) in meal.recipes" :key="recipeIndex" :class="{'row-even': recipeIndex % 2 === 1}">
+                <td v-if="recipeIndex === 0" :rowspan="meal.recipes.length" class="text-center">{{ meal.meal }}</td>
+                <td v-if="recipeIndex === 0" :rowspan="meal.recipes.length" class="text-center">{{ meal.time }}</td>
+                <td>{{ recipe.name }}</td>
+                <td>{{ recipe.category }}</td>
+                <td class="text-center">{{ recipe.count }}</td>
+                <td class="text-center">{{ recipe.weight }}</td>
+                <td class="text-center">{{ recipe.calorie }}</td>
+                <td class="text-center">{{ recipe.amount }}</td>
+              </tr>
+            </template>
+          </tbody>
+        </table>
+      </div>
+
+      <!-- 费用统计 -->
+      <div class="total-amount">
+        <span>费用:</span>
+        <span class="amount">{{ totalPrice }}元</span>
+      </div>
+    </el-card>
+
+    <!-- 营养分析卡片 -->
+    <el-card class="analysis-card" v-if="false">
+      <el-tabs v-model="activeTab">
+        <el-tab-pane label="三大营养分析" name="nutrition">
+          <div class="nutrition-header">
+            <div class="nutrition-target">
+              营养设定:<span>{{ nutritionTarget }}kcal/d</span>
+            </div>
+            <div class="nutrition-actual">
+              实际热量:<span>{{ actualCalories }}kcal/d</span>
+            </div>
+          </div>
+          <div class="nutrition-content">
+            <!-- 左侧表格 -->
+            <div class="table-section">
+              <table class="nutrition-table">
+                <thead>
+                  <tr>
+                    <th>三大营养素</th>
+                    <th>质量(g)</th>
+                    <th>热量占比</th>
+                    <th>参考值</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr v-for="item in nutritionData" :key="item.name">
+                    <td>{{ item.name }}</td>
+                    <td>{{ item.weight }}</td>
+                    <td>{{ item.ratio }}%</td>
+                    <td>{{ item.reference }}</td>
+                  </tr>
+                </tbody>
+              </table>
+            </div>
+            <!-- 右侧图表 -->
+            <div class="chart-section">
+              <div class="chart-title">三大营养素元素质量占比</div>
+              <div ref="chartRef" class="chart-container"></div>
+              <div class="chart-legend">
+                <div class="legend-item">
+                  <span class="color-dot protein"></span>
+                  <span>蛋白质 26.14%</span>
+                </div>
+                <div class="legend-item">
+                  <span class="color-dot fat"></span>
+                  <span>脂肪 11.64%</span>
+                </div>
+                <div class="legend-item">
+                  <span class="color-dot carbs"></span>
+                  <span>碳水化合物 62.02%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="营养数据分析" name="data">
+          <div style="text-align: center" class="table-wrapper">
+            <table class="nutrition-analysis-table">
+              <thead>
+                <tr>
+                  <th rowspan="2">元素类型</th>
+                  <th rowspan="2">元素名称</th>
+                  <th rowspan="2">单位</th>
+                  <th colspan="2">膳食营养含量/天</th>
+                  <th rowspan="2">肠外营养含量/天</th>
+                  <th rowspan="2">肠内营养含量/天</th>
+                  <th rowspan="2">营养设定</th>
+                </tr>
+                <tr>
+                  <th>当前处方</th>
+                  <th>历史处方</th>
+                </tr>
+              </thead>
+              <tbody>
+                <template v-for="group in groupedNutritionData" :key="group.type">
+                  <template v-for="(item, itemIndex) in group.items" :key="item.name">
+                    <tr>
+                      <td v-if="itemIndex === 0" :rowspan="group.items.length" class="type-cell">{{ group.type }}</td>
+                      <td class="name-cell">{{ item.name }}</td>
+                      <td class="unit-cell">{{ item.unit }}</td>
+                      <td :class="{highlight: item.current > item.target}">{{ item.current }}</td>
+                      <td>{{ item.history || '--' }}</td>
+                      <td>{{ item.external || '--' }}</td>
+                      <td>{{ item.internal || '--' }}</td>
+                      <td>{{ item.target }}</td>
+                    </tr>
+                  </template>
+                </template>
+              </tbody>
+            </table>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref, onMounted, computed, watch} from 'vue';
+import * as echarts from 'echarts';
+import {ArrowLeft} from '@element-plus/icons-vue';
+const emit = defineEmits(['change', 'del', 'add']);
+
+import {getMealPlan} from '@/api/patients/hospitalMealPlan';
+import {MealPlanVO, MealPlanQuery, MealPlanForm} from '@/api/patients/hospitalMealPlan/types';
+
+interface NutritionItem {
+  type: string;
+  name: string;
+  unit: string;
+  current: string;
+  history: string;
+  external: string; // 肠外营养含量
+  internal: string; // 肠内营养含量
+  target: string;
+}
+// 表格数据
+const tableData = ref([]);
+const activeTab = ref('nutrition');
+const dateRange = ref([]);
+const totalPrice = ref(0.0);
+const currentRecipeIndex = ref(0); // 当前显示的食谱索引
+const allRecipesData = ref([]); // 存储所有食谱数据
+const mealPlanVo = ref();
+
+// 切换食谱
+const switchRecipe = (direction: number) => {
+  const newIndex = currentRecipeIndex.value + direction;
+  if (newIndex >= 0 && newIndex < allRecipesData.value.length) {
+    currentRecipeIndex.value = newIndex;
+    tableData.value = allRecipesData.value[currentRecipeIndex.value] || [];
+  }
+};
+
+// 直接切换到指定食谱
+const switchToRecipe = (index: number) => {
+  if (index >= 0 && index < allRecipesData.value.length) {
+    currentRecipeIndex.value = index;
+    tableData.value = allRecipesData.value[currentRecipeIndex.value] || [];
+  }
+};
+
+// 营养数据
+const nutritionData = ref([
+  {name: '蛋白质', weight: '71.4860', ratio: '23.74', reference: '10% - 15%'},
+  {name: '脂肪', weight: '32.3765', ratio: '24.19', reference: '20% - 30%'},
+  {name: '碳水化合物', weight: '169.6211', ratio: '56.32', reference: '50% - 65%'}
+]);
+
+// 图表引用
+const chartRef = ref<HTMLElement | null>(null);
+// 声明接收的 props
+const props = defineProps({
+  infoId: {
+    type: [Number, String],
+    required: true
+  }
+});
+// 修改图表配置
+const initChart = () => {
+  if (!chartRef.value) return;
+
+  const chart = echarts.init(chartRef.value);
+  const option = {
+    tooltip: {
+      trigger: 'item',
+      formatter: '{b}: {c}%'
+    },
+    legend: {
+      show: false
+    },
+    series: [
+      {
+        type: 'pie',
+        radius: ['50%', '70%'],
+        center: ['50%', '50%'],
+        avoidLabelOverlap: false,
+        label: {
+          show: false
+        },
+        labelLine: {
+          show: false
+        },
+        emphasis: {
+          scale: false,
+          scaleSize: 0
+        },
+        data: [
+          {
+            value: 26.14,
+            name: '蛋白质',
+            itemStyle: {
+              color: '#36cfc9',
+              borderWidth: 0
+            }
+          },
+          {
+            value: 11.64,
+            name: '脂肪',
+            itemStyle: {
+              color: '#ffd666',
+              borderWidth: 0
+            }
+          },
+          {
+            value: 62.02,
+            name: '碳水化合物',
+            itemStyle: {
+              color: '#85a5ff',
+              borderWidth: 0
+            }
+          }
+        ]
+      }
+    ]
+  };
+
+  chart.setOption(option);
+
+  // 监听窗口大小变化
+  window.addEventListener('resize', () => {
+    chart.resize();
+  });
+};
+
+// 返回上一页
+const goBack = async () => {
+  emit('change', 'hospitalIndex');
+};
+const quoteMealPlan = async () => {
+  emit('add', 'hospitalDetail', mealPlanVo.value);
+};
+const deleteMealPlan = async () => {
+  emit('del', 'hospitalDetail', props.infoId);
+};
+
+// 添加响应式数据
+const nutritionTarget = ref('1035.35');
+const actualCalories = ref('1204.60');
+
+// 按元素类型分组的数据
+const groupedNutritionData = computed(() => {
+  const groups: {
+    [key: string]: any[];
+  } = {};
+  nutritionAnalysisData.forEach((item) => {
+    if (!groups[item.type]) {
+      groups[item.type] = [];
+    }
+    groups[item.type].push(item);
+  });
+  return Object.entries(groups).map(([type, items]) => ({
+    type,
+    items
+  }));
+});
+
+// 营养数据分析数据
+const nutritionAnalysisData: NutritionItem[] = [
+  {
+    type: '热能及三大营养素',
+    name: '热量',
+    unit: 'kcal',
+    current: '1204.5965',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1035.35'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '蛋白质',
+    unit: 'g',
+    current: '71.486',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '50'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '脂肪',
+    unit: 'g',
+    current: '32.3765',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '23.01'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '碳水化合物',
+    unit: 'g',
+    current: '169.6211',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '129.42'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '热能-kilojoules',
+    unit: 'kj',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '4331.9'
+  },
+  {
+    type: '常量元素',
+    name: '钠',
+    unit: 'mg',
+    current: '1026.8556',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1500'
+  },
+  {
+    type: '常量元素',
+    name: '磷',
+    unit: 'mg',
+    current: '331.8685',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '720'
+  },
+  {
+    type: '常量元素',
+    name: '钙',
+    unit: 'mg',
+    current: '862.651',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '800'
+  },
+  {
+    type: '常量元素',
+    name: '钾',
+    unit: 'mg',
+    current: '439.089',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '2000'
+  },
+  {
+    type: '常量元素',
+    name: '镁',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '530'
+  },
+  {
+    type: '常量元素',
+    name: '氯',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '2300'
+  },
+  {
+    type: '微量元素',
+    name: '铁',
+    unit: 'mg',
+    current: '20.6671',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '20'
+  },
+  {
+    type: '微量元素',
+    name: '锌',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '7.5'
+  },
+  {
+    type: '微量元素',
+    name: '硒',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '60'
+  },
+  {
+    type: '微量元素',
+    name: '铜',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '0.8'
+  },
+  {
+    type: '微量元素',
+    name: '锰',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '4.5'
+  },
+  {
+    type: '微量元素',
+    name: '碘',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '120'
+  },
+  {
+    type: '微量元素',
+    name: '氟',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.5'
+  },
+  {
+    type: '微量元素',
+    name: '铬',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '30'
+  },
+  {
+    type: '维生素',
+    name: '维生素B2',
+    unit: 'mg',
+    current: '1.9407',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.2'
+  },
+  {
+    type: '维生素',
+    name: '维生素C',
+    unit: 'mg',
+    current: '166.742',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '100'
+  },
+  {
+    type: '维生素',
+    name: '维生素B1',
+    unit: 'mg',
+    current: '1.1105',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.2'
+  },
+  {
+    type: '维生素',
+    name: '烟酸',
+    unit: 'mg',
+    current: '10.396',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '12'
+  },
+  {
+    type: '维生素',
+    name: '维生素E',
+    unit: 'mg',
+    current: '20.4819',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '14'
+  },
+  {
+    type: '维生素',
+    name: '维生素D',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '10'
+  },
+  {
+    type: '维生素',
+    name: '维生素K',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '80'
+  },
+  {
+    type: '维生素',
+    name: '维生素B6',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '1.4'
+  },
+  {
+    type: '维生素',
+    name: '维生素B12',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '2.4'
+  },
+  {
+    type: '维生素',
+    name: '叶酸',
+    unit: 'μgDFE',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '400'
+  },
+  {
+    type: '维生素',
+    name: '胆碱',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '400'
+  },
+  {
+    type: '维生素',
+    name: '生物素',
+    unit: 'μg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '40'
+  },
+  {
+    type: '维生素',
+    name: '泛醇',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '5'
+  },
+  {
+    type: '脂类',
+    name: '胆固醇',
+    unit: 'g',
+    current: '0.6345',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '--'
+  },
+  {
+    type: '其他',
+    name: '水分',
+    unit: 'ml',
+    current: '1147.0572',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '--'
+  },
+  {
+    type: '其他',
+    name: '膳食纤维',
+    unit: 'g',
+    current: '10.7333',
+    history: '--',
+    external: '--',
+    internal: '--',
+    target: '25'
+  }
+];
+
+/** 查询院内膳食主列表 */
+const getDetail = async () => {
+  if (props.infoId && (typeof props.infoId === 'number' || typeof props.infoId === 'string')) {
+    try {
+      const res = await getMealPlan(props.infoId);
+
+      if (res.code === 200 && res.data) {
+        mealPlanVo.value = res.data;
+        const data = res.data as any;
+
+        // 更新日期范围
+        if (data.recommendStartDate && data.recommendEndDate) {
+          dateRange.value = [data.recommendStartDate, data.recommendEndDate];
+        }
+        if (data.totalPrice) {
+          totalPrice.value = data.totalPrice;
+        }
+
+        // 更新表格数据
+        if (data.mealRecipeList && data.mealRecipeList.length > 0) {
+          // 按食谱编号分组数据
+          const recipeGroups = {};
+
+          data.mealRecipeList.forEach((recipe) => {
+            const recipeNo = recipe.recipeNo;
+            if (!recipeGroups[recipeNo]) {
+              recipeGroups[recipeNo] = [];
+            }
+
+            // 按餐次分组
+            const mealTime = recipe.mealTime;
+            let mealGroup = recipeGroups[recipeNo].find((group) => group.meal === mealTime);
+
+            if (!mealGroup) {
+              mealGroup = {
+                meal: mealTime,
+                time: recipe.eatTime ? recipe.eatTime.split(' ')[1] : '08:00',
+                recipes: []
+              };
+              recipeGroups[recipeNo].push(mealGroup);
+            }
+
+            mealGroup.recipes.push({
+              name: recipe.foodName,
+              category: recipe.foodCategoryName,
+              count: recipe.amount,
+              weight: recipe.foodWeight ? recipe.foodWeight.toString() : '0',
+              calorie: recipe.calorie ? recipe.calorie.toString() : '0',
+              amount: recipe.price ? recipe.price.toString() : '0'
+            });
+          });
+
+          // 存储所有食谱数据
+          allRecipesData.value = Object.values(recipeGroups) as any[];
+          // 设置当前显示的食谱
+          tableData.value = allRecipesData.value[currentRecipeIndex.value] || [];
+
+          // 如果有多个食谱,可以在这里添加食谱切换功能
+        }
+      }
+    } catch (error) {
+      console.error('获取详情失败:', error);
+    }
+  }
+};
+
+// 监听 infoId 变化,当有值时执行 getDetail
+watch(
+  () => props.infoId,
+  (newVal) => {
+    if (newVal) {
+      getDetail();
+    }
+  }
+);
+
+onMounted(() => {
+  initChart();
+  // 如果 onMounted 时已经有 infoId,也执行一次
+  if (props.infoId) {
+    getDetail();
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+  background: #f5f7fa;
+  min-height: 100vh;
+}
+
+.recipe-card {
+  background: #fff;
+  border-radius: 4px;
+  padding: 20px;
+  margin-bottom: 16px;
+  position: relative;
+  width: 89vw;
+
+  .pay-status-icon {
+    position: absolute;
+    top: -2px;
+    right: -4px;
+    width: 100px;
+    /* 调整为更合适的大小 */
+    height: 100px;
+    transform: rotate(10deg);
+    /* 添加轻微旋转以匹配设计 */
+    z-index: 1;
+  }
+
+  .card-header {
+    margin-bottom: 20px;
+
+    .back {
+      margin-right: 20px;
+    }
+
+    .header-left {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+
+      .back-btn {
+        border-radius: 4px;
+        padding: 8px 16px;
+      }
+
+      .title {
+        font-size: 16px;
+        font-weight: 500;
+        color: #303133;
+      }
+    }
+  }
+
+  .date-operation-bar {
+    display: flex;
+    align-items: center;
+    margin-bottom: 16px;
+    border-bottom: 1px solid #ebeef5;
+    padding-bottom: 16px;
+
+    .date-picker {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #606266;
+      margin-right: 20px;
+
+      .date-input {
+        width: 240px;
+      }
+    }
+
+    .operation-btns {
+      display: flex;
+      gap: 12px;
+    }
+  }
+
+  .recipe-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .recipe-title-wrapper {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      width: 100%;
+      gap: 12px;
+
+      .recipe-buttons {
+        display: flex;
+        gap: 8px;
+        flex-wrap: wrap;
+
+        .recipe-btn {
+          font-size: 14px;
+          padding: 8px 16px;
+          min-width: 80px;
+          transition: all 0.3s;
+
+          &:hover {
+            transform: translateY(-1px);
+          }
+        }
+      }
+
+      .recipe-tip {
+        color: #ff9900;
+        font-size: 14px;
+      }
+    }
+  }
+
+  .nutrition-warning {
+    margin-bottom: 16px;
+
+    :deep(.el-alert) {
+      background: #fff9ed;
+      border: 1px solid #faecd8;
+      padding: 8px 16px;
+
+      .el-alert__icon {
+        font-size: 16px;
+        color: #e6a23c;
+      }
+
+      .el-alert__title {
+        font-size: 14px;
+        color: #e6a23c;
+      }
+    }
+  }
+
+  .recipe-table {
+    margin-bottom: 16px;
+
+    :deep(.el-table) {
+      &::before {
+        display: none;
+      }
+
+      .el-table__header {
+        th {
+          background-color: #f5f7fa;
+          color: #606266;
+          font-weight: 500;
+          padding: 8px 0;
+        }
+      }
+
+      .el-table__body {
+        td {
+          padding: 8px;
+        }
+      }
+
+      .cell {
+        color: #606266;
+      }
+    }
+  }
+
+  .total-amount {
+    text-align: right;
+    font-size: 20px;
+    color: #606266;
+
+    .amount {
+      color: #f56c6c;
+      font-weight: bold;
+      margin-left: 4px;
+    }
+  }
+}
+
+.nutrition-analysis {
+  background: #fff;
+  border-radius: 8px;
+  padding: 20px;
+
+  .nutrition-content {
+    .nutrition-header {
+      display: flex;
+      gap: 24px;
+      margin-bottom: 20px;
+
+      .nutrition-target,
+      .nutrition-actual {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        color: #606266;
+
+        .value {
+          color: #409eff;
+          font-weight: 600;
+        }
+      }
+    }
+  }
+
+  .chart-container {
+    text-align: center;
+    padding: 20px;
+
+    .chart-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+      margin-bottom: 20px;
+    }
+
+    .chart-content {
+      height: 300px;
+      margin-bottom: 20px;
+    }
+
+    .chart-legend {
+      display: flex;
+      justify-content: center;
+      gap: 24px;
+
+      .legend-item {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        color: #606266;
+        font-size: 14px;
+
+        .color-block {
+          width: 12px;
+          height: 12px;
+          border-radius: 2px;
+
+          &.protein {
+            background-color: #36cfc9;
+          }
+
+          &.fat {
+            background-color: #ffa940;
+          }
+
+          &.carbs {
+            background-color: #2f54eb;
+          }
+        }
+      }
+    }
+  }
+}
+
+:deep(.el-table) {
+  .el-table__header {
+    th {
+      background-color: #f5f7fa;
+      color: #606266;
+      font-weight: 500;
+    }
+  }
+
+  .cell {
+    white-space: pre-line;
+  }
+}
+
+.table-wrapper {
+  width: 100%;
+  overflow-x: auto;
+  margin-bottom: 16px;
+}
+
+.recipe-table {
+  width: 100%;
+  border-collapse: collapse;
+  border: 1px solid #ebeef5;
+
+  th,
+  td {
+    border: 1px solid #ebeef5;
+    padding: 12px 8px;
+    font-size: 14px;
+    line-height: 1.5;
+  }
+
+  th {
+    background-color: #e8f4ff;
+    color: #333;
+    font-weight: normal;
+    text-align: center;
+  }
+
+  td {
+    background-color: #fff;
+    color: #606266;
+  }
+
+  .text-center {
+    text-align: center;
+  }
+
+  tbody {
+    tr {
+      &.row-even {
+        td {
+          background-color: #f5f7fa;
+        }
+      }
+
+      &:hover td {
+        background-color: #f5f7fa;
+      }
+    }
+  }
+}
+
+// 设置列宽
+.recipe-table {
+  th,
+  td {
+    &:nth-child(1) {
+      width: 80px;
+    }
+
+    // 餐次
+    &:nth-child(2) {
+      width: 120px;
+    }
+
+    // 用餐时间
+    &:nth-child(3) {
+      min-width: 180px;
+    }
+
+    // 食谱名称
+    &:nth-child(4) {
+      width: 160px;
+    }
+
+    // 食谱分类
+    &:nth-child(5) {
+      width: 80px;
+    }
+
+    // 份数
+    &:nth-child(6) {
+      width: 120px;
+    }
+
+    // 食材重量
+    &:nth-child(7) {
+      width: 120px;
+    }
+
+    // 热量
+    &:nth-child(8) {
+      width: 100px;
+    }
+
+    // 金额
+  }
+}
+
+.analysis-card {
+  margin-top: 16px;
+  width: 89vw;
+
+  .nutrition-header {
+    display: flex;
+    gap: 32px;
+    margin-bottom: 16px;
+    font-size: 14px;
+    color: #606266;
+
+    span {
+      color: #409eff;
+      margin-left: 4px;
+    }
+  }
+
+  .nutrition-content {
+    display: flex;
+    gap: 24px;
+  }
+
+  .table-section {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .nutrition-table {
+    width: 100%;
+    border-collapse: collapse;
+
+    th,
+    td {
+      padding: 12px;
+      text-align: left;
+      border: 1px solid #ebeef5;
+      font-size: 14px;
+    }
+
+    th {
+      background-color: #f5f7fa;
+      color: #606266;
+      font-weight: normal;
+    }
+
+    td {
+      background: #fff;
+      color: #606266;
+    }
+  }
+
+  .chart-section {
+    width: 400px;
+    flex-shrink: 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+
+  .chart-title {
+    font-size: 14px;
+    color: #303133;
+    margin-bottom: 16px;
+    text-align: center;
+  }
+
+  .chart-container {
+    width: 100%;
+    height: 220px;
+  }
+
+  .chart-legend {
+    margin-top: 16px;
+    display: flex;
+    gap: 16px;
+    justify-content: center;
+
+    .legend-item {
+      display: flex;
+      align-items: center;
+      gap: 4px;
+      font-size: 12px;
+      color: #606266;
+    }
+
+    .color-dot {
+      width: 8px;
+      height: 8px;
+      border-radius: 50%;
+
+      &.protein {
+        background-color: #36cfc9;
+      }
+
+      &.fat {
+        background-color: #ffd666;
+      }
+
+      &.carbs {
+        background-color: #85a5ff;
+      }
+    }
+  }
+}
+
+.nutrition-analysis-table {
+  width: 100%;
+  border-collapse: collapse;
+  text-align: center;
+
+  thead {
+    position: sticky;
+    top: 0;
+    z-index: 1;
+    background-color: #fff;
+
+    th {
+      background-color: #e8f4ff;
+      border: 1px solid #ebeef5;
+      padding: 12px 8px;
+      font-size: 14px;
+      line-height: 1.5;
+      text-align: center;
+      vertical-align: middle;
+      color: #606266;
+      font-weight: normal;
+      height: 44px;
+      white-space: nowrap;
+    }
+  }
+
+  td {
+    padding: 12px 8px;
+    border: 1px solid #ebeef5;
+    font-size: 14px;
+    line-height: 1.5;
+    text-align: center;
+    vertical-align: middle;
+    color: #606266;
+    height: 44px;
+    white-space: nowrap;
+    background-color: #fff; // 内容单元格统一使用白色背景
+
+    &.highlight {
+      color: #ff4d4f; // 保持高亮数字的红色
+    }
+
+    &.type-cell {
+      text-align: center;
+      background-color: #fff; // 类型单元格也使用白色背景
+      display: table-cell;
+    }
+  }
+
+  tbody {
+    tr {
+      background-color: #fff; // 所有行使用白色背景
+    }
+  }
+}
+
+.table-wrapper {
+  height: 500px;
+  overflow-y: auto;
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #c0c4cc;
+    border-radius: 3px;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: #f5f7fa;
+  }
+
+  table {
+    width: 100%;
+    border-collapse: collapse;
+
+    thead {
+      position: sticky;
+      top: 0;
+      z-index: 1;
+      background-color: #e8f4ff;
+
+      th {
+        background-color: #e8f4ff;
+        border: 1px solid #ebeef5;
+        padding: 12px 8px;
+        font-size: 14px;
+        line-height: 1.5;
+        text-align: center;
+        vertical-align: middle;
+        color: #606266;
+        font-weight: normal;
+        height: 44px;
+        white-space: nowrap;
+      }
+    }
+
+    tbody {
+      td {
+        border: 1px solid #ebeef5;
+        padding: 12px 8px;
+        font-size: 14px;
+        line-height: 1.5;
+        text-align: center;
+        vertical-align: middle;
+        color: #606266;
+        height: 44px;
+        white-space: nowrap;
+        background-color: #fff;
+
+        &.highlight {
+          color: #ff4d4f;
+        }
+
+        &.type-cell {
+          text-align: center;
+          background-color: #fff;
+          display: table-cell;
+        }
+      }
+
+      tr {
+        background-color: #fff;
+      }
+    }
+  }
+}
+</style>

+ 248 - 231
src/views/patients/dietTherapy/hospitalIndex.vue

@@ -1,258 +1,275 @@
 <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" label-width="120px">
-                        <el-form-item label="推荐时间:">
-                            <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
-                        </el-form-item>
-                        <el-form-item label="看诊类型:">
-                            <el-select v-model="queryParams.type" class="spec-unit-select">
-                                <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-                            </el-select>
-                        </el-form-item>
-                        <el-form-item>
-                            <el-input v-model="queryParams.searchValue" placeholder="门诊号/住院号/医生" style="width: 240px; " clearable />
-                        </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" plain icon="Plus" @click="emit('addHospital')" v-hasPermi="['patients:hospitalMealPlan:add']">新增院内膳食</el-button>
-                    </el-col>
-                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-                </el-row>
-            </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" label-width="120px">
+            <el-form-item label="推荐时间:">
+              <el-date-picker
+                v-model="queryParams.dateRange"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+              />
+            </el-form-item>
+            <el-form-item label="看诊类型:">
+              <el-select v-model="queryParams.type" class="spec-unit-select">
+                <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-input v-model="queryParams.searchValue" placeholder="门诊号/住院号/医生" style="width: 240px" clearable />
+            </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-table v-loading="loading" border :data="mealPlanList" @selection-change="handleSelectionChange">
-                <el-table-column type="selection" width="55" align="center" />
-                <el-table-column label="推荐时间" align="center" prop="createTime" />
-                <el-table-column label="看诊类型" align="center" prop="type">
-                    <template #default="scope">
-                        <span>{{getDictLabel(treatment_user_type ,scope.row.type )|| '--' }}</span>
-                    </template>
-                </el-table-column>
-                <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
-                <el-table-column label="处方状态" align="center" prop="status">
-                    <template #default="scope">
-                        <span>{{getDictLabel(payment_status ,scope.row.status )|| '--' }}</span>
-                    </template>
-                </el-table-column>
-                <el-table-column label="推荐医生" align="center" prop="createByUser" />
-                <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="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['patients:hospitalMealPlan:edit']"></el-button>
-                        </el-tooltip>
-                        <el-tooltip content="删除" placement="top">
-                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['patients:hospitalMealPlan:remove']"></el-button>
-                        </el-tooltip>
-                    </template>
-                </el-table-column>
-            </el-table>
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="emit('addHospital')" v-hasPermi="['patients:hospitalMealPlan:add']"
+              >新增院内膳食</el-button
+            >
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
 
-            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
-        </el-card>
+      <el-table v-loading="loading" border :data="mealPlanList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="推荐时间" align="center" prop="createTime" />
+        <el-table-column label="看诊类型" align="center" prop="type">
+          <template #default="scope">
+            <span>{{ getDictLabel(treatment_user_type, scope.row.type) || '--' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
+        <el-table-column label="处方状态" align="center" prop="status">
+          <template #default="scope">
+            <span>{{ getDictLabel(payment_status, scope.row.status) || '--' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="推荐医生" align="center" prop="createByUser" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="详情">
+              <el-button link type="primary" icon="View" @click="handleView(scope.row)">详情</el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
 
-    </div>
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+  </div>
 </template>
 
 <script setup name="MealPlan" lang="ts">
-    import { listMealPlan, getMealPlan, delMealPlan, addMealPlan, updateMealPlan } from '@/api/patients/hospitalMealPlan';
-    import { MealPlanVO, MealPlanQuery, MealPlanForm } from '@/api/patients/hospitalMealPlan/types';
+import {listMealPlan, getMealPlan, delMealPlan, addMealPlan, updateMealPlan} from '@/api/patients/hospitalMealPlan';
+import {MealPlanVO, MealPlanQuery, MealPlanForm} from '@/api/patients/hospitalMealPlan/types';
+import {useHospitalStore} from '@/store/modules/hospital';
 
-    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-    const { treatment_user_type, payment_status } = toRefs < any > (proxy ?.useDict('treatment_user_type', 'payment_status'));
+const useStore = useHospitalStore();
+const {setHospitalList, hospitalList} = useStore;
 
-    const mealPlanList = ref < MealPlanVO[] > ([]);
-    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 emit = defineEmits(['addHospital']);
+const {proxy} = getCurrentInstance() as ComponentInternalInstance;
+const {treatment_user_type, payment_status} = toRefs<any>(proxy?.useDict('treatment_user_type', 'payment_status'));
 
-    const queryFormRef = ref < ElFormInstance > ();
-    const mealPlanFormRef = ref < ElFormInstance > ();
+const mealPlanList = ref<MealPlanVO[]>([]);
+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 emit = defineEmits(['change', 'addHospital', 'back']);
 
-    const dialog = reactive < DialogOption > ({
-        visible: false,
-        title: ''
-    });
-    const props = defineProps({
-        patientInfo: {
-            type: Object,
-            required: true,
-            default: () => ({
-                id: '',
-                name: '',
-                age: '',
-                gender: ''
-            })
-        }
-    });
+const queryFormRef = ref<ElFormInstance>();
+const mealPlanFormRef = ref<ElFormInstance>();
 
-    const initFormData: MealPlanForm = {
-        id: undefined,
-        type: props.patientInfo.type,
-        patientId: props.patientInfo.id,
-        outpatientNo: props.patientInfo.outpatientNo,
-        deptId: props.patientInfo.deptId,
-        recommendStartDate: undefined,
-        recommendEndDate: undefined,
-        status: undefined,
-        remark: undefined,
-        mealRecipeList: [],
-    }
-    const data = reactive < PageData < MealPlanForm,
-        MealPlanQuery >> ({
-            form: { ...initFormData },
-            queryParams: {
-                pageNum: 1,
-                pageSize: 10,
-                type: undefined,
-                patientId: props.patientInfo.id,
-                outpatientNo: undefined,
-                deptId: undefined,
-                dateRange: [],
-                searchValue: undefined,
-                params: {}
-            },
-            rules: {
-                id: [
-                    { required: true, message: "主键不能为空", trigger: "blur" }
-                ],
-                patientId: [
-                    { required: true, message: "患者ID不能为空", trigger: "blur" }
-                ],
-            }
-        });
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+const props = defineProps({
+  patientInfo: {
+    type: Object,
+    required: true,
+    default: () => ({
+      id: '',
+      name: '',
+      age: '',
+      gender: ''
+    })
+  }
+});
 
-    const { queryParams, form, rules } = toRefs(data);
+const initFormData: MealPlanForm = {
+  id: undefined,
+  type: props.patientInfo.type,
+  patientId: props.patientInfo.id,
+  outpatientNo: props.patientInfo.outpatientNo,
+  deptId: props.patientInfo.deptId,
+  recommendStartDate: undefined,
+  recommendEndDate: undefined,
+  totalPrice: undefined,
+  status: undefined,
+  remark: undefined,
+  mealRecipeList: []
+};
+const data = reactive<PageData<MealPlanForm, MealPlanQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    type: undefined,
+    patientId: props.patientInfo.id,
+    outpatientNo: undefined,
+    deptId: undefined,
+    dateRange: [],
+    searchValue: undefined,
+    params: {}
+  },
+  rules: {
+    id: [{required: true, message: '主键不能为空', trigger: 'blur'}],
+    patientId: [{required: true, message: '患者ID不能为空', trigger: 'blur'}]
+  }
+});
 
-    /** 查询院内膳食主列表 */
-    const getList = async () => {
-        loading.value = true;
-        const res = await listMealPlan(queryParams.value);
-        mealPlanList.value = res.rows;
-        total.value = res.total;
-        loading.value = false;
-    }
+const {queryParams, form, rules} = toRefs(data);
 
-    // 字典label工具
-    function getDictLabel(dictList: any[], value: string) {
-        if (!dictList || !Array.isArray(dictList)) return value || '--';
-        const found = dictList.find(item => item.value === value);
-        return found ? found.label : value || '--';
-    }
+/** 查询院内膳食主列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listMealPlan(queryParams.value);
+  mealPlanList.value = res.rows;
+  setHospitalList(mealPlanList.value);
+  total.value = res.total;
+  loading.value = false;
+};
 
-    /** 取消按钮 */
-    const cancel = () => {
-        reset();
-        dialog.visible = false;
-    }
+// 字典label工具
+function getDictLabel(dictList: any[], value: string) {
+  if (!dictList || !Array.isArray(dictList)) return value || '--';
+  const found = dictList.find((item) => item.value === value);
+  return found ? found.label : value || '--';
+}
 
-    /** 表单重置 */
-    const reset = () => {
-        form.value = { ...initFormData };
-        mealPlanFormRef.value ?.resetFields();
-        queryParams.value.dateRange = undefined;
-        queryParams.value.type = undefined;
-        queryParams.value.searchValue = undefined;
-        queryParams.value.pageNum = 1;
-        queryParams.value.pageSize = 10;
-    }
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
 
-    /** 搜索按钮操作 */
-    const handleQuery = () => {
-        queryParams.value.pageNum = 1;
-        getList();
-    }
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  mealPlanFormRef.value?.resetFields();
+  queryParams.value.dateRange = undefined;
+  queryParams.value.type = undefined;
+  queryParams.value.searchValue = undefined;
+  queryParams.value.pageNum = 1;
+  queryParams.value.pageSize = 10;
+};
 
-    /** 重置按钮操作 */
-    const resetQuery = () => {
-        queryFormRef.value ?.resetFields();
-         queryParams.value.dateRange = undefined;
-        queryParams.value.type = undefined;
-        queryParams.value.searchValue = undefined;
-        queryParams.value.pageNum = 1;
-        queryParams.value.pageSize = 10;
-        handleQuery();
-    }
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
 
-    /** 多选框选中数据 */
-    const handleSelectionChange = (selection: MealPlanVO[]) => {
-        ids.value = selection.map(item => item.id);
-        single.value = selection.length != 1;
-        multiple.value = !selection.length;
-    }
+const handleView = async (row?: MealPlanVO) => {
+  emit('change', 'hospitalIndex', row);
+};
 
-    /** 新增按钮操作 */
-    const handleAdd = () => {
-        reset();
-        dialog.visible = true;
-        dialog.title = "添加院内膳食";
-    }
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  queryParams.value.dateRange = undefined;
+  queryParams.value.type = undefined;
+  queryParams.value.searchValue = undefined;
+  queryParams.value.pageNum = 1;
+  queryParams.value.pageSize = 10;
+  handleQuery();
+};
 
-    /** 修改按钮操作 */
-    const handleUpdate = async (row ? : MealPlanVO) => {
-        reset();
-        const _id = row ?.id || ids.value[0]
-        const res = await getMealPlan(_id);
-        Object.assign(form.value, res.data);
-        dialog.visible = true;
-        dialog.title = "修改院内膳食";
-    }
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: MealPlanVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
 
-    /** 提交按钮 */
-    const submitForm = (mealPlanForm) => {
-        form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
-        form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
-        form.value.mealRecipeList = mealPlanForm.mealRecipeList;
-        addMealPlan(form.value).finally(() => buttonLoading.value = false);
-        getList();
-        mealPlanFormRef.value ?.validate(async (valid: boolean) => {
-            if (true) {
-                form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
-                form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
-                form.value.mealRecipeList = mealPlanForm.mealRecipeList;
-                buttonLoading.value = true;
-                if (form.value.id) {
-                    await updateMealPlan(form.value).finally(() => buttonLoading.value = false);
-                } else {
-                    await addMealPlan(form.value).finally(() => buttonLoading.value = false);
-                }
-                proxy ?.$modal.msgSuccess("操作成功");
-                dialog.visible = false;
-                await getList();
-            }
-        });
-    }
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加院内膳食';
+};
 
-    defineExpose({ submitForm });
+//
+const handleDetail = (row?: MealPlanVO) => {
+  console.log('row', JSON.stringify(row));
+};
 
-    /** 删除按钮操作 */
-    const handleDelete = async (row ? : MealPlanVO) => {
-        const _ids = row ?.id || ids.value;
-        await proxy ?.$modal.confirm('是否确认删除院内膳食主编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
-        await delMealPlan(_ids);
-        proxy ?.$modal.msgSuccess("删除成功");
-        await getList();
+/** 修改按钮操作 */
+const handleUpdate = async (row?: MealPlanVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getMealPlan(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改院内膳食';
+};
+
+/** 提交按钮 */
+const submitForm = (mealPlanForm) => {
+  form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
+  form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
+  form.value.totalPrice = mealPlanForm.totalPrice;
+  form.value.mealRecipeList = mealPlanForm.mealRecipeList;
+  addMealPlan(form.value).finally(() => (buttonLoading.value = false));
+  getList();
+  mealPlanFormRef.value?.validate(async (valid: boolean) => {
+    if (true) {
+      form.value.recommendStartDate = mealPlanForm.mealTimeRange[0];
+      form.value.recommendEndDate = mealPlanForm.mealTimeRange[1];
+      form.value.mealRecipeList = mealPlanForm.mealRecipeList;
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateMealPlan(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addMealPlan(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
     }
+  });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (id?: number) => {
+  const _ids = id;
+  await proxy?.$modal.confirm('是否确认作废院内膳食主编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delMealPlan(_ids);
+  proxy?.$modal.msgSuccess('作废成功');
+  emit('back', 'hospitalIndex');
+
+  await getList();
+};
+
+defineExpose({submitForm, handleDelete});
 
-    onMounted(() => {
-        getList();
-    });
-</script>
+onMounted(() => {
+  getList();
+});
+</script>

+ 273 - 190
src/views/patients/dietTherapy/index.vue

@@ -1,212 +1,295 @@
 <template>
-    <div class="container">
-        <!-- 首页的tab列表区域 -->
-        <div v-show="type === PageType.LIST">
-            <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
-                <el-tab-pane label="院内膳食" name="hospital">
-                    <HospitalIndex ref="hospitalIndexRef" :activeName="activeName" @addHospital="handleHospital" :patientInfo="props.patientInfo" />
-                </el-tab-pane>
-                <!-- <el-tab-pane label="平衡膳食" name="balance">
+  <div class="container">
+    <!-- 首页的tab列表区域 -->
+    <div v-show="type === PageType.LIST">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+        <el-tab-pane label="院内膳食" name="hospital">
+          <HospitalIndex
+            ref="hospitalIndexRef"
+            :activeName="activeName"
+            @addHospital="handleHospital"
+            :patientInfo="props.patientInfo"
+            @change="handleView"
+            @back="handleDetailBack"
+          />
+        </el-tab-pane>
+        <!-- <el-tab-pane label="平衡膳食" name="balance">
                     <div class="btn_content" @click="handleBalance()">
                         <el-button type="primary">新增{{ tabLabelMap[activeName] }}</el-button>
                     </div>
                 </el-tab-pane> -->
-                <el-tab-pane label="日常膳食" name="daily">
-                    <DailyIndex ref="dailyIndexRef" :activeName="activeName" @addDaily="handleDaily" :patientInfo="props.patientInfo" />
-                </el-tab-pane>
-                <el-tab-pane label="智能推荐" name="smart">
-                    <!-- <div class="btn_content" @click="handleSmartRecommend()">
+        <el-tab-pane label="日常膳食" name="daily">
+          <DailyIndex
+            ref="dailyIndexRef"
+            :activeName="activeName"
+            @addDaily="handleDaily"
+            :patientInfo="props.patientInfo"
+            @change="handleView"
+            @back="handleDetailBack"
+          />
+        </el-tab-pane>
+        <el-tab-pane label="智能推荐" name="smart">
+          <!-- <div class="btn_content" @click="handleSmartRecommend()">
                         <el-button type="primary">新增{{ tabLabelMap[activeName] }}</el-button>
                     </div> -->
-                </el-tab-pane>
-            </el-tabs>
-        </div>
-
-        <!-- 院内膳食 -->
-        <div v-show="type === PageType.HOSPITAL">
-            <AddHospital v-if="type === PageType.HOSPITAL" @goBack="isType" @submitHospital="handleHospitalSubmit" :patientInfo="props.patientInfo"/>
-        </div>
-
-        <!-- 平衡膳食 -->
-        <div v-show="type === PageType.BALANCE">
-            <AddBalance @goBack="isType" />
-        </div>
-
-        <!-- 日常膳食 -->
-        <div v-show="type === PageType.DAILY">
-            <AddDaily v-if="type === PageType.DAILY" @goBack="isType" @submitDaily="handleDailySubmit" :patientInfo="props.patientInfo"/>
-        </div>
-
-        <!-- 智能推荐 -->
-        <div v-show="type === PageType.SMART">
-            <AddSmartRec @goBack="isType" />
-        </div>
+        </el-tab-pane>
+      </el-tabs>
     </div>
+
+    <!-- 院内膳食 -->
+    <div v-show="type === PageType.HOSPITAL">
+      <AddHospital
+        v-if="type === PageType.HOSPITAL"
+        @goBack="isType"
+        @submitHospital="handleHospitalSubmit"
+        :patientInfo="props.patientInfo"
+        :rowData="rowData"
+      />
+    </div>
+
+    <!-- 平衡膳食 -->
+    <div v-show="type === PageType.BALANCE">
+      <AddBalance @goBack="isType" />
+    </div>
+
+    <!-- 日常膳食 -->
+    <div v-show="type === PageType.DAILY">
+      <AddDaily
+        v-if="type === PageType.DAILY"
+        @goBack="isType"
+        @submitDaily="handleDailySubmit"
+        :patientInfo="props.patientInfo"
+        :rowData="rowData"
+      />
+    </div>
+
+    <!-- 智能推荐 -->
+    <div v-show="type === PageType.SMART">
+      <AddSmartRec @goBack="isType" />
+    </div>
+    <!-- 院内膳食详情 -->
+    <div v-show="type === PageType.HOSPITAL_DETAIL">
+      <HospitalDetail @change="handleDetailBack" :infoId="infoId" @del="deleteMealPlan" @add="addMealPlan" />
+    </div>
+
+    <!--日常膳食详情 -->
+    <div v-show="type === PageType.DAILY_DETAIL">
+      <DailyDetail @change="handleDetailBack" :infoId="infoId" @del="deleteMealPlan" @add="addMealPlan" />
+    </div>
+  </div>
 </template>
 <script lang="ts" setup>
-    import { ref } from 'vue';
-    import type { TabsPaneContext } from 'element-plus';
-    import AddHospital from './addHospital.vue';
-    import AddBalance from './addBalance.vue';
-    import AddDaily from './addDaily.vue';
-    import AddSmartRec from './addSmartRec.vue';
-    import HospitalIndex from './hospitalIndex.vue';
-    import DailyIndex from './dailyIndex.vue';
-    const emit = defineEmits(['change'])
-    const hospitalIndexRef = ref();
-    const dailyIndexRef = ref();
-
-
-    // 声明接收的 props
-    const props = defineProps({
-        patientInfo: {
-            type: Object,
-            required: true,
-            default: () => ({
-                id: '',
-                name: '',
-                age: '',
-                gender: ''
-            })
-        }
-    });
-    // 使用枚举定义页面类型
-    enum PageType {
-        LIST = 'list',
-            HOSPITAL = 'addForm',
-            BALANCE = 'addBalance',
-            DAILY = 'addDaily',
-            SMART = 'addSmart'
+import {ref} from 'vue';
+import type {TabsPaneContext} from 'element-plus';
+import AddHospital from './addHospital.vue';
+import AddBalance from './addBalance.vue';
+import AddDaily from './addDaily.vue';
+import AddSmartRec from './addSmartRec.vue';
+import HospitalIndex from './hospitalIndex.vue';
+import DailyIndex from './dailyIndex.vue';
+import DailyDetail from './dailyDetail.vue';
+import HospitalDetail from './hospitalDetail.vue';
+import {MealPlanVO} from '@/api/patients/hospitalMealPlan/types';
+// import { addMealPlan } from '@/api/patients/hospitalMealPlan';
+
+const emit = defineEmits(['change']);
+const hospitalIndexRef = ref();
+const dailyIndexRef = ref();
+const infoId = ref();
+const rowData = ref();
+
+// 声明接收的 props
+const props = defineProps({
+  patientInfo: {
+    type: Object,
+    required: true,
+    default: () => ({
+      id: '',
+      name: '',
+      age: '',
+      gender: ''
+    })
+  }
+});
+// 使用枚举定义页面类型
+enum PageType {
+  LIST = 'list',
+  HOSPITAL = 'addForm',
+  BALANCE = 'addBalance',
+  DAILY = 'addDaily',
+  SMART = 'addSmart',
+  DAILY_DETAIL = 'dailyDetail',
+  HOSPITAL_DETAIL = 'hospitalDetail'
+}
+
+// 当前页面类型
+const type = ref<PageType>(PageType.LIST);
+const activeName = ref('hospital');
+
+// tab标签映射
+const tabLabelMap: Record<string, string> = {
+  hospital: '院内膳食',
+  balance: '平衡膳食',
+  daily: '日常膳食',
+  smart: '智能推荐'
+};
+const handleHospitalSubmit = (mealPlanForm) => {
+  hospitalIndexRef.value?.submitForm(mealPlanForm);
+};
+const handleDailySubmit = (mealPlanForm) => {
+  dailyIndexRef.value?.submitForm(mealPlanForm);
+};
+
+const handleView = async (detailType?: string, row?: MealPlanVO) => {
+  if (row && row.id) {
+    infoId.value = row.id;
+    if (detailType === 'hospitalIndex') {
+      type.value = PageType.HOSPITAL_DETAIL;
     }
+    if (detailType === 'dailyIndex') {
+      type.value = PageType.DAILY_DETAIL;
+    }
+  }
+};
 
-    // 当前页面类型
-    const type = ref < PageType > (PageType.LIST);
-    const activeName = ref('hospital');
-
-    // tab标签映射
-    const tabLabelMap: Record < string, string > = {
-        hospital: '院内膳食',
-        balance: '平衡膳食',
-        daily: '日常膳食',
-        smart: '智能推荐'
-    };
-    const handleHospitalSubmit = (mealPlanForm) => {
-        hospitalIndexRef.value ?.submitForm(mealPlanForm);
-    };
-    const handleDailySubmit = (mealPlanForm) => {
-        console.log(12);
-        
-        dailyIndexRef.value ?.submitForm(mealPlanForm);
-    };
-
-    // 点击标签
-    const handleClick = (tab: TabsPaneContext) => {
-        console.log(tab.paneName);
-    };
-
-    // 页面跳转处理
-    const handlePageChange = (pageType: PageType) => {
-        type.value = pageType;
-    };
-
-    // 各个按钮的点击处理
-    const handleHospital = () => {
-        handlePageChange(PageType.HOSPITAL);
-    };
-    // 平衡膳食
-    const handleBalance = () => {
-        handlePageChange(PageType.BALANCE);
-    };
-
-    // 日常膳食
-    const handleDaily = () => {
-        handlePageChange(PageType.DAILY);
-    };
-
-    // 智能推荐
-    const handleSmartRecommend = () => {
-        handlePageChange(PageType.SMART);
-    };
-
-    // 返回列表页
-    const isType = () => {
-        handlePageChange(PageType.LIST);
-    };
+const addMealPlan = async (detailType?: string, row?: MealPlanVO) => {
+  if (row) {
+    rowData.value = row;
+    if (detailType === 'hospitalDetail') {
+      type.value = PageType.HOSPITAL;
+    }
+    if (detailType === 'dailyDetail') {
+      type.value = PageType.DAILY;
+    }
+  }
+};
+
+// 处理详情页返回
+const handleDetailBack = (pageType: string) => {
+  if (pageType === 'hospitalIndex') {
+    type.value = PageType.LIST;
+  }
+  if (pageType === 'dailyIndex') {
+    type.value = PageType.LIST;
+  }
+};
+
+const deleteMealPlan = (pageType: string, planId: number) => {
+  if (pageType === 'hospitalDetail') {
+    hospitalIndexRef.value?.handleDelete([planId]);
+  }
+  if (pageType === 'dailyDetail') {
+    dailyIndexRef.value?.handleDelete(planId);
+  }
+};
+// 点击标签
+const handleClick = (tab: TabsPaneContext) => {
+  console.log(tab.paneName);
+};
+
+// 页面跳转处理
+const handlePageChange = (pageType: PageType) => {
+  type.value = pageType;
+};
+
+// 各个按钮的点击处理
+const handleHospital = () => {
+  handlePageChange(PageType.HOSPITAL);
+};
+// 平衡膳食
+const handleBalance = () => {
+  handlePageChange(PageType.BALANCE);
+};
+
+// 日常膳食
+const handleDaily = () => {
+  handlePageChange(PageType.DAILY);
+};
+
+// 智能推荐
+const handleSmartRecommend = () => {
+  handlePageChange(PageType.SMART);
+};
+
+// 返回列表页
+const isType = () => {
+  handlePageChange(PageType.LIST);
+};
 </script>
 <style scoped>
-    .demo-tabs {
-        width: 90vw;
-        background: #f7f9fb;
-        border-radius: 12px 12px 0 0;
-        padding: 16px 0 0 16px;
-        min-height: 800px;
-    }
+.demo-tabs {
+  width: 90vw;
+  background: #f7f9fb;
+  border-radius: 12px 12px 0 0;
+  padding: 16px 0 0 16px;
+  min-height: 800px;
+}
 
-    .btn_content {
-        margin-top: 20px;
-    }
+.btn_content {
+  margin-top: 20px;
+}
 
-    :deep(.el-tabs__header) {
-        border-bottom: none !important;
-        margin-bottom: 0 !important;
-        background: transparent;
-    }
+:deep(.el-tabs__header) {
+  border-bottom: none !important;
+  margin-bottom: 0 !important;
+  background: transparent;
+}
 
-    :deep(.el-tabs__nav) {
-        background: transparent;
-        border: none;
-        align-items: center;
-        height: 72px;
-        display: flex;
-    }
+:deep(.el-tabs__nav) {
+  background: transparent;
+  border: none;
+  align-items: center;
+  height: 72px;
+  display: flex;
+}
 
-    :deep(.el-tabs__content) {
-        background: #fff !important;
-        height: 600px;
-    }
+:deep(.el-tabs__content) {
+  background: #fff !important;
+  height: 600px;
+}
 
-    :deep(.el-tabs__item) {
-        background: transparent !important;
-        position: relative;
-        z-index: 1;
-        font-size: 16px;
-        color: #333;
-        padding: 0 48px !important;
-        height: 64px;
-        line-height: 64px;
-        display: flex;
-        align-items: center;
-        transition: color 0.2s;
-        border: none !important;
-    }
+:deep(.el-tabs__item) {
+  background: transparent !important;
+  position: relative;
+  z-index: 1;
+  font-size: 16px;
+  color: #333;
+  padding: 0 48px !important;
+  height: 64px;
+  line-height: 64px;
+  display: flex;
+  align-items: center;
+  transition: color 0.2s;
+  border: none !important;
+}
 
-    :deep(.el-tabs__item.is-active) {
-        color: #409eff !important;
-        z-index: 2;
-    }
+:deep(.el-tabs__item.is-active) {
+  color: #409eff !important;
+  z-index: 2;
+}
 
-    :deep(.el-tabs__item.is-active)::before {
-        content: '';
-        position: absolute;
-        left: 0;
-        right: 0;
-        top: 0;
-        bottom: 0;
-        background: #fff;
-        border-radius: 12px 12px 0 0;
-        box-shadow: 0 2px 8px rgba(64, 158, 255, 0.08);
-        z-index: -1;
-    }
+:deep(.el-tabs__item.is-active)::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  background: #fff;
+  border-radius: 12px 12px 0 0;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.08);
+  z-index: -1;
+}
 
-    .diet-content-area {
-        background: #fff;
-        border-radius: 0 0 16px 16px;
-        min-height: 300px;
-        /* 让内容区和Tabs无缝衔接 */
-        margin-top: -24px;
-        padding: 32px 40px;
-        box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
-        position: relative;
-        z-index: 1;
-    }
-</style>
+.diet-content-area {
+  background: #fff;
+  border-radius: 0 0 16px 16px;
+  min-height: 300px;
+  /* 让内容区和Tabs无缝衔接 */
+  margin-top: -24px;
+  padding: 32px 40px;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
+  position: relative;
+  z-index: 1;
+}
+</style>

+ 48 - 16
src/views/patients/medicalRecord/detailDialog.vue

@@ -3,24 +3,56 @@
         <div class="detail-dialog-body">
             <el-row :gutter="0">
                 <el-col :span="12">
-                    <div class="detail-row"><span class="label required">看诊类型:</span><span class="value">{{ detailData.type === '0' ? '门诊' : '住院' }}</span></div>
-                    <div class="detail-row"><span class="label">诊疗卡号:</span><span class="value">{{ detailData.treatNum || '--' }}</span></div>
-                    <div class="detail-row"><span class="label required">科室:</span><span class="value">{{ detailData.deptName || '--' }}</span></div>
-                    <div class="detail-row"><span class="label required">姓名:</span><span class="value">{{ detailData.treatName || '--' }}</span></div>
-                    <div class="detail-row"><span class="label required">身份证:</span><span class="value">{{ detailData.idCard || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">年龄:</span><span class="value">{{ detailData.age || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">身高:</span><span class="value">{{ detailData.height ? detailData.height + 'cm' : '--' }}</span></div>
-                    <div class="detail-row"><span class="label">BMI:</span><span class="value">{{ detailData.bmi || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">过敏食物:</span><span class="value">{{ detailData.allergyFoot || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">过敏药物:</span><span class="value">{{ detailData.allergyDrug || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">体力活动:</span><span class="value">{{ getDictLabel(physicalActivityDict, detailData.activity) || '--' }}</span></div>
+                    <div class="detail-row">
+                        <span class="label required">看诊类型:</span><span class="value">{{ detailData.type === '0' ? '门诊' : '住院' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">诊疗卡号:</span><span class="value">{{ detailData.treatNum || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label required">科室:</span><span class="value">{{ detailData.deptName || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label required">姓名:</span><span class="value">{{ detailData.treatName || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label required">身份证:</span><span class="value">{{ detailData.idCard || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">年龄:</span><span class="value">{{ detailData.age || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">身高:</span><span class="value">{{ detailData.height ? detailData.height + 'cm' : '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">BMI:</span><span class="value">{{ detailData.bmi || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">过敏食物:</span><span class="value">{{ detailData.allergyFoot || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">过敏药物:</span><span class="value">{{ detailData.allergyDrug || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">体力活动:</span><span class="value">{{ getDictLabel(physicalActivityDict, detailData.activity) || '--' }}</span>
+                    </div>
                 </el-col>
                 <el-col :span="12">
-                    <div class="detail-row"><span class="label">门诊号:</span><span class="value">{{ detailData.outpatientNo || '--' }}</span></div>
-                    <div class="detail-row"><span class="label required">性别:</span><span class="value">{{ detailData.sex === '0' ? '男' : detailData.sex === '1' ? '女' : '--' }}</span></div>
-                    <div class="detail-row"><span class="label">出生日期:</span><span class="value">{{ detailData.birthday || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">联系电话:</span><span class="value">{{ detailData.phoneNum || '--' }}</span></div>
-                    <div class="detail-row"><span class="label">体重:</span><span class="value">{{ detailData.weight ? detailData.weight + 'kg' : '--' }}</span></div>
+                    <div class="detail-row">
+                        <span class="label">门诊号:</span><span class="value">{{ detailData.outpatientNo || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label required">性别:</span><span class="value">{{ detailData.sex === '0' ? '男' : detailData.sex === '1' ? '女' : '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">出生日期:</span><span class="value">{{ detailData.birthday || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">联系电话:</span><span class="value">{{ detailData.phoneNum || '--' }}</span>
+                    </div>
+                    <div class="detail-row">
+                        <span class="label">体重:</span><span class="value">{{ detailData.weight ? detailData.weight + 'kg' : '--' }}</span>
+                    </div>
                 </el-col>
             </el-row>
         </div>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 519 - 474
src/views/patients/medicalRecord/index.vue


+ 107 - 33
src/views/patients/medicalRecord/levelMenu.vue

@@ -2,41 +2,71 @@
     <div class="patient-info">
         <span>营养病例</span>
     </div>
-    <div class="custom-tab-bar">
-        <el-menu :default-active="activeMenu" class="medical-menu" @select="handleSelect" mode="horizontal">
-            <el-menu-item index="medicalRecord">
-                <span>病史记录</span>
-            </el-menu-item>
-            <el-menu-item index="visitRecord">
-                <span>检查指标</span>
-            </el-menu-item>
-            <el-menu-item index="nutritionScreening">
-                <span>营养筛查</span>
-            </el-menu-item>
-            <el-menu-item index="nutritionEvaluation">
-                <span>营养评估</span>
-            </el-menu-item>
-            <el-menu-item index="nutritionDiagnosis">
-                <span>营养诊断</span>
-            </el-menu-item>
-            <el-menu-item index="nutritionPlan">
-                <span>营养干预</span>
-            </el-menu-item>
-            <el-menu-item index="nutritionMonitor">
-                <span>营养膳食</span>
-            </el-menu-item>
-            <el-menu-item index="checkRoom" v-show="props.patientInfo.type=='1'">
-                <span>查房记录</span>
-            </el-menu-item>
-        </el-menu>
-    </div>
+    <el-row :gutter="20">
+        <el-col :span="21">
+            <div class="custom-tab-bar">
+                <el-menu :default-active="activeMenu" class="medical-menu" @select="handleSelect" mode="horizontal">
+                    <el-menu-item index="medicalRecord">
+                        <span>病史记录</span>
+                    </el-menu-item>
+                    <el-menu-item index="visitRecord">
+                        <span>检查指标</span>
+                    </el-menu-item>
+                    <el-menu-item index="nutritionScreening">
+                        <span>营养筛查</span>
+                    </el-menu-item>
+                    <el-menu-item index="nutritionEvaluation">
+                        <span>营养评估</span>
+                    </el-menu-item>
+                    <el-menu-item index="nutritionDiagnosis">
+                        <span>营养诊断</span>
+                    </el-menu-item>
+                    <el-menu-item index="nutritionPlan">
+                        <span>营养干预</span>
+                    </el-menu-item>
+                    <el-menu-item index="nutritionMonitor">
+                        <span>营养膳食</span>
+                    </el-menu-item>
+                    <el-menu-item index="checkRoom" v-show="props.patientInfo.type=='1'">
+                        <span>查房记录</span>
+                    </el-menu-item>
+                </el-menu>
+            </div>
 
-    <div>
-        <!-- <keep-alive>
+            <div>
+                <!-- <keep-alive>
         </keep-alive> -->
-        <component :is="currentComponent" v-if="currentComponent" :patient-info="props.patientInfo" />
+                <component :is="currentComponent" v-if="currentComponent" :patient-info="props.patientInfo" />
+
+            </div>
+        </el-col>
+        <el-col :span="3">
+            <div class="patient-right">
+                <span style="margin-left: 10px; display: block;">病例历史</span>
+                <span style="border-bottom: 2px solid #ccc;margin-top: 10px;width: 100%;display: block;"></span>
+            </div>
+            <div v-for="item in useStore.diagnosisList" :key="item.id" class="diagnosis-item" @click="handleDiagnosisClick(item)">
+                <el-row>
+                    <el-col :span="3">
+                        <div class="item-type">{{getDictLabel(treatment_user_type, item.type)  }}</div>
+                    </el-col>
+                    <el-col :span="21">
+                        <el-row style="margin-top: 15px;">
+                            <el-col :span="24">
+                                <span>{{ item.createTime }}</span>
+                            </el-col>
+                        </el-row>
+                        <el-row>
+                            <el-col :span="24">
+                                <span>门诊号:{{ item.outpatientNo }}</span>
+                            </el-col>
+                        </el-row>
+                    </el-col>
+                </el-row>
+            </div>
+        </el-col>
+    </el-row>
 
-    </div>
 
 
 </template>
@@ -51,7 +81,8 @@
     const NutritionScreening = defineAsyncComponent(() => import('@/views/patients/medicalRecord/levelMenu/nutritionScreening/index.vue'));
     const NutritionEvaluation = defineAsyncComponent(() => import('@/views/patients/medicalRecord/levelMenu/nutritionEvaluation/index.vue'));
     const activeMenu = ref('medicalRecord');
-
+    import { useNutritionDiagnosisStore } from '@/store/modules/diagnosis';
+    const useStore = useNutritionDiagnosisStore();
     const componentMap = {
         medicalRecord: MedicalRecord,
         visitRecord: VisitRecord,
@@ -62,6 +93,8 @@
     };
 
     const currentComponent = ref(componentMap['medicalRecord']); // 默认显示
+    const { proxy } = getCurrentInstance() as any;
+    const { treatment_user_type } = toRefs < any > (proxy ?.useDict('treatment_user_type'));
 
     // 声明接收的 props
     const props = defineProps({
@@ -77,10 +110,19 @@
         }
     });
 
+    const handleDiagnosisClick = (item) => {
+        useStore.setDiagnosisInfo(item)
+    }
     const handleSelect = (key: string) => {
         activeMenu.value = key;
         currentComponent.value = componentMap[key] || null;
     };
+
+    function getDictLabel(dictList: any[], value: string) {
+        if (!dictList || !Array.isArray(dictList)) return value || '--';
+        const found = dictList.find(item => item.value === value);
+        return found ? found.label : value || '--';
+    }
 </script>
 
 <style lang="scss" scoped>
@@ -216,4 +258,36 @@
         align-items: center;
         justify-content: center;
     }
+
+    .diagnosis-item {
+        margin-top: 10px;
+        display: inline-block;
+        color: #3f6cb5;
+        background: #f4f7ff;
+        border: 1px solid #76b4f4;
+        border-radius: 8px;
+        text-align: center;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+        position: relative;
+        height: 80px;
+        width: 96%;
+        align-items: center;
+        /* 垂直居中 */
+        justify-content: center;
+        /* 水平居中 */
+        min-height: 67px;
+        line-height: 30px;
+    }
+
+    .item-type {
+        border-right: 1px solid#76b4f4;
+        height: 80px;
+        display: flex;
+        align-items: center;
+        /* 垂直居中 */
+        justify-content: center;
+        /* 水平居中 */
+        background: #3f6cb5;
+        color: #fff;
+    }
 </style>

+ 341 - 29
src/views/patients/nutriDiagnosis/index.vue

@@ -70,34 +70,84 @@
         </div>
 
         <div v-show="type === 'addForm'">
-            <el-form ref="diagnosisFormRef" :model="form" :rules="rules" label-width="120px">
-                <el-form-item label="营养诊断:" prop="diagnosisLableId">
-                    <el-select v-model="form.labelList" multiple placeholder="请选择" style="width: 100%;" :disabled="true" @click="labelDialogVisible = true" class="custom-label-select">
-                        <el-option v-for="item in labelOptions" :key="item.labelId" :label="item.labelName" :value="item.labelId">
-                            <el-tag type="info" size="small">{{ item.labelName }}</el-tag>
-                        </el-option>
-                    </el-select>
-                </el-form-item>
-                <el-form-item label="营养诊断依据:" prop="diagnosisBasisId">
-                    <el-input v-model="form.diagnosisBasisId" placeholder="请输入营养筛查/评估结果" clearable />
-                </el-form-item>
-                <el-form-item label="营养会诊结论:">
-                    <div class="consultation-toolbar">
-                        <el-button type="danger" plain @click="clearContent">清空记录</el-button>
-                        <el-button @click="showTemplateDialog = true">导入模板</el-button>
+            <el-row :gutter="20">
+                <el-col :span="20">
+                    <el-form ref="diagnosisFormRef" :model="form" :rules="rules" label-width="120px">
+                        <el-form-item label="营养诊断:" prop="diagnosisLableId">
+                            <el-select v-model="form.labelList" multiple placeholder="请选择" style="width: 100%;" :disabled="true" @click="labelDialogVisible = true" class="custom-label-select">
+                                <el-option v-for="item in labelOptions" :key="item.labelId" :label="item.labelName" :value="item.labelId">
+                                    <el-tag type="info" size="small">{{ item.labelName }}</el-tag>
+                                </el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="营养诊断依据:" prop="diagnosisBasisId">
+                            <div class="diagnosis-basis-list">
+                                <div v-if="diagnosisBasisList.length > 0">
+                                    <div v-for="(item, index) in diagnosisBasisList" :key="item.id" class="basis-item">
+                                        <el-input v-model="item.content" type="textarea" :rows="item.content.split('\n').length + 1" readonly resize="none" />
+                                        <el-button type="danger" @click="removeBasisItem(index)">删除</el-button>
+                                    </div>
+                                </div>
+                                <div v-else>
+                                    <div class="basis-item">
+                                        <el-input placeholder="请选择营养筛查/评估结果" readonly resize="none" />
+                                    </div>
+                                </div>
+                            </div>
+                        </el-form-item>
+                        <el-form-item label="营养会诊结论:">
+                            <div class="consultation-toolbar">
+                                <el-button type="danger" plain @click="clearContent">清空记录</el-button>
+                                <el-button @click="showTemplateDialog = true">导入模板</el-button>
+                            </div>
+                        </el-form-item>
+                        <el-form-item>
+                            <Editor v-model="form.consultantResult" placeholder="请输入内容..." style="min-height: 200px; width: 100%;" />
+                        </el-form-item>
+                        <el-form-item label="营养医嘱:" prop="medicalOrder">
+                            <el-input v-model="form.medicalOrder" type="textarea" :rows="5" placeholder="请输入" clearable />
+                        </el-form-item>
+                    </el-form>
+                </el-col>
+                <!-- 营养筛查和评估的选择项 -->
+                <el-col :span="4">
+                    <div class="screen-eval-card">
+                        <div>
+                            <div class="card-title">营养筛查/评估</div>
+                            <span style="font-size: 12px;">(点击添加下列筛查结果增加诊断依据)</span>
+                            <div style="border-bottom: 2px solid #ccc;margin-top: 10px;width: 100%;"></div>
+                           <div>
+                             <span style="margin-top: 15px;">时间:</span>
+                                <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" style="width: 70%;margin-top: 10px;"></el-date-picker>
+                           </div>
+                        </div>
+                        <div v-for="item in screenEvalList" :key="item.id" class="screen-eval-item">
+                            <div class="eval-content">
+                                <div v-if="item.type === 'evaluation'">
+                                    <div>评估时间:{{ item.date }}</div>
+                                    <div>营养评估类型:{{ item.evalType }}</div>
+                                    <div v-for="(v, i) in item.energyArr" :key="i">{{ v }}</div>
+                                    <div>{{ item.suggestion }}</div>
+                                </div>
+                                <div v-else>
+                                    <div>筛查时间:{{ item.date }}</div>
+                                    <div>营养筛查方法:{{ item.method }}</div>
+                                    <div>营养风险总评分:{{ item.score }}</div>
+                                    <div>筛查结论:{{ item.conclusion }}</div>
+                                </div>
+                            </div>
+                            <div class="eval-button">
+                                <el-button type="success" size="small" @click="addToDiagnosisBasis(item)">
+                                    【添加至诊断依据】
+                                </el-button>
+                            </div>
+                        </div>
                     </div>
-                </el-form-item>
-                <el-form-item>
-                    <Editor v-model="form.consultantResult" placeholder="请输入内容..." style="min-height: 200px; width: 100%;" />
-                </el-form-item>
-                <el-form-item label="营养医嘱:" prop="medicalOrder">
-                    <el-input v-model="form.medicalOrder" placeholder="请输入" clearable />
-                </el-form-item>
-
-            </el-form>
+                </el-col>
+            </el-row>
             <LabelDialog v-model="labelDialogVisible" :initial-selected-labels="labelOptions || []" @confirm="onLabelConfirm" />
             <ConsultantTemplateDialog v-model:visible="showTemplateDialog" @select="onTemplateSelect" />
-            <div class="dialog-footer" style="text-align: center; margin-top: 100px">
+            <div class="footter-low" style="text-align: center; margin-top: 100px">
                 <el-button @click="handleCancel">取 消</el-button>
                 <el-button :loading="buttonLoading" type="primary" @click="submitForm">提 交</el-button>
             </div>
@@ -113,7 +163,10 @@
     import { getTreatmentUser as fetchTreatmentUser } from '@/api/workbench/treatmentUser';
     import LabelDialog from '@/views/warehouse/nutriProduct/labelDialog.vue';
     import { getDiseaseLabel } from '@/api/system/diseaseLabel'; // 新增: 导入获取标签详情API
-    import { log } from 'console';
+    import { listEvaluation } from '@/api/patients/evaluation';
+    import { EvaluationVO, EvaluationQuery, EvaluationForm } from '@/api/patients/evaluation/types';
+    import { listScreening } from '@/api/patients/screening';
+    import { ScreeningVO, ScreeningQuery, ScreeningForm } from '@/api/patients/screening/types';
     import DetailDialog from './detailDialog.vue';
     import { watch } from 'vue';
     const emit = defineEmits(['change'])
@@ -122,7 +175,8 @@
     const ConsultantTemplateDialog = defineAsyncComponent(() => import('./consultantTemplateDialog.vue'));
     const { treatment_user_type } = toRefs < any > (proxy ?.useDict('treatment_user_type'));
 
-
+    const diagnosisBasisList = ref < DiagnosisBasisItem[] > ([]);
+    const newBasisItem = ref('');
     const diagnosisList = ref < DiagnosisVO[] > ([]);
     const buttonLoading = ref(false);
     const loading = ref(true);
@@ -140,12 +194,17 @@
     const queryFormRef = ref < ElFormInstance > ();
     const diagnosisFormRef = ref < ElFormInstance > ();
     const showTemplateDialog = ref(false);
-
+    const diagnosisBasisStr = ref('');
     const dialog = reactive < DialogOption > ({
         visible: false,
         title: ''
     });
 
+    interface DiagnosisBasisItem {
+        id: string; // 用于防重
+        content: string; // 用于显示
+    }
+
     // 声明接收的 props
     const props = defineProps({
         patientInfo: {
@@ -205,6 +264,77 @@
         }, { immediate: true }
     );
 
+    // 添加筛查/评估结果
+    const addToDiagnosisBasis = (item: any) => {
+        // 1. 检查是否已添加(基于ID)
+        const isAlreadyAdded = diagnosisBasisList.value.some(
+            entry => entry.id === item.id
+        );
+
+        if (isAlreadyAdded) {
+            ElMessage.warning('该条目已添加至诊断依据!');
+            return;
+        }
+
+        // 2. 拼接 diagnosisBasisId(分号分隔)
+        if (item.id) {
+            const currentIds = form.value.diagnosisBasisId ?
+                form.value.diagnosisBasisId.split(';').map(id => id.trim()).filter(Boolean) : [];
+
+            if (!currentIds.includes(item.id)) {
+                form.value.diagnosisBasisId = currentIds.length > 0 ?
+                    `${form.value.diagnosisBasisId};${item.id}` :
+                    item.id;
+            }
+        }
+
+        // 3. 生成显示内容(不包含ID)
+        let content = '';
+        if (item.type === 'evaluation') {
+            content = `
+评估时间:${item.date}
+营养评估类型:${item.evalType}
+${item.energyArr?.join('\n') || ''}
+${item.suggestion}
+        `.trim();
+        } else {
+            content = `
+筛查时间:${item.date}
+营养筛查方法:${item.method}
+营养风险总评分:${item.score}
+筛查结论:${item.conclusion}
+        `.trim();
+        }
+
+        // 4. 存储到列表
+        diagnosisBasisList.value.push({
+            id: item.id,
+            content: content
+        });
+    };
+
+    const removeBasisItem = (index: number) => {
+        // 获取要删除的项目
+        const itemToRemove = diagnosisBasisList.value[index];
+
+        if (itemToRemove && itemToRemove.id) {
+            // 从 diagnosisBasisId 中移除对应的ID
+            const diagnosisBasisIdStr = form.value.diagnosisBasisId ? String(form.value.diagnosisBasisId) : '';
+            const currentIds = diagnosisBasisIdStr ?
+                diagnosisBasisIdStr.split(';').map((id: string) => id.trim()).filter(Boolean) : [];
+
+            // 过滤掉要删除的ID
+            const updatedIds = currentIds.filter((id: string) => id !== String(itemToRemove.id));
+
+            // 更新 diagnosisBasisId
+            form.value.diagnosisBasisId = updatedIds.length > 0 ? updatedIds.join(';') : undefined;
+        }
+
+        // 从显示列表中删除项目
+        diagnosisBasisList.value.splice(index, 1);
+    };
+
+
     /** 查询营养诊断列表 */
     const getList = async () => {
         loading.value = true;
@@ -398,7 +528,189 @@
         return div.textContent || div.innerText || '';
     }
 
+    const screenEvalDateRange = ref < any[] > ([]);
+    const screenEvalList = ref < any[] > ([]);
+
+    const fetchScreenEvalList = async () => {
+        // 获取评估
+        const evalRes = await listEvaluation({
+            patientId: props.patientInfo ?.id,
+            dateRange: screenEvalDateRange.value
+        });
+        // 获取筛查
+        const screeningRes = await listScreening({
+            patientId: props.patientInfo ?.id,
+            dateRange: screenEvalDateRange.value
+        });
+        // 组装成统一格式
+        const evalList = (evalRes.rows || []).map(row => {
+
+            // 解析content字段,获取建议和热量摄入
+            let suggestion = '';
+            let energyArr = [];
+            try {
+                if (row.content) {
+                    const contentObj = typeof row.content === 'string' ? JSON.parse(row.content) : row.content;
+                    // 建议
+                    if (contentObj.suggestion) suggestion = contentObj.suggestion;
+                    // 热量摄入
+                    if (contentObj.energyIntakeList && Array.isArray(contentObj.energyIntakeList)) {
+                        energyArr = contentObj.energyIntakeList.map(e => `${e.date}热量摄入:${e.value}kcal/d`);
+                    }
+                }
+            } catch (e) {}
+            return {
+                id: row.id,
+                type: 'evaluation',
+                date: formatDate(row.evaluationTime || row.screeningTime || row.createTime),
+                evalType: row.configName,
+                energyArr,
+                suggestion: suggestion || row.suggestion || row.remark || '',
+            };
+        });
+        const screeningList = (screeningRes.rows || []).map(row => {
+            // 解析content字段,获取结论
+            let conclusion = '';
+            try {
+                if (row.content) {
+                    const contentObj = typeof row.content === 'string' ? JSON.parse(row.content) : row.content;
+                    if (contentObj.conclusion) conclusion = contentObj.conclusion;
+                }
+            } catch (e) {}
+            return {
+                id: row.id,
+                type: 'screening',
+                date: formatDate(row.screeningTime || row.createTime),
+                method: row.configName,
+                score: row.screeningScore,
+                conclusion: conclusion || row.screeningConclusion || '',
+            };
+        });
+        screenEvalList.value = [...evalList, ...screeningList];
+    };
+    const formatDate = (dateStr) => {
+        if (!dateStr) return '';
+        const date = new Date(dateStr);
+        const year = date.getFullYear();
+        const month = String(date.getMonth() + 1).padStart(2, '0');
+        const day = String(date.getDate()).padStart(2, '0');
+        return `${year}-${month}-${day}`;
+    };
+
     onMounted(() => {
         getList();
+        fetchScreenEvalList();
     });
-</script>
+</script>
+
+<style lang="scss" scoped>
+    .screen-eval-card {
+        margin-bottom: 10px;
+        background: #fff;
+    }
+
+    .card-title {
+        font-weight: bold;
+        font-size: 16px;
+        margin-bottom: 8px;
+        padding: 10px;
+    }
+
+    .card-tip {
+        color: #999;
+        font-size: 12px;
+        margin-left: 8px;
+    }
+
+    .screen-eval-item {
+        background: #f4f4f4;
+        border-radius: 6px;
+        padding: 10px 12px;
+        margin-bottom: 10px;
+        box-shadow: 0 1px 2px #eee;
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+    }
+
+    .eval-content {
+        flex: 1;
+        font-size: 14px;
+        color: #333;
+        line-height: 1.7;
+    }
+
+    .diagnosis-basis-list {
+        margin-bottom: 10px;
+    }
+
+    .basis-item {
+        display: flex;
+        align-items: flex-start;
+        /* 顶部对齐 */
+        margin-bottom: 10px;
+        width: 65vw;
+    }
+
+    .basis-item .el-textarea {
+        flex: 1;
+        margin-right: 8px;
+    }
+
+    /* 确保文本换行 */
+    .el-textarea__inner {
+        white-space: pre-line;
+    }
+
+    .screen-eval-item {
+        display: flex;
+        flex-direction: column;
+        margin-bottom: 16px;
+        padding: 12px;
+        background: #f9f9f9;
+        border-radius: 4px;
+    }
+
+    .eval-content div {
+        margin-bottom: 4px;
+        line-height: 1.5;
+    }
+
+    .eval-button {
+        margin-top: 8px;
+        text-align: right;
+    }
+
+    @media (max-width: 768px) {
+        .eval-button .el-button {
+            width: 100%;
+        }
+    }
+
+    .eval-button .el-button:hover {
+        opacity: 0.8;
+    }
+
+    .footter-low {
+        position: fixed;
+        z-index: 99;
+        bottom: 0;
+        left: calc(var(--left-menu-max-width) + var(--app-content-padding));
+        right: 0;
+        height: 90px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        background: #fff;
+        box-shadow: 0 -3px 6px 1px #6c6d6f26;
+        width: 90vw;
+        margin-right: 10px;
+
+        .el-button {
+            margin-top: 30px;
+            min-width: 120px;
+            height: 44px;
+            padding: 0 24px;
+        }
+    }
+</style>

+ 275 - 270
src/views/patients/nutritionEducation/index.vue

@@ -6,7 +6,13 @@
           <el-card shadow="hover">
             <el-form ref="queryFormRef" :model="queryParams" :inline="true">
               <el-form-item>
-                <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+                <el-date-picker
+                  v-model="queryParams.dateRange"
+                  type="daterange"
+                  range-separator="-"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                />
               </el-form-item>
               <el-form-item label="看诊类型">
                 <el-select v-model="queryParams.type" class="spec-unit-select">
@@ -14,7 +20,7 @@
                 </el-select>
               </el-form-item>
               <el-form-item>
-                <el-input v-model="queryParams.searchValue" placeholder="姓名/门诊/住院号" style="width: 240px; " clearable />
+                <el-input v-model="queryParams.searchValue" placeholder="姓名/门诊/住院号" style="width: 240px" clearable />
               </el-form-item>
               <el-form-item>
                 <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -78,20 +84,20 @@
     </div>
     <div v-show="type === 'addForm'">
       <!-- 添加或修改营养宣教对话框 -->
-      <el-button type="primary" @click="handleBack">返回</el-button> <span style="margin-left: 20px;">新增营养宣教</span> 
-      <el-form ref="educationFormRef" :model="form" :rules="rules" label-width="120px" style="margin-top: 20px;">
+      <el-button type="primary" @click="handleBack">返回</el-button> <span style="margin-left: 20px">新增营养宣教</span>
+      <el-form ref="educationFormRef" :model="form" :rules="rules" label-width="120px" style="margin-top: 20px">
         <el-form-item label="科室:" prop="deptName">
-          <el-input v-model="form.deptName" placeholder="请输入科室" :disabled="true" style="width: 30%;" />
+          <el-input v-model="form.deptName" placeholder="请输入科室" :disabled="true" style="width: 30%" />
         </el-form-item>
         <el-form-item label="营养宣教标题:" prop="educationTitle">
-          <el-input v-model="form.educationTitle" placeholder="请输入营养宣教标题" style="width: 30%;" />
-          <el-button style="margin-left: 10px;" type="primary" @click="showTemplateDialog = true">导入模板</el-button>
+          <el-input v-model="form.educationTitle" placeholder="请输入营养宣教标题" style="width: 30%" />
+          <el-button style="margin-left: 10px" type="primary" @click="showTemplateDialog = true">导入模板</el-button>
         </el-form-item>
         <el-form-item label="描述:" prop="description">
-          <el-input v-model="form.description" type="textarea" :rows="5" placeholder="请输入内容" style="width: 30%;" />
+          <el-input v-model="form.description" type="textarea" :rows="5" placeholder="请输入内容" style="width: 30%" />
         </el-form-item>
         <el-form-item label="正文:">
-          <editor v-model="form.content" :min-height="192" style="width: 75%;" />
+          <editor v-model="form.content" :min-height="192" style="width: 75%" />
         </el-form-item>
       </el-form>
       <EducationTemplateDialog v-model:visible="showTemplateDialog" @select="onTemplateSelect" />
@@ -112,288 +118,287 @@
 </template>
 
 <script setup name="Education" lang="ts">
-    import { listEducation, getEducation, delEducation, addEducation, updateEducation } from '@/api/patients/nutritionEducation';
-    import { EducationVO, EducationQuery, EducationForm } from '@/api/patients/nutritionEducation/types';
-    const EducationTemplateDialog = defineAsyncComponent(() => import('./educationTemplateDialog.vue'));
-    import DetailDialog from './detailDialog.vue';
-    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-    const { treatment_user_type } = toRefs < any > (proxy ?.useDict('treatment_user_type'));
+import {listEducation, getEducation, delEducation, addEducation, updateEducation} from '@/api/patients/nutritionEducation';
+import {EducationVO, EducationQuery, EducationForm} from '@/api/patients/nutritionEducation/types';
+const EducationTemplateDialog = defineAsyncComponent(() => import('./educationTemplateDialog.vue'));
+import DetailDialog from './detailDialog.vue';
+const {proxy} = getCurrentInstance() as ComponentInternalInstance;
+const {treatment_user_type} = toRefs<any>(proxy?.useDict('treatment_user_type'));
 
-    const educationList = ref < EducationVO[] > ([]);
-    const buttonLoading = ref(false);
-    const loading = ref(true);
-    const type = ref('list');
-    const showSearch = ref(true);
-    const ids = ref < Array < string | number >> ([]);
-    const single = ref(true);
-    const multiple = ref(true);
-    const total = ref(0);
-    const showTemplateDialog = ref(false);
-    const showDetailDialog = ref(false);
-    const currentDetail = ref({});
-     const emit = defineEmits(['change'])
-    const queryFormRef = ref < ElFormInstance > ();
-    const educationFormRef = ref < ElFormInstance > ();
+const educationList = ref<EducationVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const type = ref('list');
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const showTemplateDialog = ref(false);
+const showDetailDialog = ref(false);
+const currentDetail = ref({});
+const emit = defineEmits(['change']);
+const queryFormRef = ref<ElFormInstance>();
+const educationFormRef = ref<ElFormInstance>();
 
-    const dialog = reactive < DialogOption > ({
-        visible: false,
-        title: ''
-    });
-    // 声明接收的 props
-    const props = defineProps({
-        patientInfo: {
-            type: Object,
-            required: true,
-            default: () => ({
-                id: '',
-                name: '',
-                age: '',
-                deptId: '',
-                gender: ''
-            })
-        }
-    });
-    const initFormData: EducationForm = {
-        id: undefined,
-        patientId: props.patientInfo ?.id,
-        educationTitle: undefined,
-        educationTemplateId: undefined,
-        description: undefined,
-        content: undefined,
-        contentStr: undefined,
-        type: props.patientInfo ?.type,
-        deptId: props.patientInfo ?.deptId,
-        deptName: undefined,
-        outpatientNo: props.patientInfo ?.outpatientNo,
-    }
-    const data = reactive < PageData < EducationForm,
-        EducationQuery >> ({
-            form: { ...initFormData },
-            queryParams: {
-                pageNum: 1,
-                pageSize: 10,
-                patientId: props.patientInfo ?.id,
-                dateRange: undefined,
-                searchValue: undefined,
-                params: {}
-            },
-            rules: {
-                id: [
-                    { required: true, message: "不能为空", trigger: "blur" }
-                ],
-                patientId: [
-                    { required: true, message: "患者id不能为空", trigger: "blur" }
-                ],
-            }
-        });
-
-    const { queryParams, form, rules } = toRefs(data);
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+// 声明接收的 props
+const props = defineProps({
+  patientInfo: {
+    type: Object,
+    required: true,
+    default: () => ({
+      id: '',
+      name: '',
+      age: '',
+      deptId: '',
+      gender: ''
+    })
+  }
+});
+const initFormData: EducationForm = {
+  id: undefined,
+  patientId: props.patientInfo?.id,
+  educationTitle: undefined,
+  educationTemplateId: undefined,
+  description: undefined,
+  content: undefined,
+  contentStr: undefined,
+  type: props.patientInfo?.type,
+  deptId: props.patientInfo?.deptId,
+  deptName: undefined,
+  outpatientNo: props.patientInfo?.outpatientNo
+};
+const data = reactive<PageData<EducationForm, EducationQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    patientId: props.patientInfo?.id,
+    dateRange: undefined,
+    searchValue: undefined,
+    params: {}
+  },
+  rules: {
+    id: [{required: true, message: '不能为空', trigger: 'blur'}],
+    patientId: [{required: true, message: '患者id不能为空', trigger: 'blur'}]
+  }
+});
 
-    // 监听患者ID变化,自动同步到表单和查询参数
-    watch(
-        () => props.patientInfo.id,
-        (newId) => {
-            form.value.patientId = newId;
-            queryParams.value.patientId = newId;
-        }, { immediate: true }
-    );
-    /** 查询营养宣教列表 */
-    const getList = async () => {
-        loading.value = true;
-        const res = await listEducation(queryParams.value);
-        educationList.value = res.rows;
-        total.value = res.total;
-        loading.value = false;
-    }
-    // 添加tooltip相关的状态和方法
-    const tooltipVisible = ref(false);
-    const tooltipContent = ref('');
-    const tooltipStyle = ref({
-        left: '0px',
-        top: '0px'
-    });
-    const hideTooltip = () => {
-        tooltipVisible.value = false;
-    };
-    const showTooltip = (event: MouseEvent, content: string) => {
-        const target = event.target as HTMLElement;
-        const rect = target.getBoundingClientRect();
+const {queryParams, form, rules} = toRefs(data);
 
-        tooltipContent.value = content;
-        tooltipStyle.value = {
-            left: `${rect.left + window.scrollX}px`,
-            top: `${rect.bottom + window.scrollY + 5}px`
-        };
-        tooltipVisible.value = true;
-    };
-    const onTemplateSelect = async (data) => {
-        form.value.content = data.template;
-        form.value.educationTitle = data.label;
-        form.value.educationTemplateId = data.id;
-        form.value.description = data.description;
+// 监听患者ID变化,自动同步到表单和查询参数
+watch(
+  () => props.patientInfo.id,
+  (newId) => {
+    form.value.patientId = newId;
+    queryParams.value.patientId = newId;
+  },
+  {immediate: true}
+);
+/** 查询营养宣教列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listEducation(queryParams.value);
+  educationList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+// 添加tooltip相关的状态和方法
+const tooltipVisible = ref(false);
+const tooltipContent = ref('');
+const tooltipStyle = ref({
+  left: '0px',
+  top: '0px'
+});
+const hideTooltip = () => {
+  tooltipVisible.value = false;
+};
+const showTooltip = (event: MouseEvent, content: string) => {
+  const target = event.target as HTMLElement;
+  const rect = target.getBoundingClientRect();
 
-    };
+  tooltipContent.value = content;
+  tooltipStyle.value = {
+    left: `${rect.left + window.scrollX}px`,
+    top: `${rect.bottom + window.scrollY + 5}px`
+  };
+  tooltipVisible.value = true;
+};
+const onTemplateSelect = async (data) => {
+  form.value.content = data.template;
+  form.value.educationTitle = data.label;
+  form.value.educationTemplateId = data.id;
+  form.value.description = data.description;
+};
 
-    /** 取消按钮 */
-    const cancel = () => {
-        reset();
-        dialog.visible = false;
-    }
-    const handleDetail = (row) => {
-        currentDetail.value = row;
-        currentDetail.value.content = stripHtml(currentDetail.value.content);
-        showDetailDialog.value = true;
-    }
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+const handleDetail = (row) => {
+  currentDetail.value = row;
+  currentDetail.value.content = stripHtml(currentDetail.value.content);
+  showDetailDialog.value = true;
+};
 
-    function stripHtml(html) {
-        const div = document.createElement('div');
-        div.innerHTML = html;
-        return div.textContent || div.innerText || '';
-    }
+function stripHtml(html) {
+  const div = document.createElement('div');
+  div.innerHTML = html;
+  return div.textContent || div.innerText || '';
+}
 
-    const handleBack = () => {
-        type.value = 'list';
-    }
-    const handleCancel = () => {
-        type.value = 'list';
-    };
+const handleBack = () => {
+  type.value = 'list';
+};
+const handleCancel = () => {
+  type.value = 'list';
+};
 
-    /** 表单重置 */
-    const reset = () => {
-        form.value = {
-            ...initFormData,
-            patientId: props.patientInfo ?.id // 用最新id
-        };
-        educationFormRef.value ?.resetFields();
-    }
+/** 表单重置 */
+const reset = () => {
+  form.value = {
+    ...initFormData,
+    patientId: props.patientInfo?.id // 用最新id
+  };
+  educationFormRef.value?.resetFields();
+};
 
-    /** 搜索按钮操作 */
-    const handleQuery = () => {
-        queryParams.value.pageNum = 1;
-        getList();
-    }
-    // 字典label工具
-    function getDictLabel(dictList: any[], value: string) {
-        if (!dictList || !Array.isArray(dictList)) return value || '--';
-        const found = dictList.find(item => item.value === value);
-        return found ? found.label : value || '--';
-    }
-    /** 重置按钮操作 */
-    const resetQuery = () => {
-        queryFormRef.value ?.resetFields();
-        queryParams.value.dateRange = undefined;
-        queryParams.value.type = undefined;
-        queryParams.value.searchValue = undefined;
-        handleQuery();
-    }
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+// 字典label工具
+function getDictLabel(dictList: any[], value: string) {
+  if (!dictList || !Array.isArray(dictList)) return value || '--';
+  const found = dictList.find((item) => item.value === value);
+  return found ? found.label : value || '--';
+}
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  queryParams.value.dateRange = undefined;
+  queryParams.value.type = undefined;
+  queryParams.value.searchValue = undefined;
+  handleQuery();
+};
 
-    /** 多选框选中数据 */
-    const handleSelectionChange = (selection: EducationVO[]) => {
-        ids.value = selection.map(item => item.id);
-        single.value = selection.length != 1;
-        multiple.value = !selection.length;
-    }
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: EducationVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
 
-    /** 新增按钮操作 */
-    const handleAdd = () => {
-        reset();
-        type.value = 'addForm';
-        form.value.deptName = props.patientInfo ?.deptName;
-        form.value.deptId = props.patientInfo ?.deptId;
-        form.value.patientId = props.patientInfo ?.id;
-        dialog.visible = true;
-        dialog.title = "添加营养宣教";
-    }
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  type.value = 'addForm';
+  form.value.deptName = props.patientInfo?.deptName;
+  form.value.deptId = props.patientInfo?.deptId;
+  form.value.patientId = props.patientInfo?.id;
+  dialog.visible = true;
+  dialog.title = '添加营养宣教';
+};
 
-    /** 修改按钮操作 */
-    const handleUpdate = async (row ? : EducationVO) => {
-        reset();
-        const _id = row ?.id || ids.value[0]
-        const res = await getEducation(_id);
-        Object.assign(form.value, res.data);
-        dialog.visible = true;
-        dialog.title = "修改营养宣教";
-    }
+/** 修改按钮操作 */
+const handleUpdate = async (row?: EducationVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getEducation(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改营养宣教';
+};
 
-    /** 提交按钮 */
-    const submitForm = () => {
-        educationFormRef.value ?.validate(async (valid: boolean) => {
-            if (valid) {
-                buttonLoading.value = true;
-                if (form.value.id) {
-                    form.value.contentStr = window.btoa(encodeURIComponent(form.value.content))
-                    await updateEducation(form.value).finally(() => buttonLoading.value = false);
-                } else {
-                    form.value.contentStr = window.btoa(encodeURIComponent(form.value.content))
-                    await addEducation(form.value).finally(() => buttonLoading.value = false);
-                }
-                proxy ?.$modal.msgSuccess("操作成功");
-                dialog.visible = false;
-                await getList();
-                type.value = 'list';
-            }
-        });
+/** 提交按钮 */
+const submitForm = () => {
+  educationFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        form.value.contentStr = window.btoa(encodeURIComponent(form.value.content));
+        await updateEducation(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        form.value.contentStr = window.btoa(encodeURIComponent(form.value.content));
+        await addEducation(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
+      type.value = 'list';
     }
+  });
+};
 
-    /** 删除按钮操作 */
-    const handleDelete = async (row ? : EducationVO) => {
-        const _ids = row ?.id || ids.value;
-        await proxy ?.$modal.confirm('是否确认删除营养宣教编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
-        await delEducation(_ids);
-        type.value = 'list';
-        proxy ?.$modal.msgSuccess("删除成功");
-        await getList();
-    }
+/** 删除按钮操作 */
+const handleDelete = async (row?: EducationVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除营养宣教编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delEducation(_ids);
+  type.value = 'list';
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
 
-    /** 导出按钮操作 */
-    const handleExport = () => {
-        proxy ?.download('patients/nutritionEducation/export', {
-            ...queryParams.value
-        }, `education_${new Date().getTime()}.xlsx`)
-    }
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'patients/nutritionEducation/export',
+    {
+      ...queryParams.value
+    },
+    `education_${new Date().getTime()}.xlsx`
+  );
+};
 
-    onMounted(() => {
-        getList();
-    });
+onMounted(() => {
+  getList();
+});
 </script>
 
 <style scoped>
-    .description-cell {
-        display: -webkit-box;
-        -webkit-box-orient: vertical;
-        -webkit-line-clamp: 2;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        word-break: break-all;
-        line-height: 1.5;
-        max-height: 3em;
-        text-align: left;
-        padding: 0 8px;
-        cursor: pointer;
-    }
+.description-cell {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  word-break: break-all;
+  line-height: 1.5;
+  max-height: 3em;
+  text-align: left;
+  padding: 0 8px;
+  cursor: pointer;
+}
 
-    .custom-tooltip {
-        position: fixed;
-        z-index: 9999;
-        background: white;
-        border: 1px solid #e4e7ed;
-        border-radius: 4px;
-        padding: 12px;
-        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-        max-width: 400px;
-        line-height: 1.5;
-        font-size: 14px;
-        word-break: break-all;
-        text-align: left;
-    }
+.custom-tooltip {
+  position: fixed;
+  z-index: 9999;
+  background: white;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  padding: 12px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  max-width: 400px;
+  line-height: 1.5;
+  font-size: 14px;
+  word-break: break-all;
+  text-align: left;
+}
 
-    .fade-enter-active,
-    .fade-leave-active {
-        transition: opacity 0.2s ease;
-    }
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.2s ease;
+}
 
-    .fade-enter-from,
-    .fade-leave-to {
-        opacity: 0;
-    }
-</style>
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+</style>

+ 5 - 5
src/views/patients/nutritionSetting/addForm.vue

@@ -27,7 +27,7 @@
                 <el-col :span="3" v-if="title === '烧伤公式'"><span>烧伤面积:</span>
                     <el-input v-model="form.burnArea" style="width: 120px;" /> <span>%</span>
                 </el-col>
-                <el-col :span="3"><span>体重:</span>
+                <el-col :span="3"><span class="required">*</span><span>体重:</span>
                     <el-input v-model="form.weight" style="width: 120px;" /> <span>kg</span>
                 </el-col>
                 <el-col :span="3"><span>上臂围:</span>
@@ -39,7 +39,7 @@
                     <el-input v-model="form.calfCircumference" style="width: 120px;" /> <span>cm</span>
                 </el-col>
                 <el-col :span="20" style="text-align:right;">
-                    <el-button type="primary" class="recalc-btn" @click="()=>recalculate(form.gender, form.age, form.height, form.weight, form.activity, form.stressType)">重新计算</el-button>
+                    <el-button type="primary" class="recalc-btn" @click="()=>recalculate(form.settingType,form.gender, form.age, form.height, form.weight, form.activity, form.stressType,form.burnArea)">重新计算</el-button>
                 </el-col>
             </el-row>
         </div>
@@ -397,13 +397,13 @@
     const NutritionSettingFormRef = ref < FormInstance > ();
 
 
-    const recalculate = async (gender, age, height, weight, activity, stressType) => {
-        const res = await recalculateValue({ gender, age, height, weight, activity, stressType });
+    const recalculate = async (settingType,gender, age, height, weight, activity, stressType,burnArea) => {
+        const res = await recalculateValue({settingType, gender, age, height, weight, activity, stressType ,burnArea});
+        
         if (res) {
             const keepSettingType = form.settingType;
             Object.assign(form, res);
             form.settingType = keepSettingType; // 恢复settingType的值
-
         }
         showFlag.value = 'true';
     };

+ 25 - 26
src/views/patients/nutritionSetting/index.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="p-2">
-        <div v-show="type=='list'">
+        <div v-show="type == 'list'">
             <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">
@@ -19,7 +19,7 @@
                                 </el-select>
                             </el-form-item>
                             <el-form-item>
-                                <el-input v-model="queryParams.searchValue" placeholder="门诊/住院号、医生" style="width: 240px; " clearable />
+                                <el-input v-model="queryParams.searchValue" placeholder="门诊/住院号、医生" style="width: 240px" clearable />
                             </el-form-item>
                             <el-form-item>
                                 <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -44,13 +44,13 @@
                     <el-table-column label="时间" align="center" prop="createTime" />
                     <el-table-column label="看诊类型" align="center" prop="type">
                         <template #default="scope">
-                            <span>{{getDictLabel(treatment_user_type ,scope.row.type )|| '--' }}</span>
+                            <span>{{ getDictLabel(treatment_user_type, scope.row.type) || '--' }}</span>
                         </template>
                     </el-table-column>
                     <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
                     <el-table-column label="营养设定方式" align="center" prop="settingType">
                         <template #default="scope">
-                            <span>{{getDictLabel(nutrition_setting_type ,scope.row.settingType )|| '--' }}</span>
+                            <span>{{ getDictLabel(nutrition_setting_type, scope.row.settingType) || '--' }}</span>
                         </template>
                     </el-table-column>
                     <el-table-column label="所需热量(kcal/d)" align="center" prop="caloriesKcalPerDay" />
@@ -71,30 +71,29 @@
         </div>
         <div>
             <el-dialog :title="'选择营养设定'" v-model="dialog.visible" width="737px" append-to-body :close-on-click-modal="false" :show-close="true" class="nutrition-setting-dialog">
-                <el-row :gutter="20" style="margin-bottom: 10px;">
+                <el-row :gutter="20" style="margin-bottom: 10px">
                     <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '1' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('1', 'BEE')">BEE</el-button>
+                        <el-button :class="['setting-type-btn', form.settingType === '1' ? 'active' : '']" style="width: 100%; height: 46px" @click="handleSelectSettingType('1', 'BEE')">BEE</el-button>
                     </el-col>
                     <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '2' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('2', 'DRIS')">DRIS</el-button>
+                        <el-button :class="['setting-type-btn', form.settingType === '2' ? 'active' : '']" style="width: 100%; height: 46px" @click="handleSelectSettingType('2', 'DRIS')">DRIS</el-button>
                     </el-col>
                 </el-row>
                 <el-row :gutter="20">
                     <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '3' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('3','拇指测法')">拇指测法</el-button>
+                        <el-button :class="['setting-type-btn', form.settingType === '3' ? 'active' : '']" style="width: 100%; height: 46px" @click="handleSelectSettingType('3', '拇指测法')">拇指测法</el-button>
                     </el-col>
                     <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '4' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('4','烧伤公式')">烧伤公式</el-button>
+                        <el-button :class="['setting-type-btn', form.settingType === '4' ? 'active' : '']" style="width: 100%; height: 46px" @click="handleSelectSettingType('4', '烧伤公式')">烧伤公式</el-button>
                     </el-col>
                 </el-row>
             </el-dialog>
         </div>
-        <div v-show="type=='addForm'">
+        <div v-show="type == 'addForm'">
             <!-- 添加或修改营养设定对话框 -->
             <add-form :form="form" :rules="rules" :buttonLoading="buttonLoading" :cancel="cancel" :handleCancelOne="handleCancelOne" :title="title" />
         </div>
     </div>
-
 </template>
 
 <script setup name="NutritionSetting" lang="ts">
@@ -103,7 +102,7 @@
     import { listSetting, getSetting, delSetting, addSetting, updateSetting } from '@/api/patients/nutritionSetting';
     import { NutritionSettingVO, NutritionSettingQuery, NutritionSettingForm } from '@/api/patients/nutritionSetting/types';
     import AddForm from './addForm.vue';
-    const emit = defineEmits(['change'])
+    const emit = defineEmits(['change']);
     import { log } from 'vxe-table';
 
     const { proxy } = getCurrentInstance();
@@ -189,6 +188,7 @@
         settingType: undefined,
         type: props.patientInfo ?.type,
         deptId: props.patientInfo ?.deptId,
+        patientId: props.patientInfo ?.id,
         deptName: undefined,
         outpatientNo: props.patientInfo ?.outpatientNo,
         bmi: props.patientInfo ?.bmi,
@@ -200,14 +200,13 @@
         lowHip: undefined,
         burnArea: undefined,
         gender: props.patientInfo ?.gender,
-        age: props.patientInfo ?.age,
-
+        age: props.patientInfo ?.age
     };
 
     const form = ref({ ...initFormData });
     const queryParams = ref({
         patientId: props.patientInfo ?.id,
-        dateRange: [new Date(), new Date()],
+        dateRange: [],
         type: '',
         settingType: '',
         searchValue: '',
@@ -216,12 +215,8 @@
     });
 
     const rules = ref({
-        height: [
-            { required: true, message: '身高不能为空', trigger: 'blur' }
-        ],
-        activity: [
-            { required: true, message: '体力活动不能为空', trigger: 'change' }
-        ],
+        height: [{ required: true, message: '身高不能为空', trigger: 'blur' }],
+        activity: [{ required: true, message: '体力活动不能为空', trigger: 'change' }],
         // 只有在 BEE 公式下才校验应激状态
         stressType: [{
             required: true,
@@ -247,9 +242,12 @@
     };
 
     const handleExport = () => {
-        proxy ?.download('/patients/nutritionSetting/export', {
-            ...queryParams.value
-        }, `setting_${new Date().getTime()}.xlsx`)
+        proxy ?.download(
+            '/patients/nutritionSetting/export', {
+                ...queryParams.value
+            },
+            `setting_${new Date().getTime()}.xlsx`
+        );
     };
 
     const handleSelectSettingType = (settingType, typeName) => {
@@ -264,7 +262,7 @@
     // 字典label工具
     function getDictLabel(dictList: any[], value: string) {
         if (!dictList || !Array.isArray(dictList)) return value || '--';
-        const found = dictList.find(item => item.value === value);
+        const found = dictList.find((item) => item.value === value);
         return found ? found.label : value || '--';
     }
 
@@ -296,7 +294,7 @@
         handleQuery();
     };
     const handleSelectionChange = (selection: NutritionSettingVO[]) => {
-        ids.value = selection.map(item => item.id);
+        ids.value = selection.map((item) => item.id);
         single.value = selection.length != 1;
         multiple.value = !selection.length;
     };
@@ -317,6 +315,7 @@
         loading.value = true;
         //  这里补充你的获取数据逻辑
         const res = await listSetting(queryParams.value);
+
         settingList.value = res.rows || [];
         total.value = res.total;
         loading.value = false;

+ 2 - 2
src/views/workbench/treatmentUser/index.vue

@@ -126,8 +126,8 @@
                 <div v-show="form.type == '1'">
                     <el-row :gutter="10">
                         <el-col :span="12">
-                            <el-form-item label="床号" prop="bedNum">
-                                <el-input v-model="form.bedNum" placeholder="请输入" />
+                            <el-form-item label="床号" prop="bedNo">
+                                <el-input v-model="form.bedNo" placeholder="请输入" />
                             </el-form-item>
                         </el-col>
                         <el-col :span="12">

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor