Kaynağa Gözat

合并medicalRecord/index

HuRongxin 1 ay önce
ebeveyn
işleme
9de980631e
32 değiştirilmiş dosya ile 6278 ekleme ve 296 silme
  1. 1 1
      .env.development
  2. 1 1
      .env.production
  3. 606 0
      .specstory/history/2025-07-14_04-02Z-修改-index-vue-以实现宫格按钮样式.md
  4. 141 59
      prompt/info.txt
  5. 63 0
      src/api/patients/nutrition/index.ts
  6. 372 0
      src/api/patients/nutrition/types.ts
  7. 63 0
      src/api/patients/nutritionConsumable/index.ts
  8. 222 0
      src/api/patients/nutritionConsumable/types.ts
  9. 63 0
      src/api/patients/settlement/index.ts
  10. 221 0
      src/api/patients/settlement/types.ts
  11. 1 0
      src/api/system/screeningAssessmentConfig/types.ts
  12. 7 0
      src/api/warehouse/productNutrition/index.ts
  13. 7 0
      src/api/warehouse/suppliesManage/index.ts
  14. BIN
      src/assets/images/pay.png
  15. 1 1
      src/utils/request.ts
  16. 3 3
      src/views/login.vue
  17. 213 0
      src/views/patients/enteralNutrition/components/LeftCard.vue
  18. 310 0
      src/views/patients/enteralNutrition/components/RightCard.vue
  19. 178 0
      src/views/patients/enteralNutrition/components/history/LeftCard.vue
  20. 658 0
      src/views/patients/enteralNutrition/components/history/RightCard.vue
  21. 635 0
      src/views/patients/enteralNutrition/components/table/ConfigureTable.vue
  22. 422 0
      src/views/patients/enteralNutrition/components/table/MaterialTable.vue
  23. 496 0
      src/views/patients/enteralNutrition/components/table/NutritionTable.vue
  24. 507 0
      src/views/patients/enteralNutrition/components/table/PackageTable.vue
  25. 28 0
      src/views/patients/enteralNutrition/history.vue
  26. 36 0
      src/views/patients/enteralNutrition/index.vue
  27. 272 54
      src/views/patients/evaluation/add.vue
  28. 145 127
      src/views/patients/medicalRecord/index.vue
  29. 242 0
      src/views/patients/parenteralNutrition/index.vue
  30. 319 33
      src/views/patients/screening/add.vue
  31. 42 14
      src/views/system/screeningAssessmentConfig/add.vue
  32. 3 3
      vite.config.ts

+ 1 - 1
.env.development

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
+VITE_APP_TITLE = 智能营养管理系统
 
 # 开发环境配置
 VITE_APP_ENV = 'development'

+ 1 - 1
.env.production

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
+VITE_APP_TITLE = 智能营养管理系统
 
 # 生产环境配置
 VITE_APP_ENV = 'production'

+ 606 - 0
.specstory/history/2025-07-14_04-02Z-修改-index-vue-以实现宫格按钮样式.md

@@ -1215,3 +1215,609 @@ _**Assistant**_
 
 ---
 
+_**User**_
+
+为我生成三个建表sql
+
+---
+
+_**Assistant**_
+
+根据你提供的字段,下面为你生成三个 MySQL 建表 SQL,分别对应:
+
+1. 结算管理(settlement)
+2. 肠内营养(enteral_nutrition)
+3. 肠内营养耗材(enteral_nutrition_consumable)
+
+字段类型和主键设计已做合理推断,如需调整请告知。
+
+---
+
+### 1. 结算管理表
+
+```sql
+CREATE TABLE settlement (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  order_time DATETIME COMMENT '开单时间',
+  visit_type VARCHAR(32) COMMENT '看诊类型',
+  charge_type VARCHAR(32) COMMENT '收费类型',
+  patient_name VARCHAR(64) COMMENT '患者姓名',
+  patient_department VARCHAR(64) COMMENT '患者科室',
+  patient_no VARCHAR(32) COMMENT '门诊/住院号',
+  phone VARCHAR(32) COMMENT '联系电话',
+  id_card VARCHAR(32) COMMENT '身份证号',
+  receivable_amount DECIMAL(10,2) COMMENT '应收金额'
+) COMMENT='结算管理';
+```
+
+---
+
+### 2. 肠内营养表
+
+```sql
+CREATE TABLE enteral_nutrition (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  settlement_id BIGINT COMMENT '结算管理id',
+  prescription_date DATE COMMENT '开方日期',
+  group_no VARCHAR(32) COMMENT '组号',
+  nutrition_product VARCHAR(64) COMMENT '营养产品',
+  stop_date DATE COMMENT '停嘱日期',
+  prescription_type VARCHAR(32) COMMENT '处方类型',
+  quantity INT COMMENT '数量',
+  dose_per_time VARCHAR(32) COMMENT '用量/次',
+  meal_time VARCHAR(64) COMMENT '餐次时间',
+  frequency VARCHAR(32) COMMENT '频次',
+  first_day VARCHAR(16) COMMENT '首日',
+  dose_per_day VARCHAR(32) COMMENT '用量/日',
+  usage_days INT COMMENT '使用天数',
+  total_dose VARCHAR(32) COMMENT '用量/总',
+  specification VARCHAR(64) COMMENT '规格',
+  usage VARCHAR(64) COMMENT '用法',
+  preparation_volume_per_time VARCHAR(32) COMMENT '制剂液量/次',
+  preparation_concentration_per_time VARCHAR(32) COMMENT '制剂浓度/次',
+  energy_density_per_time VARCHAR(32) COMMENT '能量密度/次',
+  prescription_remark VARCHAR(255) COMMENT '处方备注',
+  daily_calories VARCHAR(32) COMMENT '每日热量',
+  amount DECIMAL(10,2) COMMENT '金额'
+) COMMENT='肠内营养';
+```
+
+---
+
+### 3. 肠内营养耗材表
+
+```sql
+CREATE TABLE enteral_nutrition_consumable (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  group_no VARCHAR(32) COMMENT '组号',
+  consumable VARCHAR(64) COMMENT '耗材',
+  specification VARCHAR(64) COMMENT '规格',
+  dose_per_time VARCHAR(32) COMMENT '用量/次',
+  frequency VARCHAR(32) COMMENT '频次',
+  dose_per_day VARCHAR(32) COMMENT '用量/日',
+  usage_days INT COMMENT '使用天数',
+  first_day VARCHAR(16) COMMENT '首日',
+  quantity INT COMMENT '数量',
+  prescription_remark VARCHAR(255) COMMENT '处方备注',
+  amount DECIMAL(10,2) COMMENT '金额'
+) COMMENT='肠内营养耗材';
+```
+
+---
+
+如需外键、索引、时间戳、唯一约束等,请补充说明!
+
+---
+
+_**User**_
+
+支付方式 帮我创建这个字段
+
+---
+
+_**Assistant**_
+
+当然!你可以将“支付方式”字段添加到你的结算管理表(settlement)中。  
+推荐字段名为 `payment_method`,类型一般用 `VARCHAR(32)` 或 `VARCHAR(20)` 即可。
+
+**示例:**
+
+```sql
+ALTER TABLE settlement
+ADD COLUMN payment_method VARCHAR(32) COMMENT '支付方式' AFTER receivable_amount;
+```
+
+如果你是在建表时直接加字段,则如下:
+
+```sql
+CREATE TABLE settlement (
+  id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  order_time DATETIME COMMENT '开单时间',
+  visit_type VARCHAR(32) COMMENT '看诊类型',
+  charge_type VARCHAR(32) COMMENT '收费类型',
+  patient_name VARCHAR(64) COMMENT '患者姓名',
+  patient_department VARCHAR(64) COMMENT '患者科室',
+  patient_no VARCHAR(32) COMMENT '门诊/住院号',
+  phone VARCHAR(32) COMMENT '联系电话',
+  id_card VARCHAR(32) COMMENT '身份证号',
+  receivable_amount DECIMAL(10,2) COMMENT '应收金额',
+  payment_method VARCHAR(32) COMMENT '支付方式'
+) COMMENT='结算管理';
+```
+
+如需枚举类型(如“现金/微信/支付宝/银行卡”等),也可以用 `ENUM` 类型:
+
+```sql
+payment_method ENUM('现金','微信','支付宝','银行卡') COMMENT '支付方式'
+```
+
+如需进一步约束或默认值,请告知!
+
+---
+
+_**User**_
+
+帮我把字段名都加上`
+
+---
+
+_**Assistant**_
+
+好的,以下是三个表的建表 SQL,**所有字段名都已加上反引号 `**,以保证兼容性和防止关键字冲突。
+
+---
+
+### 1. 结算管理 settlement
+
+```sql
+CREATE TABLE `settlement` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `order_time` DATETIME COMMENT '开单时间',
+  `visit_type` VARCHAR(32) COMMENT '看诊类型',
+  `charge_type` VARCHAR(32) COMMENT '收费类型',
+  `patient_id` bigint(20) DEFAULT NULL COMMENT '患者ID',
+  `patient_name` VARCHAR(64) COMMENT '患者姓名',
+  `patient_department` VARCHAR(64) COMMENT '患者科室',
+  `patient_no` VARCHAR(32) COMMENT '门诊/住院号',
+  `phone` VARCHAR(32) COMMENT '联系电话',
+  `id_card` VARCHAR(32) COMMENT '身份证号',
+  `receivable_amount` DECIMAL(10,2) COMMENT '应收金额',
+  `payment_status` varchar(20)   COMMENT '支付状态(未支付/已支付/已退款)',
+  `payment_method` CHAR(1) COMMENT '支付方式',
+
+  -- 系统字段
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='结算管理';
+```
+
+---
+
+### 2. 肠内营养 enteral_nutrition
+
+```sql
+CREATE TABLE `enteral_nutrition` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `settlement_id` BIGINT COMMENT '结算管理id',
+  `prescription_date` DATE COMMENT '开方日期',
+  `group_no` VARCHAR(32) COMMENT '组号',
+  `nutrition_product` VARCHAR(64) COMMENT '营养产品',
+  `stop_date` DATE COMMENT '停嘱日期',
+  `prescription_type` VARCHAR(32) COMMENT '处方类型',
+  `quantity` INT COMMENT '数量',
+  `dose_per_time` VARCHAR(32) COMMENT '用量/次',
+  `meal_time` VARCHAR(64) COMMENT '餐次时间',
+  `frequency` VARCHAR(32) COMMENT '频次',
+  `first_day` VARCHAR(16) COMMENT '首日',
+  `dose_per_day` VARCHAR(32) COMMENT '用量/日',
+  `usage_days` INT COMMENT '使用天数',
+  `total_dose` VARCHAR(32) COMMENT '用量/总',
+  `specification` VARCHAR(64) COMMENT '规格',
+  `usage` VARCHAR(64) COMMENT '用法',
+  `preparation_volume_per_time` VARCHAR(32) COMMENT '制剂液量/次',
+  `preparation_concentration_per_time` VARCHAR(32) COMMENT '制剂浓度/次',
+  `energy_density_per_time` VARCHAR(32) COMMENT '能量密度/次',
+  `prescription_remark` VARCHAR(255) COMMENT '处方备注',
+  `daily_calories` VARCHAR(32) COMMENT '每日热量',
+  `amount` DECIMAL(10,2) COMMENT '金额',
+
+  -- 系统字段
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养';
+```
+
+---
+
+### 3. 肠内营养耗材 enteral_nutrition_consumable
+
+```sql
+CREATE TABLE `enteral_nutrition_consumable` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `group_no` VARCHAR(32) COMMENT '组号',
+  `consumable` VARCHAR(64) COMMENT '耗材',
+  `specification` VARCHAR(64) COMMENT '规格',
+  `dose_per_time` VARCHAR(32) COMMENT '用量/次',
+  `frequency` VARCHAR(32) COMMENT '频次',
+  `dose_per_day` VARCHAR(32) COMMENT '用量/日',
+  `usage_days` INT COMMENT '使用天数',
+  `first_day` VARCHAR(16) COMMENT '首日',
+  `quantity` INT COMMENT '数量',
+  `prescription_remark` VARCHAR(255) COMMENT '处方备注',
+  `amount` DECIMAL(10,2) COMMENT '金额',
+
+  -- 系统字段
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养耗材';
+```
+
+---
+
+如需进一步调整字段类型或添加索引、外键等,请随时告知!
+
+---
+
+_**User**_
+
+帮我把字段名都加上`
+
+---
+
+_**Assistant**_
+
+以下是三个表的建表 SQL,**所有字段名都已加上反引号 `**,完全符合你的要求:
+
+---
+
+### 1. 结算管理 settlement
+
+```sql
+CREATE TABLE `settlement` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `order_time` DATETIME COMMENT '开单时间',
+  `visit_type` VARCHAR(32) COMMENT '看诊类型',
+  `charge_type` VARCHAR(32) COMMENT '收费类型',
+  `patient_id` bigint(20) DEFAULT NULL COMMENT '患者ID',
+  `patient_name` VARCHAR(64) COMMENT '患者姓名',
+  `patient_department` VARCHAR(64) COMMENT '患者科室',
+  `patient_no` VARCHAR(32) COMMENT '门诊/住院号',
+  `phone` VARCHAR(32) COMMENT '联系电话',
+  `id_card` VARCHAR(32) COMMENT '身份证号',
+  `receivable_amount` DECIMAL(10,2) COMMENT '应收金额',
+  `payment_status` varchar(20)   COMMENT '支付状态(未支付/已支付/已退款)',
+  `payment_method` CHAR(1) COMMENT '支付方式',
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='结算管理';
+```
+
+---
+
+### 2. 肠内营养 enteral_nutrition
+
+```sql
+CREATE TABLE `enteral_nutrition` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `settlement_id` BIGINT COMMENT '结算管理id',
+  `prescription_date` DATE COMMENT '开方日期',
+  `group_no` VARCHAR(32) COMMENT '组号',
+  `nutrition_product` VARCHAR(64) COMMENT '营养产品',
+  `stop_date` DATE COMMENT '停嘱日期',
+  `prescription_type` VARCHAR(32) COMMENT '处方类型',
+  `quantity` INT COMMENT '数量',
+  `dose_per_time` VARCHAR(32) COMMENT '用量/次',
+  `meal_time` VARCHAR(64) COMMENT '餐次时间',
+  `frequency` VARCHAR(32) COMMENT '频次',
+  `first_day` VARCHAR(16) COMMENT '首日',
+  `dose_per_day` VARCHAR(32) COMMENT '用量/日',
+  `usage_days` INT COMMENT '使用天数',
+  `total_dose` VARCHAR(32) COMMENT '用量/总',
+  `specification` VARCHAR(64) COMMENT '规格',
+  `usage` VARCHAR(64) COMMENT '用法',
+  `preparation_volume_per_time` VARCHAR(32) COMMENT '制剂液量/次',
+  `preparation_concentration_per_time` VARCHAR(32) COMMENT '制剂浓度/次',
+  `energy_density_per_time` VARCHAR(32) COMMENT '能量密度/次',
+  `prescription_remark` VARCHAR(255) COMMENT '处方备注',
+  `daily_calories` VARCHAR(32) COMMENT '每日热量',
+  `amount` DECIMAL(10,2) COMMENT '金额',
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养';
+```
+
+---
+
+### 3. 肠内营养耗材 enteral_nutrition_consumable
+
+```sql
+CREATE TABLE `enteral_nutrition_consumable` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `group_no` VARCHAR(32) COMMENT '组号',
+  `consumable` VARCHAR(64) COMMENT '耗材',
+  `specification` VARCHAR(64) COMMENT '规格',
+  `dose_per_time` VARCHAR(32) COMMENT '用量/次',
+  `frequency` VARCHAR(32) COMMENT '频次',
+  `dose_per_day` VARCHAR(32) COMMENT '用量/日',
+  `usage_days` INT COMMENT '使用天数',
+  `first_day` VARCHAR(16) COMMENT '首日',
+  `quantity` INT COMMENT '数量',
+  `prescription_remark` VARCHAR(255) COMMENT '处方备注',
+  `amount` DECIMAL(10,2) COMMENT '金额',
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养耗材';
+```
+
+---
+
+如需进一步调整字段类型、索引、外键等,请随时告知!
+
+---
+
+_**User**_
+
+帮我把字段名都加上`,直接修改
+
+---
+
+_**Assistant**_
+
+```diff
+    支付方式
+  
+- CREATE TABLE settlement (
+-   id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
++ CREATE TABLE `settlement` (
++   `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+-   order_time DATETIME COMMENT '开单时间',
+-   visit_type VARCHAR(32) COMMENT '看诊类型',
+-   charge_type VARCHAR(32) COMMENT '收费类型',
++   `order_time` DATETIME COMMENT '开单时间',
++   `visit_type` VARCHAR(32) COMMENT '看诊类型',
++   `charge_type` VARCHAR(32) COMMENT '收费类型',
+    `patient_id` bigint(20) DEFAULT NULL COMMENT '患者ID',
+-   patient_name VARCHAR(64) COMMENT '患者姓名',
+-   patient_department VARCHAR(64) COMMENT '患者科室',
+-   patient_no VARCHAR(32) COMMENT '门诊/住院号',
+-   phone VARCHAR(32) COMMENT '联系电话',
+-   id_card VARCHAR(32) COMMENT '身份证号',
+-   receivable_amount DECIMAL(10,2) COMMENT '应收金额',
++   `patient_name` VARCHAR(64) COMMENT '患者姓名',
++   `patient_department` VARCHAR(64) COMMENT '患者科室',
++   `patient_no` VARCHAR(32) COMMENT '门诊/住院号',
++   `phone` VARCHAR(32) COMMENT '联系电话',
++   `id_card` VARCHAR(32) COMMENT '身份证号',
++   `receivable_amount` DECIMAL(10,2) COMMENT '应收金额',
+    `payment_status` varchar(20)   COMMENT '支付状态(未支付/已支付/已退款)',
+-   payment_method CHAR(1) COMMENT '支付方式'
++   `payment_method` CHAR(1) COMMENT '支付方式',
+  
+    -- 系统字段
+-   status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+-   del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
+-   create_dept  bigint null comment '创建部门',
+-   create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
+-   create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+-   update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+-     update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
++   `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
++   `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
++   `create_dept`  bigint null comment '创建部门',
++   `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
++   `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
++   `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
++   `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='结算管理';
+  
+```
+
+---
+
+已将 settlement 表的所有字段名都加上了反引号 `,包括主键和系统字段,完全符合你的要求。如需其它表也这样处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我把字段名都加上`,直接修改
+
+---
+
+_**Assistant**_
+
+```diff
+    金额
+   
+- CREATE TABLE enteral_nutrition (
+-   id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
++ CREATE TABLE `enteral_nutrition` (
++   `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+-   settlement_id BIGINT COMMENT '结算管理id',
+-   prescription_date DATE COMMENT '开方日期',
+-   group_no VARCHAR(32) COMMENT '组号',
+-   nutrition_product VARCHAR(64) COMMENT '营养产品',
+-   stop_date DATE COMMENT '停嘱日期',
+-   prescription_type VARCHAR(32) COMMENT '处方类型',
+-   quantity INT COMMENT '数量',
+-   dose_per_time VARCHAR(32) COMMENT '用量/次',
+-   meal_time VARCHAR(64) COMMENT '餐次时间',
+-   frequency VARCHAR(32) COMMENT '频次',
+-   first_day VARCHAR(16) COMMENT '首日',
+-   dose_per_day VARCHAR(32) COMMENT '用量/日',
+-   usage_days INT COMMENT '使用天数',
+-   total_dose VARCHAR(32) COMMENT '用量/总',
+-   specification VARCHAR(64) COMMENT '规格',
+-   usage VARCHAR(64) COMMENT '用法',
+-   preparation_volume_per_time VARCHAR(32) COMMENT '制剂液量/次',
+-   preparation_concentration_per_time VARCHAR(32) COMMENT '制剂浓度/次',
+-   energy_density_per_time VARCHAR(32) COMMENT '能量密度/次',
+-   prescription_remark VARCHAR(255) COMMENT '处方备注',
+-   daily_calories VARCHAR(32) COMMENT '每日热量',
+-   amount DECIMAL(10,2) COMMENT '金额',
++   `settlement_id` BIGINT COMMENT '结算管理id',
++   `prescription_date` DATE COMMENT '开方日期',
++   `group_no` VARCHAR(32) COMMENT '组号',
++   `nutrition_product` VARCHAR(64) COMMENT '营养产品',
++   `stop_date` DATE COMMENT '停嘱日期',
++   `prescription_type` VARCHAR(32) COMMENT '处方类型',
++   `quantity` INT COMMENT '数量',
++   `dose_per_time` VARCHAR(32) COMMENT '用量/次',
++   `meal_time` VARCHAR(64) COMMENT '餐次时间',
++   `frequency` VARCHAR(32) COMMENT '频次',
++   `first_day` VARCHAR(16) COMMENT '首日',
++   `dose_per_day` VARCHAR(32) COMMENT '用量/日',
++   `usage_days` INT COMMENT '使用天数',
++   `total_dose` VARCHAR(32) COMMENT '用量/总',
++   `specification` VARCHAR(64) COMMENT '规格',
++   `usage` VARCHAR(64) COMMENT '用法',
++   `preparation_volume_per_time` VARCHAR(32) COMMENT '制剂液量/次',
++   `preparation_concentration_per_time` VARCHAR(32) COMMENT '制剂浓度/次',
++   `energy_density_per_time` VARCHAR(32) COMMENT '能量密度/次',
++   `prescription_remark` VARCHAR(255) COMMENT '处方备注',
++   `daily_calories` VARCHAR(32) COMMENT '每日热量',
++   `amount` DECIMAL(10,2) COMMENT '金额',
+  
+    -- 系统字段
+-   status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+-   del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
+-   create_dept  bigint null comment '创建部门',
+-   create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
+-   create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+-   update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+-   update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
++   `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
++   `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
++   `create_dept`  bigint null comment '创建部门',
++   `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
++   `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
++   `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
++   `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养';
+  
+```
+
+---
+
+已将 enteral_nutrition 表的所有字段名都加上了反引号 `,包括主键和系统字段,完全符合你的要求。如需其它表也这样处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我把字段名都加上`,直接修改
+
+---
+
+_**Assistant**_
+
+```diff
+  
+   
+-  CREATE TABLE enteral_nutrition_consumable (
+-   id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
++  CREATE TABLE `enteral_nutrition_consumable` (
++   `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+    `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+-   group_no VARCHAR(32) COMMENT '组号',
+-   consumable VARCHAR(64) COMMENT '耗材',
+-   specification VARCHAR(64) COMMENT '规格',
+-   dose_per_time VARCHAR(32) COMMENT '用量/次',
+-   frequency VARCHAR(32) COMMENT '频次',
+-   dose_per_day VARCHAR(32) COMMENT '用量/日',
+-   usage_days INT COMMENT '使用天数',
+-   first_day VARCHAR(16) COMMENT '首日',
+-   quantity INT COMMENT '数量',
+-   prescription_remark VARCHAR(255) COMMENT '处方备注',
+-   amount DECIMAL(10,2) COMMENT '金额',
++   `group_no` VARCHAR(32) COMMENT '组号',
++   `consumable` VARCHAR(64) COMMENT '耗材',
++   `specification` VARCHAR(64) COMMENT '规格',
++   `dose_per_time` VARCHAR(32) COMMENT '用量/次',
++   `frequency` VARCHAR(32) COMMENT '频次',
++   `dose_per_day` VARCHAR(32) COMMENT '用量/日',
++   `usage_days` INT COMMENT '使用天数',
++   `first_day` VARCHAR(16) COMMENT '首日',
++   `quantity` INT COMMENT '数量',
++   `prescription_remark` VARCHAR(255) COMMENT '处方备注',
++   `amount` DECIMAL(10,2) COMMENT '金额',
+  
+    -- 系统字段
+-   status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+-   del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
+-   create_dept  bigint null comment '创建部门',
+-   create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
+-   create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+-   update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
+-   update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
++   `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
++   `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
++   `create_dept`  bigint null comment '创建部门',
++   `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
++   `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
++   `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
++   `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养耗材';
+  
+```
+
+---
+
+已将 enteral_nutrition_consumable 表的所有字段名都加上了反引号 `,包括主键和系统字段,完全符合你的要求。如需其它表也这样处理,请随时告知!
+
+---
+
+_**User**_
+
+帮我将样式改为文字右边显示,直接修改代码
+
+---
+
+_**Assistant**_
+
+Cancelled
+
+---
+
+
+
+---
+

+ 141 - 59
prompt/info.txt

@@ -1,76 +1,158 @@
+营养筛查
 营养评估
-  时间
-  看诊类型
-  门诊/住院号
-  营养评估类型类型  
-  支付状态
-  筛查医生/护士
+预包装处方
+配置处方
+长嘱处方
+院内膳食
 
 
+ 
 
+结算管理
+  开单时间
+  看诊类型
+  收费类型
+  患者姓名
+  患者科室
+  门诊/住院号
+  联系电话
+  身份证号
+  应收金额
+  支付状态
+  支付方式
 
--- 营养评估表
-CREATE TABLE `nutrition_screening` (
+CREATE TABLE `settlement` (
   `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `order_time` DATETIME COMMENT '开单时间',
+  `visit_type` VARCHAR(32) COMMENT '看诊类型',
+  `charge_type` VARCHAR(32) COMMENT '收费类型',
   `patient_id` bigint(20) DEFAULT NULL COMMENT '患者ID',
-  `config_id` bigint NOT NULL COMMENT '营养筛查类型',
-  `screening_time` datetime NOT NULL COMMENT '筛查时间',
-  `visit_type` char(1) NOT NULL COMMENT '看诊类型(0门诊 1住院)',
-  `patient_no` varchar(50) NOT NULL COMMENT '门诊/住院号',   
-  `payment_status` varchar(20) DEFAULT '未支付' COMMENT '支付状态(未支付/已支付/已退款)',
-  `content` longtext  null comment '内容',
+  `patient_name` VARCHAR(64) COMMENT '患者姓名',
+  `patient_department` VARCHAR(64) COMMENT '患者科室',
+  `patient_no` VARCHAR(32) COMMENT '门诊/住院号',
+  `phone` VARCHAR(32) COMMENT '联系电话',
+  `id_card` VARCHAR(32) COMMENT '身份证号',
+  `receivable_amount` DECIMAL(10,2) COMMENT '应收金额',
+  `payment_status` varchar(20)   COMMENT '支付状态(未支付/已支付/已退款)',
+  `payment_method` CHAR(1) COMMENT '支付方式',
 
   -- 系统字段
-  status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
-  del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
-  create_dept  bigint null comment '创建部门',
-  create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
-  create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
-  update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'   
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='营养评估表';
-
-
-
-
-CREATE TABLE sys_screening_assessment_config (
-    config_id     BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
-    tenant_id  varchar(20) default '000000' null comment '租户编号',
-    type          char(1) NOT NULL COMMENT '量表类型',           -- 如:营养筛查、营养评估
-    gender        char(2) DEFAULT '-1' COMMENT '性别',         -- 男、女、不限
-    age           char(2) DEFAULT '-1' COMMENT '年龄',         -- 如:不限、18-65、>65等
-    name          VARCHAR(150) NOT NULL COMMENT '量表名称',
-    description   VARCHAR(300) DEFAULT NULL COMMENT '量表说明',
-    remark        text DEFAULT NULL COMMENT '备注',
-     
-    -- 系统字段
-    status CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
-    del_flag char default '0' null comment '删除标志(0代表存在 1代表删除)',
-    create_dept  bigint null comment '创建部门',
-    create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='筛查/评估配置表';
-
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='结算管理';
+
+
+肠内营养
+  结算管理id
+  开方日期
+  组号
+  营养产品
+  停嘱日期
+  处方类型
+  数量
+  用量/次
+  餐次时间
+  频次
+  首日
+  用量/日
+  使用天数
+  用量/总
+  规格
+  用法
+  制剂液量/次
+  制剂浓度/次
+  能量密度/次
+  处方备注
+  每日热量
+  金额
  
-CREATE TABLE sys_screening_assessment_question(
-  question_id     BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
-  tenant_id  varchar(20) default '000000' null comment '租户编号',
-  config_id     BIGINT  COMMENT '主键ID',
-  title     VARCHAR(600) NOT NULL COMMENT '标题',
-  question_type VARCHAR(50) NOT NULL COMMENT '题型',
-  content   text COMMENT '内容',
+CREATE TABLE `enteral_nutrition` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `settlement_id` BIGINT COMMENT '结算管理id',
+  `prescription_date` DATE COMMENT '开方日期',
+  `group_no` VARCHAR(32) COMMENT '组号',
+  `nutrition_product` VARCHAR(64) COMMENT '营养产品',
+  `stop_date` DATE COMMENT '停嘱日期',
+  `prescription_type` VARCHAR(32) COMMENT '处方类型',
+  `quantity` INT COMMENT '数量',
+  `dose_per_time` VARCHAR(32) COMMENT '用量/次',
+  `meal_time` VARCHAR(64) COMMENT '餐次时间',
+  `frequency` VARCHAR(32) COMMENT '频次',
+  `first_day` VARCHAR(16) COMMENT '首日',
+  `dose_per_day` VARCHAR(32) COMMENT '用量/日',
+  `usage_days` INT COMMENT '使用天数',
+  `total_dose` VARCHAR(32) COMMENT '用量/总',
+  `specification` VARCHAR(64) COMMENT '规格',
+  `usage` VARCHAR(64) COMMENT '用法',
+  `preparation_volume_per_time` VARCHAR(32) COMMENT '制剂液量/次',
+  `preparation_concentration_per_time` VARCHAR(32) COMMENT '制剂浓度/次',
+  `energy_density_per_time` VARCHAR(32) COMMENT '能量密度/次',
+  `prescription_remark` VARCHAR(255) COMMENT '处方备注',
+  `daily_calories` VARCHAR(32) COMMENT '每日热量',
+  `amount` DECIMAL(10,2) COMMENT '金额',
 
   -- 系统字段
-  create_dept  bigint null comment '创建部门',
-  create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
-  create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
-  update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='题目表';
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养';
+
+肠内营养耗材
+  组号
+  耗材
+  规格
+  用量/次
+  频次
+  用量/日
+  使用天数
+  首日
+  数量
+  处方备注
+  金额
+
  
+ CREATE TABLE `enteral_nutrition_consumable` (
+  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
+  `tenant_id`  varchar(20) default '000000' null comment '租户编号',
+  `settlement_id` BIGINT COMMENT '结算管理id',
+  `group_no` VARCHAR(32) COMMENT '组号',
+  `consumable` VARCHAR(64) COMMENT '耗材',
+  `specification` VARCHAR(64) COMMENT '规格',
+  `dose_per_time` VARCHAR(32) COMMENT '用量/次',
+  `frequency` VARCHAR(32) COMMENT '频次',
+  `dose_per_day` VARCHAR(32) COMMENT '用量/日',
+  `usage_days` INT COMMENT '使用天数',
+  `first_day` VARCHAR(16) COMMENT '首日',
+  `quantity` INT COMMENT '数量',
+  `prescription_remark` VARCHAR(255) COMMENT '处方备注',
+  `amount` DECIMAL(10,2) COMMENT '金额',
+
+  -- 系统字段
+  `status` CHAR(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
+  `del_flag` char default '0' null comment '删除标志(0代表存在 1代表删除)',
+  `create_dept`  bigint null comment '创建部门',
+  `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
+  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
+  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='肠内营养耗材';
+
+
  
+
+
+   
  
 
 

+ 63 - 0
src/api/patients/nutrition/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { NutritionVO, NutritionForm, NutritionQuery } from '@/api/system/nutrition/types';
+
+/**
+ * 查询肠内营养列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listEnteralNutrition = (query?: NutritionQuery): AxiosPromise<NutritionVO[]> => {
+  return request({
+    url: '/system/nutrition/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询肠内营养详细
+ * @param id
+ */
+export const getEnteralNutrition = (id: string | number): AxiosPromise<NutritionVO> => {
+  return request({
+    url: '/system/nutrition/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增肠内营养
+ * @param data
+ */
+export const addEnteralNutrition = (data: NutritionForm) => {
+  return request({
+    url: '/system/nutrition',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改肠内营养
+ * @param data
+ */
+export const updateEnteralNutrition = (data: NutritionForm) => {
+  return request({
+    url: '/system/nutrition',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除肠内营养
+ * @param id
+ */
+export const delEnteralNutrition = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/system/nutrition/' + id,
+    method: 'delete'
+  });
+};

+ 372 - 0
src/api/patients/nutrition/types.ts

@@ -0,0 +1,372 @@
+export interface EnteralNutritionVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 结算管理id
+   */
+  settlementId: string | number;
+
+  /**
+   * 开方日期
+   */
+  prescriptionDate: string;
+
+  /**
+   * 组号
+   */
+  groupNo: string;
+
+  /**
+   * 营养产品
+   */
+  nutritionProduct: string;
+
+  /**
+   * 停嘱日期
+   */
+  stopDate: string;
+
+  /**
+   * 处方类型
+   */
+  prescriptionType: string;
+
+  /**
+   * 数量
+   */
+  quantity: number;
+
+  /**
+   * 用量/次
+   */
+  dosePerTime: string;
+
+  /**
+   * 餐次时间
+   */
+  mealTime: string;
+
+  /**
+   * 频次
+   */
+  frequency: string;
+
+  /**
+   * 首日
+   */
+  firstDay: string;
+
+  /**
+   * 用量/日
+   */
+  dosePerDay: string;
+
+  /**
+   * 使用天数
+   */
+  usageDays: number;
+
+  /**
+   * 用量/总
+   */
+  totalDose: string;
+
+  /**
+   * 规格
+   */
+  specification: string;
+
+  /**
+   * 用法
+   */
+  usage: string;
+
+  /**
+   * 制剂液量/次
+   */
+  preparationVolumePerTime: string;
+
+  /**
+   * 制剂浓度/次
+   */
+  preparationConcentrationPerTime: string;
+
+  /**
+   * 能量密度/次
+   */
+  energyDensityPerTime: string;
+
+  /**
+   * 处方备注
+   */
+  prescriptionRemark: string;
+
+  /**
+   * 每日热量
+   */
+  dailyCalories: string;
+
+  /**
+   * 金额
+   */
+  amount: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+}
+
+export interface EnteralNutritionForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 结算管理id
+   */
+  settlementId?: string | number;
+
+  /**
+   * 开方日期
+   */
+  prescriptionDate?: string;
+
+  /**
+   * 组号
+   */
+  groupNo?: string;
+
+  /**
+   * 营养产品
+   */
+  nutritionProduct?: string;
+  nutritionProductId?: string;
+
+  /**
+   * 停嘱日期
+   */
+  stopDate?: string;
+
+  /**
+   * 处方类型
+   */
+  prescriptionType?: string;
+
+  /**
+   * 数量
+   */
+  quantity?: number;
+
+  /**
+   * 用量/次
+   */
+  dosePerTime?: string|;
+
+  /**
+   * 餐次时间
+   */
+  mealTime?: string;
+
+  /**
+   * 频次
+   */
+  frequency?: number;
+
+  /**
+   * 首日
+   */
+  firstDay?: number;
+
+  /**
+   * 用量/日
+   */
+  dosePerDay?: string;
+
+  /**
+   * 使用天数
+   */
+  usageDays?: number;
+
+  /**
+   * 用量/总
+   */
+  totalDose?: string;
+
+  /**
+   * 规格
+   */
+  specification?: string;
+
+  /**
+   * 用法
+   */
+  usage?: string;
+
+  /**
+   * 制剂液量/次
+   */
+  preparationVolumePerTime?: string;
+
+  /**
+   * 制剂浓度/次
+   */
+  preparationConcentrationPerTime?: string;
+
+  /**
+   * 能量密度/次
+   */
+  energyDensityPerTime?: string;
+
+  /**
+   * 处方备注
+   */
+  prescriptionRemark?: string;
+
+  /**
+   * 每日热量
+   */
+  dailyCalories?: string;
+
+  /**
+   * 金额
+   */
+  amount?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+}
+
+export interface EnteralNutritionQuery extends PageQuery {
+
+  /**
+   * 结算管理id
+   */
+  settlementId?: string | number;
+
+  /**
+   * 开方日期
+   */
+  prescriptionDate?: string;
+
+  /**
+   * 组号
+   */
+  groupNo?: string;
+
+  /**
+   * 营养产品
+   */
+  nutritionProduct?: string;
+
+  /**
+   * 停嘱日期
+   */
+  stopDate?: string;
+
+  /**
+   * 处方类型
+   */
+  prescriptionType?: string;
+
+  /**
+   * 数量
+   */
+  quantity?: number;
+
+  /**
+   * 用量/次
+   */
+  dosePerTime?: string;
+
+  /**
+   * 餐次时间
+   */
+  mealTime?: string;
+
+  /**
+   * 频次
+   */
+  frequency?: string;
+
+  /**
+   * 首日
+   */
+  firstDay?: string;
+
+  /**
+   * 用量/日
+   */
+  dosePerDay?: string;
+
+  /**
+   * 使用天数
+   */
+  usageDays?: number;
+
+  /**
+   * 用量/总
+   */
+  totalDose?: string;
+
+  /**
+   * 规格
+   */
+  specification?: string;
+
+  /**
+   * 用法
+   */
+  usage?: string;
+
+  /**
+   * 制剂液量/次
+   */
+  preparationVolumePerTime?: string;
+
+  /**
+   * 制剂浓度/次
+   */
+  preparationConcentrationPerTime?: string;
+
+  /**
+   * 能量密度/次
+   */
+  energyDensityPerTime?: string;
+
+  /**
+   * 处方备注
+   */
+  prescriptionRemark?: string;
+
+  /**
+   * 每日热量
+   */
+  dailyCalories?: string;
+
+  /**
+   * 金额
+   */
+  amount?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 63 - 0
src/api/patients/nutritionConsumable/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { NutritionConsumableVO, NutritionConsumableForm, NutritionConsumableQuery } from '@/api/system/nutritionConsumable/types';
+
+/**
+ * 查询肠内营养耗材列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listNutritionConsumable = (query?: NutritionConsumableQuery): AxiosPromise<NutritionConsumableVO[]> => {
+  return request({
+    url: '/system/nutritionConsumable/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询肠内营养耗材详细
+ * @param id
+ */
+export const getNutritionConsumable = (id: string | number): AxiosPromise<NutritionConsumableVO> => {
+  return request({
+    url: '/system/nutritionConsumable/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增肠内营养耗材
+ * @param data
+ */
+export const addNutritionConsumable = (data: NutritionConsumableForm) => {
+  return request({
+    url: '/system/nutritionConsumable',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改肠内营养耗材
+ * @param data
+ */
+export const updateNutritionConsumable = (data: NutritionConsumableForm) => {
+  return request({
+    url: '/system/nutritionConsumable',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除肠内营养耗材
+ * @param id
+ */
+export const delNutritionConsumable = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/system/nutritionConsumable/' + id,
+    method: 'delete'
+  });
+};

+ 222 - 0
src/api/patients/nutritionConsumable/types.ts

@@ -0,0 +1,222 @@
+export interface NutritionConsumableVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 结算管理id
+   */
+  settlementId: string | number;
+
+  /**
+   * 组号
+   */
+  groupNo: string;
+
+  /**
+   * 耗材
+   */
+  consumable: string;
+
+  /**
+   * 规格
+   */
+  specification: string;
+
+  /**
+   * 用量/次
+   */
+  dosePerTime: string;
+
+  /**
+   * 频次
+   */
+  frequency: string;
+
+  /**
+   * 用量/日
+   */
+  dosePerDay: string;
+
+  /**
+   * 使用天数
+   */
+  usageDays: number;
+
+  /**
+   * 首日
+   */
+  firstDay: string;
+
+  /**
+   * 数量
+   */
+  quantity: number;
+
+  /**
+   * 处方备注
+   */
+  prescriptionRemark: string;
+
+  /**
+   * 金额
+   */
+  amount: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+}
+
+export interface NutritionConsumableForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 结算管理id
+   */
+  settlementId?: string | number;
+
+  /**
+   * 组号
+   */
+  groupNo?: string;
+
+  /**
+   * 耗材
+   */
+  consumable?: string;
+  consumableId?: string;
+
+  /**
+   * 规格
+   */
+  specification?: string;
+
+  /**
+   * 用量/次
+   */
+  dosePerTime?: number;
+
+  /**
+   * 频次
+   */
+  frequency?: number;
+
+  /**
+   * 用量/日
+   */
+  dosePerDay?: number;
+
+  /**
+   * 使用天数
+   */
+  usageDays?: number;
+
+  /**
+   * 首日
+   */
+  firstDay?: number;
+
+  /**
+   * 数量
+   */
+  quantity?: number;
+
+  /**
+   * 处方备注
+   */
+  prescriptionRemark?: string;
+
+  /**
+   * 金额
+   */
+  amount?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+}
+
+export interface NutritionConsumableQuery extends PageQuery {
+
+  /**
+   * 结算管理id
+   */
+  settlementId?: string | number;
+
+  /**
+   * 组号
+   */
+  groupNo?: string;
+
+  /**
+   * 耗材
+   */
+  consumable?: string;
+
+  /**
+   * 规格
+   */
+  specification?: string;
+
+  /**
+   * 用量/次
+   */
+  dosePerTime?: string;
+
+  /**
+   * 频次
+   */
+  frequency?: string;
+
+  /**
+   * 用量/日
+   */
+  dosePerDay?: string;
+
+  /**
+   * 使用天数
+   */
+  usageDays?: number;
+
+  /**
+   * 首日
+   */
+  firstDay?: string;
+
+  /**
+   * 数量
+   */
+  quantity?: number;
+
+  /**
+   * 处方备注
+   */
+  prescriptionRemark?: string;
+
+  /**
+   * 金额
+   */
+  amount?: number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 63 - 0
src/api/patients/settlement/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { SettlementVO, SettlementForm, SettlementQuery } from '@/api/system/settlement/types';
+
+/**
+ * 查询结算管理列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSettlement = (query?: SettlementQuery): AxiosPromise<SettlementVO[]> => {
+  return request({
+    url: '/system/settlement/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询结算管理详细
+ * @param id
+ */
+export const getSettlement = (id: string | number): AxiosPromise<SettlementVO> => {
+  return request({
+    url: '/system/settlement/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增结算管理
+ * @param data
+ */
+export const addSettlement = (data: SettlementForm) => {
+  return request({
+    url: '/system/settlement',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改结算管理
+ * @param data
+ */
+export const updateSettlement = (data: SettlementForm) => {
+  return request({
+    url: '/system/settlement',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除结算管理
+ * @param id
+ */
+export const delSettlement = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/system/settlement/' + id,
+    method: 'delete'
+  });
+};

+ 221 - 0
src/api/patients/settlement/types.ts

@@ -0,0 +1,221 @@
+export interface SettlementVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 开单时间
+   */
+  orderTime: string;
+
+  /**
+   * 看诊类型
+   */
+  visitType: string;
+
+  /**
+   * 收费类型
+   */
+  chargeType: string;
+
+  /**
+   * 患者ID
+   */
+  patientId: string | number;
+
+  /**
+   * 患者姓名
+   */
+  patientName: string;
+
+  /**
+   * 患者科室
+   */
+  patientDepartment: string;
+
+  /**
+   * 门诊/住院号
+   */
+  patientNo: string;
+
+  /**
+   * 联系电话
+   */
+  phone: string;
+
+  /**
+   * 身份证号
+   */
+  idCard: string | number;
+
+  /**
+   * 应收金额
+   */
+  receivableAmount: number;
+
+  /**
+   * 支付状态(未支付/已支付/已退款)
+   */
+  paymentStatus: string;
+
+  /**
+   * 支付方式
+   */
+  paymentMethod: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+}
+
+export interface SettlementForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 开单时间
+   */
+  orderTime?: string;
+
+  /**
+   * 看诊类型
+   */
+  visitType?: string;
+
+  /**
+   * 收费类型
+   */
+  chargeType?: string;
+
+  /**
+   * 患者ID
+   */
+  patientId?: string | number;
+
+  /**
+   * 患者姓名
+   */
+  patientName?: string;
+
+  /**
+   * 患者科室
+   */
+  patientDepartment?: string;
+
+  /**
+   * 门诊/住院号
+   */
+  patientNo?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 身份证号
+   */
+  idCard?: string | number;
+
+  /**
+   * 应收金额
+   */
+  receivableAmount?: number;
+
+  /**
+   * 支付状态(未支付/已支付/已退款)
+   */
+  paymentStatus?: string;
+
+  /**
+   * 支付方式
+   */
+  paymentMethod?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+}
+
+export interface SettlementQuery extends PageQuery {
+
+  /**
+   * 开单时间
+   */
+  orderTime?: string;
+
+  /**
+   * 看诊类型
+   */
+  visitType?: string;
+
+  /**
+   * 收费类型
+   */
+  chargeType?: string;
+
+  /**
+   * 患者ID
+   */
+  patientId?: string | number;
+
+  /**
+   * 患者姓名
+   */
+  patientName?: string;
+
+  /**
+   * 患者科室
+   */
+  patientDepartment?: string;
+
+  /**
+   * 门诊/住院号
+   */
+  patientNo?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 身份证号
+   */
+  idCard?: string | number;
+
+  /**
+   * 应收金额
+   */
+  receivableAmount?: number;
+
+  /**
+   * 支付状态(未支付/已支付/已退款)
+   */
+  paymentStatus?: string;
+
+  /**
+   * 支付方式
+   */
+  paymentMethod?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 1 - 0
src/api/system/screeningAssessmentConfig/types.ts

@@ -49,6 +49,7 @@ export interface QuestionAttrVO {
   score?: string;
   img?: string;
   allowFillBlank?: boolean;
+  matrixFillBlank?: string;
   unit?: string;
   optionContent?: string;
   optionFlag?: boolean;

+ 7 - 0
src/api/warehouse/productNutrition/index.ts

@@ -16,6 +16,13 @@ export const listNutrition = (query?: NutritionQuery): AxiosPromise<NutritionVO[
   });
 };
 
+export const listAllNutrition = (): AxiosPromise<NutritionVO[]> => {
+  return request({
+    url: '/warehouse/nutrition/listAll',
+    method: 'get'
+  });
+};
+
 /**
  * 查询营养产品信息详细
  * @param id

+ 7 - 0
src/api/warehouse/suppliesManage/index.ts

@@ -16,6 +16,13 @@ export const listSuppliesManage = (query?: SuppliesManageQuery): AxiosPromise<Su
   });
 };
 
+export const listAll = ( ): AxiosPromise<SuppliesManageVO[]> => {
+  return request({
+    url: '/warehouse/suppliesManage/listAll',
+    method: 'get'     
+  });
+};
+
 /**
  * 查询耗材管理详细
  * @param id

BIN
src/assets/images/pay.png


+ 1 - 1
src/utils/request.ts

@@ -27,7 +27,7 @@ axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
 axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID;
 // 创建 axios 实例
 const service = axios.create({
-  baseURL: 'http://192.168.1.237/dev-api',
+  baseURL: import.meta.env.VITE_APP_BASE_API, // api 的 base_url,
   timeout: 50000
 });
 

+ 3 - 3
src/views/login.vue

@@ -5,7 +5,7 @@
         <h3 class="title">{{ title }}</h3>
         <lang-select />
       </div>
-      <el-form-item v-if="tenantEnabled" prop="tenantId">
+      <el-form-item v-if="tenantEnabled" prop="tenantId" v-show="false">
         <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">
           <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
@@ -44,7 +44,7 @@
         </div>
       </el-form-item>
       <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
-      <el-form-item style="float: right">
+      <!-- <el-form-item style="float: right">
         <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
           <svg-icon icon-class="wechat" />
         </el-button>
@@ -60,7 +60,7 @@
         <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">
           <svg-icon icon-class="github" />
         </el-button>
-      </el-form-item>
+      </el-form-item> -->
       <el-form-item style="width: 100%">
         <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
           <span v-if="!loading">{{ proxy.$t('login.login') }}</span>

+ 213 - 0
src/views/patients/enteralNutrition/components/LeftCard.vue

@@ -0,0 +1,213 @@
+<template>
+  <el-card class="left-card">
+    <!-- 顶部标签页 -->
+    <el-tabs v-model="activeTab" class="main-tabs">
+      <el-tab-pane label="肠内营养" name="nutrition">
+        <div class="content-wrapper">
+          <!-- 日期和操作栏 -->
+          <div class="operation-bar">
+            <!-- 日期选择 -->
+            <el-row>
+              <el-col :span="10">
+                <span class="label">日期时间:</span>
+                <el-date-picker v-model="dateRange" type="date"  placeholder="请选择" />
+              </el-col>
+              <el-col class="right_btn" :span="7">
+                <!-- <el-button type="primary" plain>打印知情同意书</el-button> -->
+                <el-button type="success" @click="goHistoryPrescription">历史处方</el-button>
+              </el-col>
+            </el-row>
+
+            <!-- 添加按钮组 -->
+            <div class="add-buttons">
+              <el-button :class="['add-btn', {'is-active': prescriptionType === 'normal'}]"
+                @click="addPrescription">添加配置处方</el-button>
+              <el-button :class="['add-btn', {'is-active': prescriptionType === 'package'}]"
+                @click="addTemplate">添加预包装处方</el-button>
+              <el-button :class="['add-btn', {'is-active': prescriptionType === 'long-term'}]"
+                @click="addLongTerm">添加长期医嘱处方</el-button>
+            </div>
+
+            <!-- 开方原因 -->
+            <div class="prescription-reason">
+              <span class="reason-label">开方原因:</span>
+              <span class="reason-value">1111</span>
+            </div>
+          </div>
+
+          <!-- 处方提示信息 -->
+          <div class="prescription-info">
+            <div class="warning-box">
+              当前处方中的脂肪、维生素A、维生素D、维生素E、维生素B1、维生素B2、维生素B6、维生素B12、硒(尼克黄)、维生素C、生物素、泛酸元素可能过量
+            </div>
+          </div>
+
+          <!-- 处方表格 -->
+          <div class="prescription-tables">
+            <template v-if="tableType === 'normal'">
+              <ConfigureTable @change="updateConfigureData"/>
+              <MaterialTable v-model="configData"/>
+            </template>
+            <template v-else-if="tableType === 'package'">
+              <PackageTable/>
+            </template>
+            <template v-else>
+              <NutritionTable/>
+              <MaterialTable/>
+            </template>
+          </div>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="膳食治疗" name="therapy">
+        <!-- 膳食治疗内容 -->
+      </el-tab-pane>
+    </el-tabs>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import {ref} from 'vue';
+import NutritionTable from './table/NutritionTable.vue';
+import MaterialTable from './table/MaterialTable.vue';
+import PackageTable from './table/PackageTable.vue';
+import ConfigureTable from './table/ConfigureTable.vue'; 
+ 
+import { listEnteralNutrition, getEnteralNutrition, delEnteralNutrition, addEnteralNutrition, updateEnteralNutrition } from '@/api/patients/nutrition';
+import { EnteralNutritionVO, EnteralNutritionQuery, EnteralNutritionForm } from '@/api/patients/nutrition/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+ 
+const emit = defineEmits(['gotoTop']);
+
+// 顶部tab切换
+const activeTab = ref('nutrition');
+const configData= ref('');
+
+// 表格类型
+const tableType = ref<'normal' | 'package' | 'long-term'>('normal');
+
+// 日期范围
+const dateRange = ref([]);
+
+// 处方类型
+const prescriptionType = ref<'normal' | 'package' | 'long-term'>('normal');
+
+const updateConfigureData = (val:string) => {  
+  configData.value=val;  
+};
+
+
+// 添加配置处方
+const addPrescription = () => {
+  prescriptionType.value = 'normal';
+  tableType.value = 'normal';
+};
+
+// 添加预包装处方
+const addTemplate = () => {
+  prescriptionType.value = 'package';
+  tableType.value = 'package';
+};
+
+// 添加长期医嘱处方
+const addLongTerm = () => {
+  prescriptionType.value = 'long-term';
+  tableType.value = 'long-term';
+};
+
+// 跳转历史处方页面
+const goHistoryPrescription = () => {
+  emit('gotoTop')
+};
+
+</script>
+
+<style lang="scss" scoped>
+.left-card {
+  flex: 1;
+  position: relative;
+  .main-tabs {
+    :deep(.el-tabs__header) {
+      margin-bottom: 20px;
+    }
+    :deep(.el-tabs__nav) {
+      .el-tabs__item {
+        font-size: 15px;
+        padding: 0 30px;
+        height: 40px;
+        line-height: 40px;
+      }
+    }
+  }
+  .operation-bar {
+    margin-bottom: 16px;
+    .right_btn {
+      margin-left: 268px;
+    }
+
+    .add-buttons {
+      display: flex;
+      gap: 12px;
+      margin-top: 30px;
+      margin-bottom: 12px;
+
+      .add-btn {
+        min-width: 120px;
+        background-color: #fff;
+        border: 1px solid #dcdfe6;
+        color: #606266;
+        transition: all 0.3s;
+
+        &.is-active {
+          background-color: var(--el-color-primary);
+          border-color: var(--el-color-primary);
+          color: #fff;
+        }
+
+        &:hover:not(.is-active) {
+          border-color: var(--el-color-primary);
+          color: var(--el-color-primary);
+        }
+      }
+    }
+
+    .prescription-reason {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #f56c6c;
+      font-size: 14px;
+
+      .reason-label {
+        color: #606266;
+      }
+
+      .reason-value {
+        color: #f56c6c;
+      }
+    }
+  }
+
+  .prescription-info {
+    margin-bottom: 16px;
+
+    .warning-box {
+      padding: 8px 16px;
+      background: #fff7e6;
+      border: 1px solid #ffd591;
+      border-radius: 4px;
+      color: #fa8c16;
+      border: 1px solid #fa8c16;
+      font-size: 12px;
+      line-height: 1.5;
+    }
+  }
+
+  .prescription-tables {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    margin-bottom: 16px;
+  }
+}
+</style>

+ 310 - 0
src/views/patients/enteralNutrition/components/RightCard.vue

@@ -0,0 +1,310 @@
+<template>
+  <el-card class="right-card">
+    <div class="card-header">
+      <span>营养数据分析</span>
+      <el-button link>收起</el-button>
+    </div>
+    <div class="nutrition-analysis">
+      <!-- 营养设定 -->
+      <div class="nutrition-setting">
+        <span>营养设定:</span>
+        <span class="value">897.3kcal/d</span>
+      </div>
+
+      <!-- 三大营养素表格 -->
+      <div class="nutrition-table">
+        <el-table :data="nutritionData" border size="small">
+          <el-table-column prop="name" label="三大营养素" align="center" />
+          <el-table-column prop="weight" label="质量(g)" align="center" />
+          <el-table-column prop="ratio" label="热量占比" align="center">
+            <template #default="{row}">{{ row.ratio }}%</template>
+          </el-table-column>
+          <el-table-column prop="reference" label="参考值" align="center" />
+        </el-table>
+        <div class="total-amount">
+          <span>含量:</span>
+          <span class="value">7.624g/天</span>
+        </div>
+      </div>
+
+      <!-- 营养素占比图表 -->
+      <div class="nutrition-chart">
+        <div class="chart-title">三大营养元素质量占比</div>
+        <div class="chart-content">
+          <div ref="chartRef" class="pie-chart"></div>
+          <div class="chart-legend">
+            <div class="legend-item">
+              <span class="color-block protein"></span>
+              <span>蛋白质</span>
+              <span class="percentage">44.12%</span>
+            </div>
+            <div class="legend-item">
+              <span class="color-block fat"></span>
+              <span>脂肪</span>
+              <span class="percentage">23.66%</span>
+            </div>
+            <div class="legend-item">
+              <span class="color-block carbs"></span>
+              <span>碳水化合物</span>
+              <span class="percentage">32.22%</span>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 产品列表 -->
+      <div class="product-list">
+        <el-table :data="productData" border size="small">
+          <el-table-column prop="name" label="产品名称" min-width="180" />
+          <el-table-column prop="code" label="商品编码" width="120" align="center" />
+          <el-table-column prop="type" label="产品" width="80" align="center" />
+        </el-table>
+      </div>
+    </div>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import {ref, onMounted} from 'vue';
+import * as echarts from 'echarts';
+
+// 图表相关
+const chartRef = ref<HTMLElement | null>(null);
+let myChart: echarts.ECharts | null = null;
+
+// 营养分析数据
+const nutritionData = ref([
+  {name: '蛋白质', weight: '12.7505', ratio: '34.00', reference: '10%~20%'},
+  {name: '蛋白质', weight: '12.7505', ratio: '34.00', reference: '10%~20%'},
+  {name: '蛋白质', weight: '12.7505', ratio: '34.00', reference: '10%~20%'}
+]);
+
+// 产品列表数据
+const productData = ref([
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'},
+  {name: '复合矿物质210463A', code: 'T2463098', type: '肠内'}
+]);
+
+// 初始化图表
+const initChart = () => {
+  if (!chartRef.value) return;
+
+  myChart = echarts.init(chartRef.value);
+  const option = {
+    tooltip: {
+      show: false
+    },
+    legend: {
+      show: false
+    },
+    color: ['#4B6EFF', '#8592A6', '#8CDFFF'],
+    series: [
+      {
+        name: '营养元素',
+        type: 'pie',
+        radius: ['65%', '85%'],
+        center: ['50%', '50%'],
+        startAngle: 90,
+        avoidLabelOverlap: false,
+        silent: true,
+        itemStyle: {
+          borderWidth: 0,
+          borderRadius: 0
+        },
+        label: {
+          show: false
+        },
+        emphasis: {
+          disabled: true
+        },
+        labelLine: {
+          show: false
+        },
+        data: [
+          {value: 44.12, name: '蛋白质'},
+          {value: 23.66, name: '脂肪'},
+          {value: 32.22, name: '碳水化合物'}
+        ]
+      }
+    ]
+  };
+
+  myChart.setOption(option);
+};
+
+onMounted(() => {
+  initChart();
+  window.addEventListener('resize', () => {
+    myChart?.resize();
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+.right-card {
+  width: 400px;
+
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16px;
+    padding: 0 4px;
+
+    span {
+      font-size: 16px;
+      font-weight: 500;
+      color: #303133;
+    }
+  }
+
+  .nutrition-analysis {
+    .nutrition-setting {
+      background: #fff;
+      padding: 12px;
+      margin-bottom: 16px;
+      border-radius: 4px;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #606266;
+
+      .value {
+        color: var(--el-color-primary);
+        font-weight: 500;
+      }
+    }
+
+    .nutrition-table {
+      margin-bottom: 16px;
+
+      :deep(.el-table) {
+        margin-bottom: 8px;
+
+        th {
+          background-color: #f5f7fa;
+          color: #606266;
+          font-weight: 500;
+          padding: 8px 0;
+        }
+
+        td {
+          padding: 8px;
+        }
+      }
+
+      .total-amount {
+        padding: 8px 12px;
+        background: #f5f7fa;
+        color: #606266;
+        font-size: 14px;
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        .value {
+          color: #303133;
+        }
+      }
+    }
+
+    .nutrition-chart {
+      margin-bottom: 16px;
+      background: #fff;
+      border-radius: 4px;
+      border: 1px solid #e4e7ed;
+      overflow: hidden;
+
+      .chart-title {
+        font-size: 14px;
+        color: #303133;
+        text-align: center;
+        padding: 12px 0;
+        background-color: #f5f7fa;
+        border-bottom: 1px solid #e4e7ed;
+        font-weight: 500;
+      }
+
+      .chart-content {
+        display: flex;
+        align-items: center;
+        gap: 32px;
+        padding: 16px;
+        background-color: #fff;
+
+        .pie-chart {
+          flex: none;
+          width: 140px;
+          height: 140px;
+        }
+
+        .chart-legend {
+          flex: 1;
+          min-width: 120px;
+          display: flex;
+          flex-direction: column;
+          gap: 12px;
+
+          .legend-item {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            font-size: 14px;
+            color: #606266;
+            white-space: nowrap;
+
+            .color-block {
+              width: 12px;
+              height: 12px;
+              border-radius: 2px;
+              flex-shrink: 0;
+
+              &.protein {
+                background: #4b6eff;
+              }
+              &.fat {
+                background: #8592a6;
+              }
+              &.carbs {
+                background: #8cdfff;
+              }
+            }
+
+            .percentage {
+              margin-left: 8px;
+              color: #303133;
+              font-weight: 500;
+            }
+          }
+        }
+      }
+    }
+
+    .product-list {
+      :deep(.el-table) {
+        th {
+          background-color: #f5f7fa;
+          color: #606266;
+          font-weight: 500;
+          padding: 8px 0;
+        }
+
+        td {
+          padding: 8px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 178 - 0
src/views/patients/enteralNutrition/components/history/LeftCard.vue

@@ -0,0 +1,178 @@
+<template>
+  <el-card class="left-card">
+    <!-- 搜索框 -->
+    <div class="search-box">
+      <el-input v-model="searchValue" placeholder="请输入处方ID" class="search-input">
+        <template #prefix>
+          <el-icon><Search /></el-icon>
+        </template>
+      </el-input>
+    </div>
+
+    <!-- 处方列表 -->
+    <div class="prescription-list">
+      <div
+        v-for="item in prescriptionList"
+        :key="item.id"
+        :class="['prescription-item', {active: item.id === activeId}]"
+        @click="handleItemClick(item)"
+      >
+        <!-- 时间 -->
+        <div class="item-time">{{ item.time }}</div>
+        <!-- 处方类型 -->
+        <div class="item-type">{{ item.type }}</div>
+        <!-- 处方ID -->
+        <div class="item-id">处方ID:{{ item.id }}</div>
+        <!-- 已编辑角标 -->
+        <div v-if="item.isEdited" class="edit-badge">
+          <span>已编辑</span>
+        </div>
+      </div>
+    </div>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import {ref} from 'vue';
+import {Search} from '@element-plus/icons-vue';
+
+// 搜索值
+const searchValue = ref('');
+
+// 当前选中的处方ID
+const activeId = ref('');
+
+// 处方列表数据
+const prescriptionList = ref([
+  {
+    id: '194705349732148019',
+    time: '2025-07-23 10:57:18',
+    type: '长期处方',
+    isEdited: false
+  },
+  {
+    id: '194754209113291980',
+    time: '2025-07-22 14:19:53',
+    type: '配置处方',
+    isEdited: true
+  },
+  {
+    id: '194753542425735168',
+    time: '2025-07-22 13:53:23',
+    type: '长期处方',
+    isEdited: true
+  },
+  {
+    id: '194746976848480665',
+    time: '2025-07-22 09:32:30',
+    type: '长期处方',
+    isEdited: false
+  },
+  {
+    id: '194746840280684134',
+    time: '2025-07-22 09:27:04',
+    type: '长期处方',
+    isEdited: false
+  },
+  {
+    id: '194746840280681234',
+    time: '2025-07-21 16:28:56',
+    type: '长期处方',
+    isEdited: true
+  }
+]);
+
+// 点击处方项
+const handleItemClick = (item) => {
+  activeId.value = item.id;
+};
+</script>
+
+<style lang="scss" scoped>
+.left-card {
+  width: 300px;
+  height: calc(100vh - 40px);
+
+  :deep(.el-card__body) {
+    height: 100%;
+    padding: 20px;
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+  }
+
+  .search-box {
+    .search-input {
+      .el-input__wrapper {
+        box-shadow: none;
+        border: 1px solid #dcdfe6;
+        border-radius: 4px;
+
+        &:hover {
+          border-color: #c0c4cc;
+        }
+
+        &.is-focus {
+          border-color: var(--el-color-primary);
+        }
+      }
+    }
+  }
+
+  .prescription-list {
+    flex: 1;
+    overflow-y: auto;
+
+    .prescription-item {
+      position: relative;
+      padding: 16px;
+      border-radius: 4px;
+      background: #f5f7fa;
+      cursor: pointer;
+      transition: all 0.3s;
+
+      &:not(:last-child) {
+        margin-bottom: 12px;
+      }
+
+      &:hover {
+        background: #ebeef5;
+      }
+
+      &.active {
+        background: #e6f2ff;
+      }
+
+      .item-time {
+        font-size: 16px;
+        color: #303133;
+        margin-bottom: 8px;
+      }
+
+      .item-type {
+        font-size: 14px;
+        color: #303133;
+        margin-bottom: 4px;
+      }
+
+      .item-id {
+        font-size: 13px;
+        color: #909399;
+      }
+
+      .edit-badge {
+        position: absolute;
+        top: 8px;
+        right: -10px;
+        transform: rotate(35deg);
+        background: #fff;
+        padding: 2px 16px;
+        font-size: 12px;
+        color: #ffa801;
+        border-radius: 2px;
+        white-space: nowrap;
+      }
+    }
+  }
+}
+</style>

+ 658 - 0
src/views/patients/enteralNutrition/components/history/RightCard.vue

@@ -0,0 +1,658 @@
+<template>
+  <el-card class="right-card">
+    <!-- 顶部操作按钮 -->
+    <div class="operation-buttons">
+      <div class="left-buttons">
+        <el-button plain @click="goBack">返回</el-button>
+        <el-button plain>打印</el-button>
+        <el-button type="success" plain>引用处方</el-button>
+        <el-button type="danger" plain>处方作废</el-button>
+      </div>
+      <div class="pay-status">
+        <img src="@/assets/images/pay.png" alt="待支付" />
+      </div>
+    </div>
+
+    <!-- 停嘱日期 -->
+    <div class="stop-date">
+      <span class="label">停嘱日期:</span>
+      <span class="value">2025-07-24</span>
+    </div>
+
+    <!-- 处方表格 -->
+    <div class="prescription-tables">
+      <!-- 营养产品表格 -->
+      <el-table :data="productData" border>
+        <el-table-column type="index" label="组号" width="60" align="center" />
+        <el-table-column label="营养产品" min-width="180" prop="product" />
+        <el-table-column label="用量/次" width="100" align="center">
+          <template #default="{row}">
+            <span>{{ row.dosage }}g</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="餐次时间" width="180" align="center" prop="mealTime" />
+        <el-table-column label="频次" width="100" align="center">
+          <template #default>一天3次</template>
+        </el-table-column>
+        <el-table-column label="首日" width="80" align="center">
+          <template #default="{row}">
+            <span>{{ row.firstDay }}次</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="用量/日" width="100" align="center">
+          <template #default="{row}">
+            <span>{{ row.dailyDosage }}g</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="规格" width="140" align="center">
+          <template #default="{row}">
+            <span>{{ row.specification }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="用法" width="80" align="center" prop="usage" />
+        <el-table-column label="制剂液量/次" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.liquidVolume }}ml</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="制剂浓度/次" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.concentration }}%</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="能量密度/次" width="140" align="center">
+          <template #default="{row}">
+            <span>{{ row.energyDensity }}kcal/ml</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="处方备注" min-width="150" prop="note" />
+        <el-table-column label="每日热量" width="100" align="center">
+          <template #default="{row}">
+            <span>{{ row.dailyCalories }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="金额" width="100" align="right">
+          <template #default="{row}">
+            <span>{{ row.amount }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 耗材表格 -->
+      <el-table :data="materialData" border>
+        <el-table-column type="index" label="组号" width="60" align="center" />
+        <el-table-column label="耗材" min-width="200" />
+        <el-table-column label="规格" width="120" align="center" />
+        <el-table-column label="用量/次" width="100" align="center">
+          <template #default="{row}">
+            <span>{{ row.dosage }}袋</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="频次" width="100" align="center">
+          <template #default>一天3次</template>
+        </el-table-column>
+        <el-table-column label="用量/日" width="100" align="center">
+          <template #default="{row}">
+            <span>{{ row.dailyDosage }}袋</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="首日" width="80" align="center">
+          <template #default="{row}">
+            <span>{{ row.firstDay }}次</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="数量" width="80" align="center">
+          <template #default="{row}">
+            <span>{{ row.quantity }}袋</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="处方备注" min-width="150" />
+        <el-table-column label="金额" width="100" align="right">
+          <template #default="{row}">
+            <span>{{ row.amount }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 费用统计 -->
+      <div class="table-cost">
+        <div class="cost-item">处方费用:¥15.25</div>
+        <div class="cost-item">营养配置费:¥5</div>
+        <div class="cost-item total">总计:¥20.25</div>
+      </div>
+    </div>
+
+    <!-- 分析区域 -->
+    <el-tabs v-model="activeTab" class="analysis-tabs">
+      <el-tab-pane label="三大营养素分析" name="nutrition">
+        <div class="analysis-content">
+          <div class="analysis-data">
+            <div class="data-item">
+              <span class="label">营养设定:</span>
+              <span class="value">897.3kcal/d</span>
+            </div>
+            <div class="data-item">
+              <span class="label">实际热量:</span>
+              <span class="value">12.3000kcal/d</span>
+            </div>
+          </div>
+          <div class="analysis-detail">
+            <!-- 左侧表格 -->
+            <div class="table-container">
+              <el-table :data="nutritionData" border>
+                <el-table-column label="三大营养素" prop="name" width="120" />
+                <el-table-column label="质量 (g)" prop="mass" width="120" align="center" />
+                <el-table-column label="热量占比" prop="ratio" width="120" align="center" />
+                <el-table-column label="参考值" prop="reference" min-width="120" align="center" />
+              </el-table>
+              <div class="extra-info">
+                <div class="info-item">
+                  <span class="label">氮含量:</span>
+                  <span class="value">0.1166 g/天</span>
+                </div>
+                <div class="info-item">
+                  <span class="label">热氮比:</span>
+                  <span class="value">12.3 : 0.1166</span>
+                </div>
+              </div>
+            </div>
+            <!-- 右侧饼图 -->
+            <div class="chart-container">
+              <div class="chart-title">三大营养素元素质量占比</div>
+              <div class="pie-chart" ref="pieChart"></div>
+              <div class="chart-legend">
+                <div class="legend-item">
+                  <span class="color-block" style="background: #36cfc9"></span>
+                  <span class="text">蛋白质 30.41%</span>
+                </div>
+                <div class="legend-item">
+                  <span class="color-block" style="background: #ffd666"></span>
+                  <span class="text">脂肪 16.27%</span>
+                </div>
+                <div class="legend-item">
+                  <span class="color-block" style="background: #2f54eb"></span>
+                  <span class="text">碳水化合物 53.32%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="营养数据分析" name="data">
+        <el-table :data="nutritionAnalysisData" border>
+          <el-table-column label="元素类型" prop="type" width="120" align="center" />
+          <el-table-column label="元素名称" prop="name" width="120" align="center" />
+          <el-table-column label="单位" prop="unit" width="80" align="center" />
+          <el-table-column label="肠内营养含量/天" align="center">
+            <el-table-column label="当前处方" prop="current" width="120" align="center" />
+            <el-table-column label="历史处方" prop="history" width="120" align="center" />
+          </el-table-column>
+          <el-table-column label="肠外营养含量/天" prop="parenteral" width="140" align="center" />
+          <el-table-column label="膳食营养含量/天" prop="dietary" width="140" align="center" />
+          <el-table-column label="营养设定" prop="target" width="120" align="center" />
+        </el-table>
+      </el-tab-pane>
+    </el-tabs>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import {ref, onMounted} from 'vue';
+import * as echarts from 'echarts';
+
+const activeTab = ref('nutrition');
+const pieChart = ref(null);
+
+// 营养产品数据
+const productData = ref([
+  {
+    product: '孕妇营养包(1-12月)',
+    dosage: '1.0000',
+    mealTime: '08:00,12:00,18:00',
+    firstDay: 2,
+    dailyDosage: '3.0000',
+    specification: '840.0000g/袋',
+    usage: '口服',
+    liquidVolume: '100.0000',
+    concentration: '0.9900',
+    energyDensity: '0.0410',
+    note: '--',
+    dailyCalories: '12.3000',
+    amount: '5.25'
+  }
+]);
+
+// 耗材数据
+const materialData = ref([
+  {
+    material: '肠内营养空白合剂',
+    specification: '3g/袋',
+    dosage: '1.0000',
+    dailyDosage: '3.000',
+    firstDay: 2,
+    quantity: '5.0000',
+    amount: '10.00'
+  }
+]);
+
+// 营养素分析数据
+const nutritionData = ref([
+  {
+    name: '蛋白质',
+    mass: '0.729',
+    ratio: '23.71%',
+    reference: '10% - 15%'
+  },
+  {
+    name: '脂肪',
+    mass: '0.39',
+    ratio: '28.54%',
+    reference: '20% - 30%'
+  },
+  {
+    name: '碳水化合物',
+    mass: '1.278',
+    ratio: '41.56%',
+    reference: '50% - 65%'
+  }
+]);
+
+// 营养数据分析数据
+const nutritionAnalysisData = ref([
+  {
+    type: '热能及三大营养素',
+    name: '热量',
+    unit: 'kcal',
+    current: '12.3',
+    history: '12.3',
+    parenteral: '--',
+    dietary: '--',
+    target: '897.3'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '热能',
+    unit: 'kj',
+    current: '51.45',
+    history: '51.45',
+    parenteral: '--',
+    dietary: '--',
+    target: '3754.3'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '碳水化合物',
+    unit: 'g',
+    current: '1.278',
+    history: '1.28',
+    parenteral: '--',
+    dietary: '--',
+    target: '112.16'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '蛋白质',
+    unit: 'g',
+    current: '0.729',
+    history: '0.73',
+    parenteral: '--',
+    dietary: '--',
+    target: '50'
+  },
+  {
+    type: '热能及三大营养素',
+    name: '脂肪',
+    unit: 'g',
+    current: '0.39',
+    history: '0.39',
+    parenteral: '--',
+    dietary: '--',
+    target: '19.94'
+  },
+  {
+    type: '常量元素',
+    name: '钠',
+    unit: 'mg',
+    current: '9',
+    history: '9',
+    parenteral: '--',
+    dietary: '--',
+    target: '1500'
+  },
+  {
+    type: '常量元素',
+    name: '钙',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '800'
+  },
+  {
+    type: '常量元素',
+    name: '磷',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '720'
+  },
+  {
+    type: '常量元素',
+    name: '钾',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '2000'
+  },
+  {
+    type: '常量元素',
+    name: '镁',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '330'
+  },
+  {
+    type: '常量元素',
+    name: '氯',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '2300'
+  },
+  {
+    type: '常量元素',
+    name: '铁',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '20'
+  },
+  {
+    type: '常量元素',
+    name: '锌',
+    unit: 'mg',
+    current: '0',
+    history: '--',
+    parenteral: '--',
+    dietary: '--',
+    target: '7.5'
+  }
+]);
+
+// 初始化饼图
+onMounted(() => {
+  const chart = echarts.init(pieChart.value);
+  const option = {
+    tooltip: {
+      trigger: 'item',
+      formatter: (params) => {
+        return `营养数据分析<br/>${params.marker} ${params.name} ${params.value}`;
+      },
+      backgroundColor: '#fff',
+      borderColor: '#eee',
+      borderWidth: 1,
+      textStyle: {
+        color: '#666'
+      }
+    },
+    series: [
+      {
+        type: 'pie',
+        radius: ['50%', '70%'],
+        center: ['50%', '50%'],
+        avoidLabelOverlap: false,
+        label: {
+          show: false
+        },
+        labelLine: {
+          show: false
+        },
+        emphasis: {
+          scale: false,
+          scaleSize: 0
+        },
+        data: [
+          {
+            value: 30.41,
+            name: '蛋白质',
+            itemStyle: {
+              color: '#36cfc9',
+              borderWidth: 0
+            }
+          },
+          {
+            value: 16.27,
+            name: '脂肪',
+            itemStyle: {
+              color: '#ffd666',
+              borderWidth: 0
+            }
+          },
+          {
+            value: 53.32,
+            name: '碳水化合物',
+            itemStyle: {
+              color: '#2f54eb',
+              borderWidth: 0
+            }
+          }
+        ]
+      }
+    ]
+  };
+  chart.setOption(option);
+
+  // 监听窗口大小变化,重新调整图表大小
+  window.addEventListener('resize', () => {
+    chart.resize();
+  });
+});
+
+
+const emit = defineEmits(['goBack']);
+const goBack = () => {
+  emit('goBack')
+};
+
+</script>
+
+<style lang="scss" scoped>
+.right-card {
+  flex: 1;
+  height: calc(100vh - 40px);
+  overflow-y: auto;
+
+  :deep(.el-card__body) {
+    padding: 20px;
+  }
+
+  .operation-buttons {
+    position: relative;
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    margin-bottom: 20px;
+
+    .left-buttons {
+      display: flex;
+      gap: 12px;
+    }
+
+    .pay-status {
+      position: absolute;
+      top: -10px;
+      right: -10px;
+
+      img {
+        width: 100px;
+        height: auto;
+      }
+    }
+  }
+
+  .stop-date {
+    margin-bottom: 20px;
+    font-size: 14px;
+
+    .label {
+      color: #606266;
+    }
+
+    .value {
+      color: #303133;
+    }
+  }
+
+  .prescription-tables {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    margin-bottom: 30px;
+
+    :deep(.el-table) {
+      .el-table__header th {
+        background-color: #f5f7fa;
+        color: #606266;
+      }
+    }
+
+    .table-cost {
+      display: flex;
+      flex-direction: column;
+      align-items: flex-end;
+      padding: 16px 0;
+      border-bottom: 1px solid #ebeef5;
+
+      .cost-item {
+        line-height: 24px;
+        color: #606266;
+        font-size: 18px;
+
+        &.total {
+          color: #f56c6c;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+
+  .analysis-tabs {
+    margin-bottom: 30px;
+
+    :deep(.el-tabs__header) {
+      margin-bottom: 20px;
+    }
+
+    .analysis-content {
+      .analysis-data {
+        display: flex;
+        gap: 40px;
+        margin-bottom: 20px;
+
+        .data-item {
+          font-size: 14px;
+
+          .label {
+            color: #606266;
+          }
+
+          .value {
+            color: #303133;
+          }
+        }
+      }
+
+      .analysis-detail {
+        display: flex;
+        gap: 40px;
+
+        .table-container {
+          width: 50%;
+
+          .extra-info {
+            margin-top: 16px;
+            display: flex;
+            justify-content: space-between;
+            color: #606266;
+            font-size: 14px;
+
+            .info-item {
+              .value {
+                color: #303133;
+                margin-left: 8px;
+              }
+            }
+          }
+        }
+
+        .chart-container {
+          width: 50%;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          padding-right: 20px;
+
+          .chart-title {
+            font-size: 16px;
+            font-weight: 500;
+            color: #303133;
+            margin-bottom: 20px;
+            text-align: center;
+          }
+
+          .pie-chart {
+            height: 220px;
+            margin-bottom: 20px;
+          }
+
+          .chart-legend {
+            display: flex;
+            justify-content: center;
+            gap: 20px;
+
+            .legend-item {
+              display: flex;
+              align-items: center;
+              gap: 8px;
+
+              .color-block {
+                width: 14px;
+                height: 14px;
+                border-radius: 2px;
+              }
+
+              .text {
+                font-size: 13px;
+                color: #606266;
+                white-space: nowrap;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .footer-cost {
+    display: none;
+  }
+
+  .copyright {
+    text-align: center;
+    color: #909399;
+    font-size: 12px;
+  }
+}
+</style>

+ 635 - 0
src/views/patients/enteralNutrition/components/table/ConfigureTable.vue

@@ -0,0 +1,635 @@
+<template>
+  <div class="nutrition-table">
+    <el-table :data="tableData" border>
+      <el-table-column type="index" label="组号" width="60" align="center" />
+      <el-table-column label="营养产品" min-width="300">
+        <template #default="{row}">
+          <div class="product-group">
+            <div v-for="(product, index) in row.products" :key="index" class="product-row" style="margin-bottom:5px;">
+              <el-select v-model="product.nutritionProductId" placeholder="请选择" @change="changeProductSelect">
+                <el-option v-for="pn in productNutritionList" :key="pn.id" :label="pn.productName"
+                  :value="pn.id+'_'+row.sn+'_'+index"></el-option>
+              </el-select>
+              <div class="action-buttons">
+                <el-button class="icon-btn" @click="addProduct(row)">
+                  <el-icon>
+                    <Plus />
+                  </el-icon>
+                </el-button>
+                <el-button class="icon-btn" @click="removeProduct(row, index)">
+                  <el-icon>
+                    <Delete />
+                  </el-icon>
+                </el-button>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/次" width="150" align="center">
+        <template #default="{row}">
+          <div class="dosage-group">
+            <div v-for="(product, index) in row.products" :key="index" class="dosage-input">
+              <el-input v-model="product.dosePerTime" placeholder="请输入" class="input-center"  
+              @input="dosePerTimeInput(product.dosePerTime,row.sn+'_'+index)"/>
+              <span class="unit">g</span>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="餐次时间" width="500">
+        <template #default="{row}">
+          <div class="time-slots">
+            <div class="time-row">
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[0].checked" @change="changeTimeSelection(row.timeSlots[0].checked,row.sn)"/>
+                <el-time-select v-model="row.timeSlots[0].time" start="00:00" step="00:30" end="23:30"
+                  placeholder="选择时间" :disabled="!row.timeSlots[0].checked" 
+                  />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[1].checked" @change="changeTimeSelection(row.timeSlots[1].checked,row.sn)"/>
+                <el-time-select v-model="row.timeSlots[1].time" start="00:00" step="00:30" end="23:30"
+                  placeholder="选择时间" :disabled="!row.timeSlots[1].checked" 
+                  />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[2].checked" @change="changeTimeSelection(row.timeSlots[2].checked,row.sn)"/>
+                <el-time-select v-model="row.timeSlots[2].time" start="00:00" step="00:30" end="23:30"
+                  placeholder="选择时间" :disabled="!row.timeSlots[2].checked" 
+                  />
+              </div>
+            </div>
+            <div class="time-row">
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[3].checked" @change="changeTimeSelection(row.timeSlots[3].checked,row.sn)"/>
+                <el-time-select v-model="row.timeSlots[3].time" start="00:00" step="00:30" end="23:30"
+                  placeholder="选择时间" :disabled="!row.timeSlots[3].checked" 
+                  />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[4].checked" @change="changeTimeSelection(row.timeSlots[4].checked,row.sn)"/>
+                <el-time-select v-model="row.timeSlots[4].time" start="00:00" step="00:30" end="23:30"
+                  placeholder="选择时间" :disabled="!row.timeSlots[4].checked" 
+                  />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[5].checked" @change="changeTimeSelection(row.timeSlots[5].checked,row.sn)"/>
+                <el-time-select v-model="row.timeSlots[5].time" start="00:00" step="00:30" end="23:30"
+                  placeholder="选择时间" :disabled="!row.timeSlots[5].checked" 
+                  />
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="频次" width="120" align="center">
+        <template #default="{row}">
+          <span>一天{{row.frequency}}次</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="首日" width="150" align="center">
+        <template #default="{row}">
+          <el-input v-model="row.firstDay" @input="firstDayInput(row.firstDay,row.sn)">
+            <template #append>次</template>
+          </el-input>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/日" width="100" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage" v-for="(product, index) in row.products" :key="index">
+            <span>{{product.dosePerDay }}</span>             
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="使用天数" width="200" align="center">
+        <template #default="{row}">
+          <div class="daily-size">
+            <el-input-number v-model="row.usageDays" :min="1" @change="changeUsageDays(row.usageDays,row.sn)"/>
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="用量/总" width="100" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage" v-for="(product, index) in row.products" :key="index">
+            <span>{{product.totalDose }}</span>            
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="规格" width="100" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage" v-for="(product, index) in row.products" :key="index">
+            <span>{{product.specification }}</span>             
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="用法" width="150" align="center">
+        <template #default="{row}">
+          <el-select v-model="row.usage" placeholder="请选择" >
+            <el-option v-for="dict in default_usage" :key="dict.value" :label="dict.label"
+              :value="dict.value"></el-option>
+          </el-select>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="制剂液量/次" width="170" align="center">
+        <template #default="{row}">
+          <el-input v-model="row.preparationVolumePerTime">
+            <template #append>ml</template>
+          </el-input>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="制剂浓度/次" width="100" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage">
+            <span>{{ row.preparationConcentrationPerTime }}</span>
+            <span class="unit">%</span>
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="能量密度/次" width="200" align="center">
+        <template #default="{row}">
+          <el-input v-model="row.energyDensityPerTime">
+            <template #append>kcal/ml</template>
+          </el-input>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="处方备注" width="200" align="center">
+        <template #default="{row}">
+          <template v-for="(product, index) in row.products" >
+            <el-input v-model="product.prescriptionRemark" :maxlength="100" :show-word-limit="true" />
+          </template>          
+        </template>
+      </el-table-column>
+
+      <el-table-column label="每日热量" width="100" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage" v-for="(product, index) in row.products" :key="index">
+            <span>{{product.dailyCalories }}</span>             
+          </div>
+        </template>
+      </el-table-column>
+
+
+      <el-table-column label="金额" width="100" align="center">
+        <template #default="{row}"> 
+          <div class="daily-dosage" v-for="(product, index) in row.products" :key="index">
+            <span>{{product.amount }}</span>
+          </div>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="操作" width="160" align="center" fixed="right">
+        <template #default="{$index}">
+          <div class="operation-cell">
+            <el-button type="primary" link @click="copyRow($index)">复制餐次</el-button>
+            <el-button type="danger" link @click="deleteRow($index)">删除</el-button>
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="table-footer">
+      <el-button type="primary" class="add-prescription-btn" @click="addNewRow">
+        <el-icon>
+          <CirclePlus />
+        </el-icon>
+        开具多处方
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref} from 'vue';
+import {Plus, Delete, CirclePlus} from '@element-plus/icons-vue';
+import { listEnteralNutrition, getEnteralNutrition, delEnteralNutrition, addEnteralNutrition, updateEnteralNutrition } from '@/api/patients/nutrition';
+import { EnteralNutritionVO, EnteralNutritionQuery, EnteralNutritionForm } from '@/api/patients/nutrition/types';
+import { listNutrition, listAllNutrition  } from '@/api/warehouse/productNutrition/index';
+import { NutritionVO, NutritionQuery, NutritionForm } from '@/api/warehouse/productNutrition/types';
+import { it } from 'node:test';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { default_usage } = toRefs < any > (proxy ?.useDict('default_usage'));
+
+let productNutritionList=ref<NutritionVO[]>([]);
+
+const getProductNutritionList = async () => {
+  const res = await listAllNutrition();
+  productNutritionList.value = res.rows;
+}
+
+
+interface TimeSlot {
+  checked: boolean;
+  time: string;
+} 
+
+interface TableRow  extends EnteralNutritionForm {
+  products: EnteralNutritionForm[];
+  timeSlots: TimeSlot[];
+  sn: number;
+}
+
+// 创建默认行数据的函数
+const createDefaultRow = (): TableRow => ({
+  products: [{specification:'g',totalDose:'g',dosePerDay:'g'}],
+  timeSlots: [
+    {checked: true, time: '08:00'},
+    {checked: false, time: '08:30'},
+    {checked: true, time: '12:00'},
+    {checked: false, time: '12:30'},
+    {checked: true, time: '18:00'},
+    {checked: false, time: '18:30'}
+  ],
+  usageDays:1,
+  frequency:3,
+  firstDay:1,
+  sn:0,
+});
+
+const emit = defineEmits(['change']);
+
+// 示例数据
+const tableData = ref<TableRow[]>([createDefaultRow()]);
+
+// 新增行
+const addNewRow = () => {
+  let row: TableRow = createDefaultRow();
+  row.sn = tableData.value.length ;
+  tableData.value.push(row);
+  emit('change',JSON.stringify(tableData.value))
+};
+
+const changeProductSelect = async (id: string) => {
+  let arr=id.split('_');
+  for (let item of productNutritionList.value) {
+    if (item.id.toString() != arr[0]) {
+      continue
+    }
+    
+    let row = tableData.value[Number(arr[1])];
+    let pt = row.products[Number(arr[2])];
+    pt.specification=item.productSpec;
+    pt.dosePerTime=null;     
+    pt.dailyCalories=null;
+    pt.amount=null; 
+    row.usage=item.defaultUsage;
+    pt.totalDose='0'+item.productSpecUnit;
+    pt.dosePerDay='0'+item.productSpecUnit;
+    break;
+  }
+};
+
+// 新增产品输入框
+const addProduct = (row: TableRow) => {
+  row.products.push({});
+};
+
+// 删除产品输入框
+const removeProduct = (row: TableRow, index: number) => {
+  // 如果删除后只剩一个输入框,删除整行
+  if (row.products.length <= 1) {
+    const rowIndex = tableData.value.findIndex((item) => item === row);
+    if (rowIndex !== -1) {
+      tableData.value.splice(rowIndex, 1);
+    }
+  } else {
+    // 否则只删除当前输入框
+    row.products.splice(index, 1);
+  }
+};
+ 
+
+// 复制行
+const copyRow = (index: number) => {
+  const newRow = JSON.parse(JSON.stringify(tableData.value[index]));
+  tableData.value.splice(index + 1, 0, newRow);
+  emit('change',JSON.stringify(tableData.value))
+};
+
+// 删除行
+const deleteRow = (index: number) => {
+  if (tableData.value.length === 1) return;
+  tableData.value.splice(index, 1);
+  emit('change',JSON.stringify(tableData.value))
+};
+ 
+const changeUsageDays = (value: string, sn:string) => { 
+  changeTimeSelection(value,sn);
+  emit('change',JSON.stringify(tableData.value))  
+}
+
+const firstDayInput = (value: string, sn:string) => { 
+  changeTimeSelection(value,sn);  
+  emit('change',JSON.stringify(tableData.value))
+}
+
+const changeTimeSelection = (value: string, sn:string) => {
+  let row = tableData.value[sn];
+  let frequency=0;
+  let oldFrequency=row.frequency;
+  row.timeSlots.forEach(item=>{
+    if(item.checked){
+      frequency++;
+    }
+  })
+  row.frequency=frequency;
+  if(oldFrequency!==frequency){
+    emit('change',JSON.stringify(tableData.value))
+  }
+
+  row.products.forEach(pt => {
+    if (!pt.dosePerTime || pt.dosePerTime.trim().length == 0) {
+      return;
+    }
+    let arr=pt.nutritionProductId.split('_');
+
+    for (let item of productNutritionList.value) {
+    if (item.id.toString() != arr[0]) {
+      continue
+    }    
+    
+    
+    let val=item.calorie*row.frequency*Number(pt.dosePerTime)/100.0
+    pt.dailyCalories=val.toFixed(4);
+
+    val=(row.frequency*(row.usageDays-1)+row.firstDay)*item.configSalePrice*Number(pt.dosePerTime)
+    pt.amount=Math.round(val*100)/100;
+
+    val=(row.frequency*(row.usageDays-1)+row.firstDay)*Number(pt.dosePerTime)
+    pt.totalDose=val.toFixed(4)+item.productSpecUnit;
+
+    val=row.frequency*Number(pt.dosePerTime)
+    pt.dosePerDay=val.toFixed(4)+item.productSpecUnit;
+    break;
+  }
+
+  });  
+};
+
+const dosePerTimeInput = (value: string, str:string) => {
+  let arr=str.split('_');
+  let row = tableData.value[Number(arr[0])];
+  let pt = row.products[Number(arr[1])];
+  if(!pt.dosePerTime||pt.dosePerTime.trim().length==0){
+    pt.dailyCalories=null;
+    pt.amount=null; 
+    return;
+  }
+
+  arr=pt.nutritionProductId.split('_');
+  for (let item of productNutritionList.value) {
+    if (item.id.toString() != arr[0]) {
+      continue
+    }    
+    
+    
+    let val=item.calorie*row.frequency*Number(pt.dosePerTime)/100.0
+    pt.dailyCalories=val.toFixed(4);
+
+    val=(row.frequency*(row.usageDays-1)+row.firstDay)*item.configSalePrice*Number(pt.dosePerTime)
+    pt.amount=Math.round(val*100)/100;
+
+    val=(row.frequency*(row.usageDays-1)+row.firstDay)*Number(pt.dosePerTime)
+    pt.totalDose=val.toFixed(4)+item.productSpecUnit;
+
+    val=row.frequency*Number(pt.dosePerTime)
+    pt.dosePerDay=val.toFixed(4)+item.productSpecUnit;
+    break;
+  }
+};
+
+
+onMounted(() => { 
+  getProductNutritionList();
+});
+
+</script>
+
+<style lang="scss" scoped>
+.nutrition-table {
+  :deep(.el-table) {
+    // 表头样式
+    .el-table__header {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 500;
+        padding: 8px 0;
+        height: 40px;
+      }
+    }
+
+    // 表格行样式
+    .el-table__row {
+      td {
+        padding: 4px 8px;
+      }
+    }
+  }
+
+  // 产品输入框组样式
+  .product-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .product-row {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .el-input {
+        flex: 1;
+      }
+
+      .action-buttons {
+        display: flex;
+        gap: 1px;
+
+        .icon-btn {
+          padding: 6px;
+          height: 32px;
+          border: 1px solid #dcdfe6;
+
+          &:hover {
+            border-color: var(--el-color-primary);
+            color: var(--el-color-primary);
+          }
+
+          .el-icon {
+            font-size: 14px;
+          }
+        }
+      }
+    }
+  }
+
+  // 用量输入框组样式
+  .dosage-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .dosage-input {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 4px;
+
+      .input-center {
+        width: 100px;
+
+        :deep(.el-input__inner) {
+          text-align: center;
+        }
+      }
+
+      .unit {
+        color: #909399;
+        font-size: 14px;
+        flex-shrink: 0;
+      }
+    }
+  }
+
+  // 餐次时间样式
+  .time-slots {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .time-row {
+      display: flex;
+      gap: 8px;
+
+      .time-group {
+        display: flex;
+        align-items: center;
+        gap: 4px;
+
+        :deep(.el-checkbox) {
+          margin-right: 0;
+          .el-checkbox__label {
+            display: none;
+          }
+        }
+
+        :deep(.el-time-select) {
+          .el-input {
+            width: 120px;
+          }
+          .el-input__wrapper {
+            padding: 0 8px;
+            border-radius: 2px;
+            box-shadow: 0 0 0 1px #dcdfe6 inset;
+            &:hover:not(.is-disabled) {
+              box-shadow: 0 0 0 1px #c0c4cc inset;
+            }
+            &.is-disabled {
+              background-color: #f5f7fa;
+              box-shadow: 0 0 0 1px #e4e7ed inset;
+              .el-input__inner {
+                color: #909399;
+                -webkit-text-fill-color: #909399;
+              }
+            }
+          }
+          .el-input__inner {
+            height: 32px;
+            text-align: center;
+            font-size: 14px;
+            color: #606266;
+          }
+        }
+      }
+    }
+  }
+
+  .daily-dosage,
+  .days {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 4px;
+
+    .unit {
+      color: #909399;
+      font-size: 14px;
+    }
+  }
+
+  .operation-cell {
+    display: flex;
+    justify-content: center;
+    gap: 12px;
+
+    .el-button {
+      padding: 4px 8px;
+    }
+  }
+
+  .table-footer {
+    height: 50px;
+    border: 1px solid var(--el-table-border-color);
+    border-top: none;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #f5f7fa;
+
+    .add-prescription-btn {
+      display: flex;
+      align-items: center;
+      gap: 4px;
+      height: 32px;
+      padding: 0 16px;
+      font-size: 14px;
+      background-color: var(--el-color-primary-light-8);
+      color: var(--el-color-primary);
+      border: none;
+
+      &:hover {
+        background-color: var(--el-color-primary-light-9);
+      }
+
+      .el-icon {
+        font-size: 16px;
+      }
+    }
+  }
+
+  .stop-date {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    margin-bottom: 16px;
+
+    .required {
+      color: #f56c6c;
+      font-size: 14px;
+    }
+
+    .label {
+      color: #606266;
+      font-size: 14px;
+    }
+
+    .days {
+      color: #f56c6c;
+      font-size: 14px;
+    }
+  }
+}
+
+
+:deep(.daily-size div) {
+  width: 100px;
+} 
+</style>

+ 422 - 0
src/views/patients/enteralNutrition/components/table/MaterialTable.vue

@@ -0,0 +1,422 @@
+<template>
+  <div class="material-table">
+    <el-table :data="tableData" border :max-height="600">
+      <el-table-column type="index" label="组号" width="60" align="center" />
+      <el-table-column label="耗材" min-width="300">
+        <template #default="{row}">
+          <div class="material-group">
+            <div class="material-row" style="margin-bottom:10px;">
+              <el-select v-model="row.consumableId" placeholder="请选择" @change="changeConsumableSelect">
+                <el-option v-for="pn in suppliesList" :key="pn.id" :label="pn.suppliesName"
+                  :value="pn.id+'_'+row.sn"></el-option>
+              </el-select>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="规格" width="100" align="center">
+        <template #default="{row}">
+          <div class="spec-group">
+            <span>{{ row.specification }}</span>            
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/次" width="200" align="center">
+        <template #default="{row}">
+          <div class="dosage-group">
+            <div class="dosage-input">
+              <el-input v-model="row.dosePerTime" placeholder="请输入" class="input-center" >
+                <template #append>袋</template>
+              </el-input>              
+            </div>             
+          </div>
+        </template>
+      </el-table-column>
+       
+      <el-table-column label="频次" width="100" align="center">
+        <template #default="{row}">
+          <span>一天{{row.frequency}}次</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/日" width="100" align="center">
+        <template #default="{row}">
+          <span>{{ row.dosePerDay }}</span>
+          <span class="unit">袋</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="使用天数" width="100" align="center">
+        <template #default="{row}">
+          <span>{{ row.usageDays }}天</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="首日" width="80" align="center">
+        <template #default="{row}">
+          <span>{{ row.firstDay }}次</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="数量" width="80" align="center">
+        <template #default="{row}">
+          <span>{{ row.quantity }}袋</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="处方备注" width="200" align="center">
+        <template #default="{row}">
+          <el-input v-model="row.prescriptionRemark" :maxlength="100" :show-word-limit="true" />        
+        </template>
+      </el-table-column>
+
+      <el-table-column label="金额" width="80" align="center">
+        <template #default="{row}">
+          <span>{{ row.amount }}</span>
+        </template>
+      </el-table-column>
+
+    </el-table>
+    <div class="table-footer">
+      <div class="left-buttons">
+        <el-button type="primary" plain>登为个人模板</el-button>
+        <el-button type="primary" plain>批量添加营养品</el-button>
+        <el-button type="primary" plain>处方模板</el-button>
+      </div>
+      <div class="right-summary">
+        <div class="summary-list">
+          <div class="summary-item">
+            <span class="label">处方费用:</span>
+            <span class="value">¥0.00</span>
+          </div>
+          <div class="summary-item">
+            <span class="label">营养配置费:</span>
+            <span class="value">¥39.00</span>
+          </div>
+          <div class="summary-item total">
+            <span class="label">总计:</span>
+            <span class="value">¥39.00</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref,defineProps} from 'vue';
+import {  listAll  } from '@/api/warehouse/suppliesManage';
+import { SuppliesManageVO } from '@/api/warehouse/suppliesManage/types';
+import { listNutritionConsumable, getNutritionConsumable, delNutritionConsumable, addNutritionConsumable, updateNutritionConsumable } from '@/api/patients/nutritionConsumable';
+import {NutritionConsumableForm } from '@/api/patients/nutritionConsumable/types';
+import { string } from 'vue-types';
+import { json } from 'stream/consumers';
+
+const emit = defineEmits(['update:modelValue']);
+
+const prop=defineProps({
+  modelValue: {
+    type: String,
+    default: () => undefined
+  },
+});
+
+
+interface TableRow extends NutritionConsumableForm {  
+  sn?: number;   
+}
+
+// 示例数据
+const tableData = ref<TableRow[]>([
+  {           
+    firstDay:1,
+    frequency:3,
+    dosePerTime:1,
+    dosePerDay:3,
+    usageDays:1,
+    quantity:1,
+    sn: 0    
+  }     
+]);
+
+
+let suppliesList=ref<SuppliesManageVO[]>([]);
+ 
+
+const getSuppliesList = async () => {
+  const res = await listAll();
+  suppliesList.value = res.rows;
+}
+
+ 
+
+// 复制行
+const copyRow = (index: number) => {
+  const newRow = JSON.parse(JSON.stringify(tableData.value[index]));
+  tableData.value.splice(index + 1, 0, newRow);
+};
+
+// 删除行
+const deleteRow = (index: number) => {
+  if (tableData.value.length === 1) return;
+  tableData.value.splice(index, 1);
+};
+
+const changeConsumableSelect = async (id: string) => {
+  let arr=id.split('_');
+  for (let item of suppliesList.value) {
+    if (item.id.toString() != arr[0]) {
+      continue
+    }
+    
+    
+    let row = tableData.value[Number(arr[1])];
+    row.specification=item.suppliesSpec;
+    row.amount=item.sellPrice;
+    break;
+  }
+};
+
+
+watch(
+  () => prop.modelValue,
+  async (val: string) => {
+    if(val&&val.trim().length>0){
+      let configData=JSON.parse(val);
+    const tableData = ref<TableRow[]>([]);
+
+    configData.forEach((item:any) => { 
+      let row: TableRow = {        
+        frequency: item.frequency,         
+        usageDays: item.usageDays,
+        firstDay: item.firstDay,
+        sn: tableData.value.length
+      };
+      row.dosePerTime=0;
+
+      tableData.value.push(row);
+    });
+    }
+    
+    console.log(configData, "?????*************????????????????");
+  },
+  { deep: true, immediate: true }
+);
+
+onMounted(() => { 
+  getSuppliesList();  
+});
+
+</script>
+
+<style lang="scss" scoped>
+.material-table {
+  :deep(.el-table) {
+    // 表头样式
+    .el-table__header {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 500;
+        padding: 8px 0;
+        height: 40px;
+      }
+    }
+
+    // 表格行样式
+    .el-table__row {
+      td {
+        padding: 4px 8px;
+      }
+    }
+  }
+
+  // 耗材输入框组样式
+  .material-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .material-row {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .el-input {
+        flex: 1;
+      }
+    }
+  }
+
+  // 规格组样式
+  .spec-group {
+    display: flex;
+    flex-direction: column;
+    gap: 20px;
+    padding: 8px 0;
+
+    span {
+      color: #606266;
+      font-size: 14px;
+    }
+  }
+
+  // 用量输入框组样式
+  .dosage-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .dosage-input {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 4px;
+
+      .input-center {
+        width: 100px;
+
+        :deep(.el-input__inner) {
+          text-align: center;
+        }
+      }
+
+      .unit {
+        color: #909399;
+        font-size: 14px;
+        flex-shrink: 0;
+      }
+    }
+  }
+
+  // 餐次时间样式
+  .time-slots {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .time-row {
+      display: flex;
+      gap: 8px;
+
+      .time-group {
+        display: flex;
+        align-items: center;
+        gap: 4px;
+
+        :deep(.el-checkbox) {
+          margin-right: 0;
+          .el-checkbox__label {
+            display: none;
+          }
+        }
+
+        :deep(.el-time-select) {
+          .el-input {
+            width: 120px;
+          }
+          .el-input__wrapper {
+            padding: 0 8px;
+            border-radius: 2px;
+            box-shadow: 0 0 0 1px #dcdfe6 inset;
+            &:hover:not(.is-disabled) {
+              box-shadow: 0 0 0 1px #c0c4cc inset;
+            }
+            &.is-disabled {
+              background-color: #f5f7fa;
+              box-shadow: 0 0 0 1px #e4e7ed inset;
+              .el-input__inner {
+                color: #909399;
+                -webkit-text-fill-color: #909399;
+              }
+            }
+          }
+          .el-input__inner {
+            height: 32px;
+            text-align: center;
+            font-size: 14px;
+            color: #606266;
+          }
+        }
+      }
+    }
+  }
+
+  // 操作按钮样式
+  :deep(.el-button--link) {
+    height: 28px;
+    padding: 0 8px;
+    font-size: 13px;
+
+    &.el-button--primary {
+      color: var(--el-color-primary);
+      &:hover {
+        color: var(--el-color-primary-light-3);
+      }
+    }
+
+    &.el-button--danger {
+      color: var(--el-color-danger);
+      &:hover {
+        color: var(--el-color-danger-light-3);
+      }
+    }
+  }
+
+  .table-footer {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    margin-top: 16px;
+
+    .left-buttons {
+      display: flex;
+      gap: 12px;
+
+      .el-button {
+        height: 32px;
+        padding: 0 16px;
+        font-size: 14px;
+      }
+    }
+
+    .right-summary {
+      min-width: 200px;
+
+      .summary-list {
+        display: flex;
+        flex-direction: column;
+        align-items: flex-end;
+        gap: 4px;
+
+        .summary-item {
+          display: flex;
+          align-items: center;
+          justify-content: flex-end;
+          gap: 8px;
+          text-align: right;
+
+          .label {
+            font-size: 16px;
+            color: #606266;
+          }
+
+          .value {
+            font-size: 20px;
+            color: #606266;
+            min-width: 80px;
+            text-align: right;
+          }
+
+          &.total {
+            margin-top: 4px;
+
+            .label,
+            .value {
+              color: #f56c6c;
+              font-weight: 500;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 496 - 0
src/views/patients/enteralNutrition/components/table/NutritionTable.vue

@@ -0,0 +1,496 @@
+<template>
+  <div class="nutrition-table">
+    <!-- 停嘱日期 (仅长期医嘱显示) -->
+    <div v-if="type === 'long-term'" class="stop-date">
+      <span class="required">*</span>
+      <span class="label">停嘱日期</span>
+      <el-date-picker v-model="stopDate" type="date" placeholder="请选择" format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
+      <span class="days">(使用天数:0天)</span>
+    </div>
+
+    <el-table :data="tableData" border>
+      <el-table-column type="index" label="组号" width="60" align="center" />
+      <el-table-column label="营养产品" min-width="300">
+        <template #default="{row}">
+          <div class="product-group">
+            <template v-if="!row.isNewRow">
+              <div v-for="(product, index) in row.products" :key="index" class="product-row">
+                <el-input v-model="product.value" placeholder="请输入" />
+                <div class="action-buttons">
+                  <el-button class="icon-btn" @click="addProduct(row)">
+                    <el-icon><Plus /></el-icon>
+                  </el-button>
+                  <el-button class="icon-btn" @click="removeProduct(row, index)">
+                    <el-icon><Delete /></el-icon>
+                  </el-button>
+                </div>
+              </div>
+            </template>
+            <template v-else>
+              <div v-for="(product, index) in row.products" :key="index" class="product-row">
+                <el-input v-model="product.value" placeholder="请选择" />
+                <div class="action-buttons">
+                  <el-button class="icon-btn" @click="addProduct(row)">
+                    <el-icon><Plus /></el-icon>
+                  </el-button>
+                  <el-button class="icon-btn" @click="removeProduct(row, index)">
+                    <el-icon><Delete /></el-icon>
+                  </el-button>
+                </div>
+              </div>
+            </template>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/次" width="150" align="center">
+        <template #default="{row}">
+          <div class="dosage-group">
+            <template v-if="!row.isNewRow">
+              <div v-for="(product, index) in row.products" :key="index" class="dosage-input">
+                <el-input v-model="product.dosage" placeholder="请输入" class="input-center" />
+                <span class="unit">g</span>
+              </div>
+            </template>
+            <template v-else>
+              <div v-for="(product, index) in row.products" :key="index" class="dosage-input">
+                <el-input v-model="product.dosage" placeholder="请输入" class="input-center" />
+                <span class="unit">g</span>
+              </div>
+            </template>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="餐次时间" width="500">
+        <template #default="{row}">
+          <div class="time-slots">
+            <div class="time-row">
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[0].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[0].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[0].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[1].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[1].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[1].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[2].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[2].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[2].checked"
+                />
+              </div>
+            </div>
+            <div class="time-row">
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[3].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[3].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[3].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[4].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[4].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[4].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[5].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[5].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[5].checked"
+                />
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="频次" width="120" align="center">
+        <template #default>
+          <span>一天3次</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/日" width="150" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage">
+            <span>{{ row.dailyDosage }}</span>
+            <span class="unit">袋</span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="使用天数" width="120" align="center">
+        <template #default="{row}">
+          <div class="days">
+            <span>{{ row.days }}</span>
+            <span class="unit">天</span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="160" align="center" fixed="right">
+        <template #default="{$index}">
+          <div class="operation-cell">
+            <el-button type="primary" link @click="copyRow($index)">复制餐次</el-button>
+            <el-button type="danger" link @click="deleteRow($index)">删除</el-button>
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="table-footer">
+      <el-button type="primary" class="add-prescription-btn" @click="addNewRow">
+        <el-icon><CirclePlus /></el-icon>
+        开具多处方
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref, defineProps} from 'vue';
+import {Plus, Delete, CirclePlus} from '@element-plus/icons-vue';
+
+const props = defineProps<{
+  type?: 'normal' | 'long-term';
+}>();
+
+// 停嘱日期
+const stopDate = ref('');
+
+interface TimeSlot {
+  checked: boolean;
+  time: string;
+}
+
+interface Product {
+  value: string;
+  dosage: string;
+}
+
+interface TableRow {
+  products: Product[];
+  timeSlots: TimeSlot[];
+  dailyDosage: number;
+  days: number;
+  isNewRow?: boolean;
+}
+
+// 创建默认行数据的函数
+const createDefaultRow = (isNew: boolean = false): TableRow => ({
+  products: isNew
+    ? [{value: '', dosage: ''}]
+    : [
+        {value: '', dosage: ''},
+        {value: '', dosage: ''},
+        {value: '', dosage: ''}
+      ],
+  timeSlots: [
+    {checked: false, time: '08:00'},
+    {checked: false, time: '08:30'},
+    {checked: false, time: '12:00'},
+    {checked: false, time: '12:30'},
+    {checked: false, time: '18:00'},
+    {checked: false, time: '18:30'}
+  ],
+  dailyDosage: 2.0,
+  days: 1,
+  isNewRow: isNew
+});
+
+// 示例数据
+const tableData = ref<TableRow[]>([createDefaultRow(), createDefaultRow()]);
+
+// 新增行
+const addNewRow = () => {
+  tableData.value.push(createDefaultRow(true));
+};
+
+// 新增产品输入框
+const addProduct = (row: TableRow) => {
+  row.products.push({value: '', dosage: ''});
+};
+
+// 删除产品输入框
+const removeProduct = (row: TableRow, index: number) => {
+  // 如果删除后只剩一个输入框,删除整行
+  if (row.products.length <= 1) {
+    const rowIndex = tableData.value.findIndex((item) => item === row);
+    if (rowIndex !== -1) {
+      tableData.value.splice(rowIndex, 1);
+    }
+  } else {
+    // 否则只删除当前输入框
+    row.products.splice(index, 1);
+  }
+};
+
+// 选择产品
+const selectProduct = (row: TableRow, index: number) => {
+  // TODO: 实现产品选择逻辑
+  console.log('选择产品', row, index);
+};
+
+// 删除产品
+const deleteProduct = (row: TableRow, index: number) => {
+  // TODO: 实现产品删除逻辑
+  console.log('删除产品', row, index);
+};
+
+// 复制行
+const copyRow = (index: number) => {
+  const newRow = JSON.parse(JSON.stringify(tableData.value[index]));
+  tableData.value.splice(index + 1, 0, newRow);
+};
+
+// 删除行
+const deleteRow = (index: number) => {
+  if (tableData.value.length === 1) return;
+  tableData.value.splice(index, 1);
+};
+</script>
+
+<style lang="scss" scoped>
+.nutrition-table {
+  :deep(.el-table) {
+    // 表头样式
+    .el-table__header {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 500;
+        padding: 8px 0;
+        height: 40px;
+      }
+    }
+
+    // 表格行样式
+    .el-table__row {
+      td {
+        padding: 4px 8px;
+      }
+    }
+  }
+
+  // 产品输入框组样式
+  .product-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .product-row {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .el-input {
+        flex: 1;
+      }
+
+      .action-buttons {
+        display: flex;
+        gap: 1px;
+
+        .icon-btn {
+          padding: 6px;
+          height: 32px;
+          border: 1px solid #dcdfe6;
+
+          &:hover {
+            border-color: var(--el-color-primary);
+            color: var(--el-color-primary);
+          }
+
+          .el-icon {
+            font-size: 14px;
+          }
+        }
+      }
+    }
+  }
+
+  // 用量输入框组样式
+  .dosage-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .dosage-input {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 4px;
+
+      .input-center {
+        width: 100px;
+
+        :deep(.el-input__inner) {
+          text-align: center;
+        }
+      }
+
+      .unit {
+        color: #909399;
+        font-size: 14px;
+        flex-shrink: 0;
+      }
+    }
+  }
+
+  // 餐次时间样式
+  .time-slots {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .time-row {
+      display: flex;
+      gap: 8px;
+
+      .time-group {
+        display: flex;
+        align-items: center;
+        gap: 4px;
+
+        :deep(.el-checkbox) {
+          margin-right: 0;
+          .el-checkbox__label {
+            display: none;
+          }
+        }
+
+        :deep(.el-time-select) {
+          .el-input {
+            width: 120px;
+          }
+          .el-input__wrapper {
+            padding: 0 8px;
+            border-radius: 2px;
+            box-shadow: 0 0 0 1px #dcdfe6 inset;
+            &:hover:not(.is-disabled) {
+              box-shadow: 0 0 0 1px #c0c4cc inset;
+            }
+            &.is-disabled {
+              background-color: #f5f7fa;
+              box-shadow: 0 0 0 1px #e4e7ed inset;
+              .el-input__inner {
+                color: #909399;
+                -webkit-text-fill-color: #909399;
+              }
+            }
+          }
+          .el-input__inner {
+            height: 32px;
+            text-align: center;
+            font-size: 14px;
+            color: #606266;
+          }
+        }
+      }
+    }
+  }
+
+  .daily-dosage,
+  .days {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 4px;
+
+    .unit {
+      color: #909399;
+      font-size: 14px;
+    }
+  }
+
+  .operation-cell {
+    display: flex;
+    justify-content: center;
+    gap: 12px;
+
+    .el-button {
+      padding: 4px 8px;
+    }
+  }
+
+  .table-footer {
+    height: 50px;
+    border: 1px solid var(--el-table-border-color);
+    border-top: none;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #f5f7fa;
+
+    .add-prescription-btn {
+      display: flex;
+      align-items: center;
+      gap: 4px;
+      height: 32px;
+      padding: 0 16px;
+      font-size: 14px;
+      background-color: var(--el-color-primary-light-8);
+      color: var(--el-color-primary);
+      border: none;
+
+      &:hover {
+        background-color: var(--el-color-primary-light-9);
+      }
+
+      .el-icon {
+        font-size: 16px;
+      }
+    }
+  }
+
+  .stop-date {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    margin-bottom: 16px;
+
+    .required {
+      color: #f56c6c;
+      font-size: 14px;
+    }
+
+    .label {
+      color: #606266;
+      font-size: 14px;
+    }
+
+    .days {
+      color: #f56c6c;
+      font-size: 14px;
+    }
+  }
+}
+</style>

+ 507 - 0
src/views/patients/enteralNutrition/components/table/PackageTable.vue

@@ -0,0 +1,507 @@
+<template>
+  <div class="package-table">
+    <el-table :data="tableData" border>
+      <el-table-column type="index" label="组号" width="60" align="center" />
+      <el-table-column label="营养产品" min-width="300">
+        <template #default="{row}">
+          <div class="product-group">
+            <div v-for="(product, index) in row.products" :key="index" class="product-row">
+              <el-input v-model="product.value" placeholder="请选择" />
+              <div class="action-buttons">
+                <el-button class="icon-btn" @click="addProduct(row)">
+                  <el-icon><Plus /></el-icon>
+                </el-button>
+                <el-button class="icon-btn" @click="deleteProduct(row, index)">
+                  <el-icon><Delete /></el-icon>
+                </el-button>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="数量" width="150" align="center">
+        <template #default="{row}">
+          <div class="quantity-group">
+            <div v-for="(product, index) in row.products" :key="index" class="quantity-input">
+              <el-input v-model="product.quantity" placeholder="请输入" class="input-center" />
+              <span class="unit">袋</span>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/次" width="150" align="center">
+        <template #default="{row}">
+          <div class="dosage-group">
+            <div v-for="(product, index) in row.products" :key="index" class="dosage-input">
+              <el-input v-model="product.dosage" placeholder="请输入" class="input-center" />
+              <span class="unit">g</span>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="餐次时间" width="500">
+        <template #default="{row}">
+          <div class="time-slots">
+            <div class="time-row">
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[0].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[0].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[0].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[1].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[1].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[1].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[2].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[2].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[2].checked"
+                />
+              </div>
+            </div>
+            <div class="time-row">
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[3].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[3].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[3].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[4].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[4].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[4].checked"
+                />
+              </div>
+              <div class="time-group">
+                <el-checkbox v-model="row.timeSlots[5].checked" />
+                <el-time-select
+                  v-model="row.timeSlots[5].time"
+                  start="06:00"
+                  step="00:30"
+                  end="22:00"
+                  placeholder="选择时间"
+                  :disabled="!row.timeSlots[5].checked"
+                />
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="频次" width="120" align="center">
+        <template #default>
+          <span>一天3次</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="首日" width="100" align="center">
+        <template #default="{row}">
+          <div class="first-day">
+            <el-input-number v-model="row.firstDayTimes" :min="1" :max="10" size="small" controls-position="right" />
+            <span class="unit">次</span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="用量/日" width="100" align="center">
+        <template #default="{row}">
+          <span>{{ row.dailyDosage }}g</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="使用天数" width="120" align="center">
+        <template #default="{row}">
+          <div class="days">
+            <el-input-number v-model="row.days" :min="1" :max="99" size="small" controls-position="right" />
+            <span class="unit">天</span>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="160" align="center" fixed="right">
+        <template #default="{$index}">
+          <div class="operation-cell">
+            <el-button type="primary" link @click="copyRow($index)">复制餐次</el-button>
+            <el-button type="danger" link @click="deleteRow($index)">删除</el-button>
+          </div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 添加营养产品按钮 -->
+    <div class="add-product">
+      <el-button type="primary" class="add-btn" @click="addRow">
+        <el-icon><CirclePlus /></el-icon>
+        添加营养产品
+      </el-button>
+    </div>
+    <!-- 底部按钮和总计 -->
+    <div class="table-footer">
+      <div class="left-buttons">
+        <el-button type="primary" plain>存为个人模板</el-button>
+        <el-button type="primary" plain>批量添加营养品</el-button>
+        <el-button type="primary" plain>处方模板</el-button>
+      </div>
+      <div class="right-summary">
+        <div class="summary-list">
+          <div class="summary-item">
+            <span class="label">处方费用:</span>
+            <span class="value">¥0.00</span>
+          </div>
+          <div class="summary-item total">
+            <span class="label">总计:</span>
+            <span class="value">¥0.00</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref} from 'vue';
+import {Plus, Delete, CirclePlus} from '@element-plus/icons-vue';
+
+interface TimeSlot {
+  checked: boolean;
+  time: string;
+}
+
+interface Product {
+  value: string;
+  quantity: string;
+  dosage: string;
+}
+
+interface TableRow {
+  products: Product[];
+  timeSlots: TimeSlot[];
+  firstDayTimes: number;
+  dailyDosage: number;
+  days: number;
+}
+
+// 创建默认行数据
+const createDefaultRow = (): TableRow => ({
+  products: [
+    {
+      value: '',
+      quantity: '',
+      dosage: ''
+    }
+  ],
+  timeSlots: [
+    {checked: false, time: '08:00'},
+    {checked: false, time: '08:30'},
+    {checked: false, time: '12:00'},
+    {checked: false, time: '12:30'},
+    {checked: false, time: '18:00'},
+    {checked: false, time: '18:30'}
+  ],
+  firstDayTimes: 2,
+  dailyDosage: 2.0,
+  days: 1
+});
+
+// 表格数据
+const tableData = ref<TableRow[]>([createDefaultRow()]);
+
+// 添加产品输入框
+const addProduct = (row: TableRow) => {
+  row.products.push({
+    value: '',
+    quantity: '',
+    dosage: ''
+  });
+};
+
+// 删除产品输入框
+const deleteProduct = (row: TableRow, index: number) => {
+  if (row.products.length <= 1) {
+    // 如果只剩一个输入框,删除整行
+    const rowIndex = tableData.value.findIndex((item) => item === row);
+    if (rowIndex !== -1) {
+      tableData.value.splice(rowIndex, 1);
+    }
+  } else {
+    // 否则只删除当前输入框
+    row.products.splice(index, 1);
+  }
+};
+
+// 复制行
+const copyRow = (index: number) => {
+  const newRow = JSON.parse(JSON.stringify(tableData.value[index]));
+  tableData.value.splice(index + 1, 0, newRow);
+};
+
+// 删除行
+const deleteRow = (index: number) => {
+  if (tableData.value.length === 1) return;
+  tableData.value.splice(index, 1);
+};
+
+// 添加行
+const addRow = () => {
+  tableData.value.push(createDefaultRow());
+};
+</script>
+
+<style lang="scss" scoped>
+.package-table {
+  :deep(.el-table) {
+    .el-table__header {
+      th {
+        background-color: #f5f7fa;
+        color: #606266;
+        font-weight: 500;
+        padding: 8px 0;
+        height: 40px;
+      }
+    }
+
+    .el-table__row {
+      td {
+        padding: 4px 8px;
+      }
+    }
+  }
+
+  .product-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .product-row {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .el-input {
+        flex: 1;
+      }
+
+      .action-buttons {
+        display: flex;
+        gap: 1px;
+
+        .icon-btn {
+          padding: 6px;
+          height: 32px;
+          border: 1px solid #dcdfe6;
+
+          &:hover {
+            border-color: var(--el-color-primary);
+            color: var(--el-color-primary);
+          }
+
+          .el-icon {
+            font-size: 14px;
+          }
+        }
+      }
+    }
+  }
+
+  .quantity-group,
+  .dosage-group {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .quantity-input,
+    .dosage-input {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 4px;
+      height: 32px;
+
+      .input-center {
+        width: 80px;
+
+        :deep(.el-input__inner) {
+          text-align: center;
+        }
+      }
+
+      .unit {
+        color: #909399;
+        font-size: 14px;
+      }
+    }
+  }
+
+  .time-slots {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+
+    .time-row {
+      display: flex;
+      gap: 8px;
+
+      .time-group {
+        display: flex;
+        align-items: center;
+        gap: 4px;
+
+        :deep(.el-checkbox) {
+          margin-right: 0;
+          .el-checkbox__label {
+            display: none;
+          }
+        }
+
+        :deep(.el-time-select) {
+          .el-input {
+            width: 120px;
+          }
+          .el-input__wrapper {
+            padding: 0 8px;
+            border-radius: 2px;
+            box-shadow: 0 0 0 1px #dcdfe6 inset;
+            &:hover:not(.is-disabled) {
+              box-shadow: 0 0 0 1px #c0c4cc inset;
+            }
+            &.is-disabled {
+              background-color: #f5f7fa;
+              box-shadow: 0 0 0 1px #e4e7ed inset;
+              .el-input__inner {
+                color: #909399;
+                -webkit-text-fill-color: #909399;
+              }
+            }
+          }
+          .el-input__inner {
+            height: 32px;
+            text-align: center;
+            font-size: 14px;
+            color: #606266;
+          }
+        }
+      }
+    }
+  }
+
+  .operation-cell {
+    display: flex;
+    justify-content: center;
+    gap: 12px;
+  }
+
+  .add-product {
+    display: flex;
+    justify-content: center;
+    margin-top: 16px;
+    padding: 12px 0;
+    background-color: #f5f7fa;
+    border: 1px solid var(--el-table-border-color);
+    border-top: none;
+
+    .add-btn {
+      display: flex;
+      align-items: center;
+      gap: 4px;
+      height: 32px;
+      padding: 0 16px;
+      font-size: 14px;
+      background-color: var(--el-color-primary-light-8);
+      color: var(--el-color-primary);
+      border: none;
+
+      &:hover {
+        background-color: var(--el-color-primary-light-9);
+      }
+
+      .el-icon {
+        font-size: 16px;
+      }
+    }
+  }
+
+  .table-footer {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    margin-top: 16px;
+    padding: 16px;
+    border: 1px solid var(--el-table-border-color);
+    border-top: 1px solid var(--el-table-border-color);
+
+    .left-buttons {
+      display: flex;
+      gap: 12px;
+
+      .el-button {
+        height: 32px;
+        padding: 0 16px;
+        font-size: 14px;
+      }
+    }
+
+    .right-summary {
+      min-width: 200px;
+
+      .summary-list {
+        display: flex;
+        flex-direction: column;
+        align-items: flex-end;
+        gap: 4px;
+
+        .summary-item {
+          display: flex;
+          align-items: center;
+          justify-content: flex-end;
+          gap: 8px;
+          text-align: right;
+
+          .label {
+            font-size: 16px;
+            color: #606266;
+          }
+
+          .value {
+            font-size: 20px;
+            color: #606266;
+            min-width: 80px;
+            text-align: right;
+          }
+
+          &.total {
+            margin-top: 4px;
+
+            .label,
+            .value {
+              color: #f56c6c;
+              font-weight: 500;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 28 - 0
src/views/patients/enteralNutrition/history.vue

@@ -0,0 +1,28 @@
+<template>
+  <div class="history-container">
+    <LeftCard />
+    <RightCard  @goBack="goBack"/>
+  </div>
+</template>
+
+<script setup lang="ts">
+import LeftCard from './components/history/LeftCard.vue';
+import RightCard from './components/history/RightCard.vue';
+const { patientInfo } = defineProps<{ patientInfo: any }>()
+
+
+const emit = defineEmits(['change']);
+const goBack = () => {
+  emit('change','enteralNutrition')
+};
+
+</script>
+
+<style lang="scss" scoped>
+.history-container {
+  display: flex;
+  gap: 20px;
+  min-height: 100vh;
+  background: #f5f7fa;
+}
+</style>

+ 36 - 0
src/views/patients/enteralNutrition/index.vue

@@ -0,0 +1,36 @@
+<template>
+  <div class="container">
+    <div class="main-content">
+      <!-- 左侧卡片 -->
+      <LeftCard  @gotoTop="goHistoryPrescription"/>
+      <!-- 右侧卡片 -->
+      <RightCard />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import LeftCard from './components/LeftCard.vue';
+import RightCard from './components/RightCard.vue';
+
+// 解决bug核心
+const emit = defineEmits(['change']);
+
+const goHistoryPrescription = () => {
+  emit('change', 'enteralNutritionHistory')
+};
+
+</script>
+
+<style lang="scss" scoped>
+.container {
+  min-height: 100vh;
+  background: #f5f7fa;
+}
+
+.main-content {
+  display: flex;
+  gap: 20px;
+  min-height: calc(100vh - 40px);
+}
+</style>

+ 272 - 54
src/views/patients/evaluation/add.vue

@@ -11,6 +11,41 @@
     </el-card>
 
     <el-card>
+      <!-- 基本信息 -->
+      <template v-if="form.baseInfo">
+        <div style="margin-bottom: 10px; padding-top: 20px;" class="zebra-row">
+          <el-row>
+            <el-col :span="24">
+              <span style="color: #f56c6c; margin-right: 4px;">*</span>
+              <span style="font-weight: bold;">{{'1. '+ form.baseInfo.title }}</span>
+            </el-col>
+          </el-row>
+          <el-row style="margin-bottom: 20px;margin-top: 8px;">
+            <el-col :span="24">
+              <el-form :inline="true" label-width="100px">
+                <template v-for="ctl,n in form.baseInfo.contentList">
+                  <el-form-item :label="ctl.label">
+                    <template v-if="ctl.nameEn=='birthDate'||ctl.nameEn=='admissionDate'">
+                      <el-date-picker v-model="ctl.value" type="date" placeholder="请选择" :disabled="isView"/>
+                    </template>
+                    <template v-else-if="ctl.nameEn=='gender'">
+                      <el-select v-model="ctl.value" placeholder="请选择" :disabled="isView">
+                        <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label"
+                          :value="dict.value"></el-option>
+                      </el-select>
+                    </template>
+                    <template v-else>
+                      <el-input clearable v-model="ctl.value" :disabled="isView" />
+                    </template>
+                  </el-form-item>
+                </template>
+              </el-form>
+            </el-col>
+          </el-row>
+        </div>
+      </template>
+      <!-- 基本信息 -->
+
       <template v-for="item,idx in form.otherInfo">
         <template v-if="item.questionChildType == 'singleChoice'">
           <template v-if="item.arrangement == '2'">
@@ -19,7 +54,7 @@
               <el-row>
                 <el-col :span="24">
                   <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                  <span style="font-weight: bold;">{{ item.title }}</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+item.title}}</span>
                 </el-col>
               </el-row>
               <el-row style="margin-bottom: 20px;">
@@ -27,12 +62,16 @@
                   <div class="radio-card">
                     <el-radio-group v-model="item.value" style="margin-top: 8px;">
                       <template v-for="ctl,i in item.contentList">
-                        <el-radio :label="ctl.label" :value="i" :disabled="isView">
+                        <el-radio :label="ctl.label" :value="i" :disabled="isView"
+                          :style="{'margin-top':ctl.img!=null?'20px':'0px'}">
                           <span class="option-content">
                             <span v-if="ctl.img" class="option-img">
                               <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
                             </span>
                             <span>{{ ctl.label }}</span>
+                            <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                              <el-input v-model="ctl.value" clearable :disabled="isView" />
+                            </span>
                           </span>
                         </el-radio>
                       </template>
@@ -48,7 +87,7 @@
               <el-row>
                 <el-col :span="24">
                   <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                  <span style="font-weight: bold;">{{ item.title }}</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                   <el-radio-group v-model="item.value" class="horizontal-radio-group" style="margin-top: 8px;">
                     <template v-for="ctl,i in item.contentList">
                       <el-radio :label="ctl.label" :value="i" :disabled="isView">
@@ -57,6 +96,9 @@
                             <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
                           </span>
                           <span>{{ ctl.label }}</span>
+                          <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                            <el-input v-model="ctl.value" clearable :disabled="isView" />
+                          </span>
                         </span>
                       </el-radio>
                     </template>
@@ -73,7 +115,7 @@
               <el-row>
                 <el-col :span="24">
                   <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                  <span style="font-weight: bold;">{{ item.title }}</span>
+                  <span style="font-weight: bold;">{{ idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+item.title }}</span>
                 </el-col>
               </el-row>
               <el-row style="margin-bottom: 20px;">
@@ -81,12 +123,16 @@
                   <div class="checkbox-vertical-card">
                     <el-checkbox-group v-model="item.value" style="margin-top: 8px;">
                       <template v-for="ctl,i in item.contentList">
-                        <el-checkbox :label="ctl.label" :value="i" :disabled="isView">
+                        <el-checkbox :label="ctl.label" :value="i" :disabled="isView"
+                          :style="{'margin-top':ctl.img!=null?'20px':'0px'}">
                           <span class="option-content">
                             <span v-if="ctl.img" class="option-img">
                               <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
                             </span>
                             <span>{{ ctl.label }}</span>
+                            <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                              <el-input v-model="ctl.value" clearable :disabled="isView" />
+                            </span>
                           </span>
                         </el-checkbox>
                       </template>
@@ -102,7 +148,7 @@
               <el-row>
                 <el-col :span="24">
                   <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                  <span style="font-weight: bold;">{{ item.title }}</span>
+                  <span style="font-weight: bold;">{{ idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+item.title }}</span>
                   <el-checkbox-group v-model="item.value" class="horizontal-checkbox-group" style="margin-top: 8px;">
                     <template v-for="ctl,i in item.contentList">
                       <el-checkbox :label="ctl.label" :value="i" :disabled="isView">
@@ -111,6 +157,9 @@
                             <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
                           </span>
                           <span>{{ ctl.label }}</span>
+                          <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                            <el-input v-model="ctl.value" clearable :disabled="isView" />
+                          </span>
                         </span>
                       </el-checkbox>
                     </template>
@@ -121,27 +170,25 @@
           </template>
         </template>
 
-
-        <!-- //////////////////////////////////////////////////////////////////// -->
-        <!-- <template v-if="item.questionChildType == 'fillBlanks'">
+        <template v-if="item.questionChildType == 'fillBlanks'">
           <template v-if="item.arrangement == '2'">
             <div style="margin-bottom: 10px; padding-top: 20px;"
               :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
               <el-row>
                 <el-col :span="24">
                   <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                  <span style="font-weight: bold;">{{ item.title }}</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                 </el-col>
               </el-row>
-              <el-row style="margin-bottom: 20px;">
-                <el-col :span="24">
-                  <el-form>
-                    <el-form-item prop="patientNo" label="姓名/门诊号/住院号">
-                      <el-input placeholder="姓名/门诊号/住院号" clearable />
-                    </el-form-item>
-                    <el-form-item prop="patientNo" label="姓名/门诊号/住院号">
-                      <el-input placeholder="姓名/门诊号/住院号" clearable />
-                    </el-form-item>
+              <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                <el-col :span="8">
+                  <el-form label-width="100px">
+                    <template v-for="ctl,n in item.contentList">
+                      <el-form-item :label="ctl.label">
+                        <el-input clearable v-model="ctl.value" :disabled="isView" />
+                        <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
+                      </el-form-item>
+                    </template>
                   </el-form>
                 </el-col>
               </el-row>
@@ -153,32 +200,25 @@
               <el-row>
                 <el-col :span="24">
                   <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                  <span style="font-weight: bold;">{{ item.title }}</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                 </el-col>
               </el-row>
-              <el-row style="margin-bottom: 20px;">
+              <el-row style="margin-bottom: 20px;margin-top: 8px;">
                 <el-col :span="24">
-                  <el-form  :inline="true" label-width="150px">
-                    <el-form-item label="A">
-                      <el-input placeholder="姓名/门诊号/住院号" clearable />
-                    </el-form-item>
-                    <el-form-item label="B">
-                      <el-input placeholder="姓名/门诊号/住院号" clearable />
-                    </el-form-item>
-                    <el-form-item label="C">
-                      <el-input placeholder="姓名/门诊号/住院号" clearable />
-                    </el-form-item>
-                    <el-form-item label="D">
-                      <el-input placeholder="姓名/门诊号/住院号" clearable />
-                    </el-form-item>
+                  <el-form :inline="true" label-width="100px">
+                    <template v-for="ctl,n in item.contentList">
+                      <el-form-item :label="ctl.label">
+                        <el-input clearable v-model="ctl.value" :disabled="isView" />
+                        <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
+                      </el-form-item>
+                    </template>
                   </el-form>
                 </el-col>
               </el-row>
             </div>
           </template>
-        </template> -->
+        </template>
 
-        <!-- //////////////////////////////////////////////////////////////////// -->
 
         <template v-if="item.questionChildType == 'scaleQuestions'">
           <div style="margin-bottom: 10px;  padding-top: 20px;"
@@ -186,11 +226,11 @@
             <el-row>
               <el-col :span="24">
                 <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                <span style="font-weight: bold;">{{ item.title }}</span>
+                <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                 <div style="overflow-x: scroll;margin-top: 8px;margin-left: 30px;">
                   <div class="custom-radio-grid">
                     <div v-for="ctl,n in item.contentList" :key="n" @click="selectScaleQuestions(idx,n)"
-                      :class="['custom-radio-cell', {'is-selected':ctl.value!=null,'cell': item.contentList.length === n+1, 'is-last': n+1 > 1 }]">
+                      :class="['custom-radio-cell', {'my-selected':ctl.value!=null,'cell': item.contentList.length === n+1, 'is-last': n+1 > 1 }]">
                       {{ n+1 }}
                     </div>
                   </div>
@@ -213,7 +253,7 @@
             <el-row>
               <el-col :span="24">
                 <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                <span style="font-weight: bold;">{{ item.title }}</span>
+                <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                 <div style="border-bottom: 1px solid #e5e7eb;width: 98%;margin-left: 30px;">
                   <el-row :gutter="10" class="mb8">
                     <el-col :span="3" style="margin-top: 30px;">
@@ -243,6 +283,11 @@
                           </template>
                         </el-col>
                       </template>
+                      <el-col :span="3" style="margin-top: 10px;">
+                        <span v-if="clt.allowFillBlank">
+                          <el-input v-model="clt.matrixFillBlank" clearable :disabled="isView" />
+                        </span>
+                      </el-col>
                     </el-row>
                   </template>
                 </div>
@@ -251,6 +296,133 @@
           </div>
         </template>
 
+
+        <!-- 其他:人体测量、膳食状况、营养生化检查 -->
+        <template v-if="item.questionChildType == 'anthropometry'">
+          <template v-if="item.lastType == '1'||item.lastType == '3'">
+            <div style="margin-bottom: 10px; padding-top: 20px;"
+              :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+              <el-row>
+                <el-col :span="24">
+                  <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                </el-col>
+              </el-row>
+              <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                <el-col :span="24">
+                  <el-form :inline="true" label-width="120px">
+                    <template v-for="ctl,n in item.contentList">
+                      <el-form-item :label="ctl.label">
+                        <el-input clearable v-model="ctl.value" :disabled="isView" />
+                      </el-form-item>
+                    </template>
+                  </el-form>
+                </el-col>
+              </el-row>
+            </div>
+          </template>
+          <template v-else>
+            <div style="margin-bottom: 10px; padding-top: 20px;"
+              :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+              <el-row>
+                <el-col :span="24">
+                  <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                  <el-radio-group v-model="item.value" class="horizontal-radio-group" style="margin-top: 8px;">
+                    <template v-for="ctl,i in item.contentList">
+                      <el-radio :label="ctl.label" :value="i" :disabled="isView">
+                        <span class="option-content">
+                          <span v-if="ctl.img" class="option-img">
+                            <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
+                          </span>
+                          <span>{{ ctl.label }}</span>
+                          <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                            <el-input v-model="ctl.value" clearable :disabled="isView" />
+                          </span>
+                        </span>
+                      </el-radio>
+                    </template>
+                  </el-radio-group>
+                </el-col>
+              </el-row>
+            </div>
+          </template>
+        </template>
+
+
+        <template v-if="item.questionChildType == 'dietaryStatus'">
+          <template v-if="item.lastType != '2'">
+            <div style="margin-bottom: 10px; padding-top: 20px;"
+              :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+              <el-row>
+                <el-col :span="24">
+                  <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                </el-col>
+              </el-row>
+              <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                <el-col :span="24">
+                  <el-form :inline="true" label-width="120px">
+                    <template v-for="ctl,n in item.contentList">
+                      <el-form-item :label="ctl.label">
+                        <el-input clearable v-model="ctl.value" :disabled="isView" />
+                      </el-form-item>
+                    </template>
+                  </el-form>
+                </el-col>
+              </el-row>
+            </div>
+          </template>
+          <template v-else>
+            <div style="margin-bottom: 10px; padding-top: 20px;"
+              :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+              <el-row>
+                <el-col :span="24">
+                  <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                  <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                  <el-radio-group v-model="item.value" class="horizontal-radio-group" style="margin-top: 8px;">
+                    <template v-for="ctl,i in item.contentList">
+                      <el-radio :label="ctl.label" :value="i" :disabled="isView">
+                        <span class="option-content">
+                          <span v-if="ctl.img" class="option-img">
+                            <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true" />
+                          </span>
+                          <span>{{ ctl.label }}</span>
+                          <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                            <el-input v-model="ctl.value" clearable :disabled="isView" />
+                          </span>
+                        </span>
+                      </el-radio>
+                    </template>
+                  </el-radio-group>
+                </el-col>
+              </el-row>
+            </div>
+          </template>
+        </template>
+
+
+        <template v-if="item.questionChildType == 'nutritionalBiochemical'">
+          <div style="margin-bottom: 10px; padding-top: 20px;"
+            :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+            <el-row>
+              <el-col :span="24">
+                <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+              </el-col>
+            </el-row>
+            <el-row style="margin-bottom: 20px;margin-top: 8px;">
+              <el-col :span="24">
+                <el-form :inline="true" label-width="120px">
+                  <el-form-item :label="item.title">
+                    <el-input clearable v-model="item.value" :disabled="isView" />
+                  </el-form-item>
+                </el-form>
+              </el-col>
+            </el-row>
+          </div>
+        </template>
+        <!-- 其他:人体测量、膳食状况、营养生化检查 -->
       </template>
     </el-card>
 
@@ -273,6 +445,7 @@ import {  getScreeningAssessmentConfig } from '@/api/system/screeningAssessmentC
 import {ScreeningAssessmentConfigForm} from '@/api/system/screeningAssessmentConfig/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
 
 let paramForm = ref<EvaluationForm>({});
  
@@ -312,23 +485,68 @@ const close = async () => {
 
 /** 提交按钮 */
 const submitForm = async () => {
-    for (let i = 0, len = form.value.otherInfo.length; i < len; i++) {
-        let item = form.value.otherInfo[i];
-        if (item.required && (item.value == null || item.value == undefined)) {
-            proxy?.$modal.msgError("请确保必填项(第" + (i + 1) + "题)不为空");
-            return;
-        }
+  if (form.value.baseInfo) {
+    for (let i = 0, len = form.value.baseInfo.contentList.length; i < len; i++) {
+      let item = form.value.baseInfo.contentList[i];       
+      if (item.value == null || item.value == undefined) {        
+        proxy?.$modal.msgError(item.label+"不为空");
+        return;
+      }
     }
+  }
 
-    buttonLoading.value = true;    
-    paramForm.value.content = JSON.stringify(form.value);
-    if (paramForm.value.id) {
-        await updateEvaluation(paramForm.value).finally(() => buttonLoading.value = false);
-    } else {
-        await addEvaluation(paramForm.value).finally(() => buttonLoading.value = false);
+  if (form.value.otherInfo) {
+        for (let i = 0, len = form.value.otherInfo.length; i < len; i++) {
+            let item = form.value.otherInfo[i];
+            if (item.questionType == 'otherInfo') {
+                if (item.questionChildType == 'anthropometry') {
+                    if (item.lastType == '1' || item.lastType == '3') {
+                        for (let k = 0, len = item.contentList.length; k < len; k++) {
+                            if (item.contentList[k].value == null || item.contentList[k].value == undefined) {
+                                proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)[" + item.contentList[k].label + "]不为空");
+                                return;
+                            }
+                        }
+                    } else if (item.value == null || item.value == undefined) {
+                        proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                        return;
+                    }
+                } else if (item.questionChildType == 'dietaryStatus') {
+                    if (item.lastType != '2') {
+                        for (let k = 0, len = item.contentList.length; k < len; k++) {
+                            if (item.contentList[k].value == null || item.contentList[k].value == undefined) {
+                                proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)[" + item.contentList[k].label + "]不为空");
+                                return;
+                            }
+                        }
+                    } else if (item.value == null || item.value == undefined) {
+                        proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                        return;
+                    }
+                } else {
+                    if (item.value == null || item.value == undefined) {
+                        proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                        return;
+                    }
+                }
+            } else {
+                if (item.required && (item.value == null || item.value == undefined)) {
+                    proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                    return;
+                }
+            }
+        }
     }
-    proxy?.$modal.msgSuccess("操作成功");
-    close();
+
+  buttonLoading.value = true;
+  paramForm.value.content = JSON.stringify(form.value);
+  if (paramForm.value.id) {
+    await updateEvaluation(paramForm.value).finally(() => buttonLoading.value = false);
+  } else {
+    await addEvaluation(paramForm.value).finally(() => buttonLoading.value = false);
+  }
+  proxy?.$modal.msgSuccess("操作成功");
+  close();
 }
 
  
@@ -506,7 +724,7 @@ onMounted(() => {
 }
 
 
-.is-selected {
+.my-selected {
   background-color: #ccf0a4;   /* Element Plus 主色 */
   color: #fff;  
   border-radius: 6px;

+ 145 - 127
src/views/patients/medicalRecord/index.vue

@@ -1,90 +1,100 @@
 <template>
-    <div class="app-container">
-        <div class="left-menu">
-            <div class="back-button" @click="goBack">
-                <el-icon>
-                    <ArrowLeft />
-                </el-icon>
-                返回患者列表
-            </div>
-            <el-menu :default-active="activeMenu" class="medical-menu" @select="handleSelect">
-                <el-menu-item index="medicalRecord">
-                    <span>营养病例</span>
-                </el-menu-item>
-                <el-menu-item index="visitRecord">
-                    <span>就诊记录</span>
-                </el-menu-item>
-                <el-menu-item index="checkLabel">
-                    <span>检查指标</span>
-                </el-menu-item>
-                <el-menu-item index="nutritionScreeningAdd" v-show="false">
-                    <span>营养筛查新增</span>
-                </el-menu-item>
-                <el-menu-item index="nutritionScreening">
-                    <span>营养筛查</span>
-                </el-menu-item>
-                <el-menu-item index="nutritionEvaluationAdd" v-show="false">
-                    <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-sub-menu index="nutritionIntervention">
-                    <template #title>营养干预</template>
-                    <el-menu-item index="nutritionSetting">营养设定</el-menu-item>
-                    <el-menu-item index="enteralNutrition">肠内营养</el-menu-item>
-                    <el-menu-item index="parenteralNutrition">肠外营养</el-menu-item>
-                    <el-menu-item index="dietTherapy">膳食治疗</el-menu-item>
-                </el-sub-menu>
-                <el-menu-item index="nutritionMonitor">
-                    <span>营养监测</span>
-                </el-menu-item>
-                <el-menu-item index="nutritionEducation">
-                    <span>营养宣教</span>
-                </el-menu-item>
-            </el-menu>
-            <div class="search-bar">
-                <el-input v-model="searchValue" placeholder="姓名/床号/门诊号" size="small" class="search-input" @keyup.enter="handleSearch" />
-                <el-button size="small" type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
-            </div>
-            <div class="patient-tabs">
-                <el-tabs v-model="patientTab" size="small" stretch @tab-change="handleTabChange">
-                    <el-tab-pane :label="`待诊${waitingCount}`" name="wait" />
-                    <el-tab-pane :label="`诊中${treatingCount}`" name="doing" />
-                    <el-tab-pane :label="`已诊${treatedCount}`" name="done" />
-                </el-tabs>
-            </div>
-            <div class="patient-table">
-                <el-table :data="patientList" border size="small" height="80%" :show-header="true" class="table-patients" :row-class-name="tableRowClassName" @row-dblclick="handleRowClick">
-                    <el-table-column prop="name" label="姓名" width="60" />
-                    <el-table-column prop="gender" label="性别" width="50" />
-                    <el-table-column prop="age" label="年龄" width="80" />
-                </el-table>
-            </div>
-            <div class="nav-btns">
-                <el-button size="small" @click="handlePrev">上一位</el-button>
-                <el-button size="small" type="primary" @click="handleNext">下一位</el-button>
-            </div>
+  <div class="app-container">
+    <div class="left-menu">
+      <div class="back-button" @click="goBack">
+        <el-icon>
+          <ArrowLeft />
+        </el-icon>
+        返回患者列表
+      </div>
+      <el-menu :default-active="activeMenu" class="medical-menu" @select="handleSelect">
+        <el-menu-item index="medicalRecord">
+          <span>营养病例</span>
+        </el-menu-item>
+        <el-menu-item index="visitRecord">
+          <span>就诊记录</span>
+        </el-menu-item>
+        <el-menu-item index="checkLabel">
+          <span>检查指标</span>
+        </el-menu-item>
+        <el-menu-item index="nutritionScreeningAdd" v-show="false">
+          <span>营养筛查新增</span>
+        </el-menu-item>
+        <el-menu-item index="nutritionScreening">
+          <span>营养筛查</span>
+        </el-menu-item>
+        <el-menu-item index="nutritionEvaluationAdd" v-show="false">
+          <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-sub-menu index="nutritionIntervention">
+          <template #title>营养干预</template>
+          <el-menu-item index="nutritionSetting">营养设定</el-menu-item>
+          <el-menu-item index="enteralNutrition">肠内营养</el-menu-item>
+         <el-menu-item index="enteralNutritionHistory" v-show="false">肠内营养历史处方</el-menu-item>
+          <el-menu-item index="parenteralNutrition">肠外营养</el-menu-item>
+          <el-menu-item index="dietTherapy">膳食治疗</el-menu-item>
+        </el-sub-menu>
+        <el-menu-item index="nutritionMonitor">
+          <span>营养监测</span>
+        </el-menu-item>
+        <el-menu-item index="nutritionEducation">
+          <span>营养宣教</span>
+        </el-menu-item>
+      </el-menu>
+      <div class="search-bar">
+        <el-input v-model="searchValue" placeholder="姓名/床号/门诊号" size="small" class="search-input" @keyup.enter="handleSearch" />
+        <el-button size="small" type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
+      </div>
+      <div class="patient-tabs">
+        <el-tabs v-model="patientTab" size="small" stretch @tab-change="handleTabChange">
+          <el-tab-pane :label="`待诊${waitingCount}`" name="wait" />
+          <el-tab-pane :label="`诊中${treatingCount}`" name="doing" />
+          <el-tab-pane :label="`已诊${treatedCount}`" name="done" />
+        </el-tabs>
+      </div>
+      <div class="patient-table">
+        <el-table
+          :data="patientList"
+          border
+          size="small"
+          height="80%"
+          :show-header="true"
+          class="table-patients"
+          :row-class-name="tableRowClassName"
+          @row-dblclick="handleRowClick"
+        >
+          <el-table-column prop="name" label="姓名" width="60" />
+          <el-table-column prop="gender" label="性别" width="50" />
+          <el-table-column prop="age" label="年龄" width="80" />
+        </el-table>
+      </div>
+      <div class="nav-btns">
+        <el-button size="small" @click="handlePrev">上一位</el-button>
+        <el-button size="small" type="primary" @click="handleNext">下一位</el-button>
+      </div>
+    </div>
+    <div class="main-content">
+      <el-row>
+        <div class="patient-left-info">
+          <el-row class="info-row">
+            <span class="name">{{ patientInfo.name }}</span>
+            <span class="age">{{ patientInfo.age }}</span>
+            <span class="gender-icon" :class="patientInfo.gender === '男' ? 'male' : 'female'">
+              {{ patientInfo.gender === '男' ? '♂' : '♀' }}
+            </span>
+          </el-row>
+          <el-row style="margin-top: 10px; margin-left: 10%">
+            <el-button size="small" @click="handleEdit">编辑</el-button>
+            <el-button size="small" type="primary" @click="handleDetail">详情</el-button>
+          </el-row>
         </div>
-        <div class="main-content">
-            <el-row>
-                <div class="patient-left-info">
-                    <el-row class="info-row">
-                        <span class="name">{{ patientInfo.name }}</span>
-                        <span class="age">{{ patientInfo.age }}</span>
-                        <span class="gender-icon" :class="patientInfo.gender === '男' ? 'male' : 'female'">
-                            {{ patientInfo.gender === '男' ? '♂' : '♀' }}
-                        </span>
-                    </el-row>
-                    <el-row style="margin-top: 10px; margin-left: 10%">
-                        <el-button size="small" @click="handleEdit">编辑</el-button>
-                        <el-button size="small" type="primary" @click="handleDetail">详情</el-button>
-                    </el-row>
-                </div>
-                <div class="patient-right-info">
+        <div class="patient-right-info">
                     <el-row>
                         <span>门诊号:{{ patientInfo.outpatientNo }}</span>
                         <span style="margin-left: 30px">科室:{{ patientInfo.deptName }}</span>
@@ -99,9 +109,9 @@
                         </el-tooltip>
                     </el-row>
                 </div>
-            </el-row>
-            <component :is="currentComponent" v-if="currentComponent" :patient-info="patientInfo" @change="handleSelect" />
-        </div>
+      </el-row>
+      <component :is="currentComponent" v-if="currentComponent" :patient-info="patientInfo" @change="handleSelect" />
+    </div>
 
         <!-- 患者详情弹窗 -->
         <DetailDialog v-model:visible="showDetailDialog" :detail-data="detailData" :physical-activity-dict="physicalActivityDict" @close="handleDetailClose" />
@@ -123,34 +133,40 @@
     import { useNutritionDiagnosisStore } from '@/store/modules/diagnosis';
     const useStore = useNutritionDiagnosisStore();
 
-    // 动态导入组件
-    const MedicalRecord = defineAsyncComponent(() => import('./levelMenu.vue'));
-    const NutritionScreening = defineAsyncComponent(() => import('@/views/patients/screening/index.vue'));
-    const NutritionEvaluation = defineAsyncComponent(() => import('@/views/patients/evaluation/index.vue'));
-    const NutriDiagnosis = defineAsyncComponent(() => import('@/views/patients/nutriDiagnosis/index.vue'));
-    const CheckLabel = defineAsyncComponent(() => import('@/views/patients/checkLabel/index.vue'));
-    const NutritionScreeningAdd = defineAsyncComponent(() => import('@/views/patients/screening/add.vue'));
-    const NutritionEvaluationAdd = defineAsyncComponent(() => import('@/views/patients/evaluation/add.vue'));
-    const NutritionEducation = defineAsyncComponent(() => import('@/views/patients/nutritionEducation/index.vue'));
-    const NutritionSetting = defineAsyncComponent(() => import('@/views/patients/nutritionSetting/index.vue'));
-    const DietTherapy = defineAsyncComponent(() => import('@/views/patients/dietTherapy/index.vue'));
-
-    const componentMap = {
-        medicalRecord: MedicalRecord,
-        checkLabel: CheckLabel,
-        nutritionDiagnosis: NutriDiagnosis,
-        nutritionScreening: NutritionScreening,
-        nutritionScreeningAdd: NutritionScreeningAdd,
-        nutritionEvaluation: NutritionEvaluation,
-        nutritionEvaluationAdd: NutritionEvaluationAdd,
-        nutritionEducation: NutritionEducation,
-        nutritionSetting: NutritionSetting,
-        dietTherapy: DietTherapy
-    };
-    const currentComponent = ref(componentMap['medicalRecord']);
-    const route = useRoute();
-    const router = useRouter();
-    const { proxy } = getCurrentInstance() as any;
+// 动态导入组件
+const MedicalRecord = defineAsyncComponent(() => import('./levelMenu.vue'));
+const NutritionScreening = defineAsyncComponent(() => import('@/views/patients/screening/index.vue'));
+const NutritionEvaluation = defineAsyncComponent(() => import('@/views/patients/evaluation/index.vue'));
+const NutriDiagnosis = defineAsyncComponent(() => import('@/views/patients/nutriDiagnosis/index.vue'));
+const CheckLabel = defineAsyncComponent(() => import('@/views/patients/checkLabel/index.vue'));
+const NutritionScreeningAdd = defineAsyncComponent(() => import('@/views/patients/screening/add.vue'));
+const NutritionEvaluationAdd = defineAsyncComponent(() => import('@/views/patients/evaluation/add.vue'));
+const NutritionEducation = defineAsyncComponent(() => import('@/views/patients/nutritionEducation/index.vue'));
+const NutritionSetting = defineAsyncComponent(() => import('@/views/patients/nutritionSetting/index.vue'));
+const DietTherapy = defineAsyncComponent(() => import('@/views/patients/dietTherapy/index.vue'));
+const ParenteralNutrition = defineAsyncComponent(() => import('@/views/patients/parenteralNutrition/index.vue'));
+const EnteralNutrition = defineAsyncComponent(() => import('@/views/patients/enteralNutrition/index.vue'));
+const EnteralNutritionHistory = defineAsyncComponent(() => import('@/views/patients/enteralNutrition/history.vue'));  
+
+const componentMap = {
+  medicalRecord: MedicalRecord,
+  checkLabel: CheckLabel,
+  nutritionDiagnosis: NutriDiagnosis,
+  nutritionScreening: NutritionScreening,
+  nutritionScreeningAdd: NutritionScreeningAdd,
+  nutritionEvaluation: NutritionEvaluation,
+  nutritionEvaluationAdd: NutritionEvaluationAdd,
+  nutritionEducation: NutritionEducation,
+  nutritionSetting: NutritionSetting,
+  dietTherapy: DietTherapy,
+  parenteralNutrition: ParenteralNutrition,
+  enteralNutrition: EnteralNutrition,
+  enteralNutritionHistory: EnteralNutritionHistory,
+};
+const currentComponent = ref(componentMap['medicalRecord']);
+const route = useRoute();
+const router = useRouter();
+const {proxy} = getCurrentInstance() as any;
 
     const activeMenu = ref('medicalRecord');
 
@@ -180,17 +196,19 @@
     const showEditDialog = ref(false);
     const editData = ref({} as any);
 
-    const handleSelect = (key: string, other ? : string[]) => {
-        if (key == 'nutritionScreeningAdd' || key == 'nutritionEvaluationAdd') {
-            activeMenu.value = key.replace('Add', '');
-        } else {
-            activeMenu.value = key;
-        }
-        currentComponent.value = componentMap[key] || null;
-        patientInfo.value['other'] = other;
-        patientInfo.value.type = route.query.type;
-        patientInfo.value.outpatientNo = route.query.outpatientNo;
-    };
+const handleSelect = (key: string, other?: string[]) => {
+  if (key == 'nutritionScreeningAdd' || key == 'nutritionEvaluationAdd') {
+    activeMenu.value = key.replace('Add', '');
+  } if(key=='enteralNutritionHistory'){            
+            activeMenu.value = key.replace('History',''); 
+  }else {
+    activeMenu.value = key;
+  }
+  currentComponent.value = componentMap[key] || null;
+  patientInfo.value['other'] = other;
+  patientInfo.value.type = route.query.type;
+  patientInfo.value.outpatientNo = route.query.outpatientNo;
+};
 
     const goBack = () => {
         router.back();

+ 242 - 0
src/views/patients/parenteralNutrition/index.vue

@@ -0,0 +1,242 @@
+<template>
+  <div class="p-2">
+    <el-container class="layout-container-demo" style="height: 100vh; min-height: 100vh;">
+      <el-aside id="leftPanel"
+        style="background:transparent; width: 370px;flex: 0 0 auto; border-right: 2px solid #e4e7ed;">
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+          <el-form-item label="开方日期" id="dateRangeEl">
+            <el-date-picker v-model="queryParams.screeningTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
+              range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+              :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]">
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item id="doctorNameEl">
+            <el-input v-model="queryParams.patientNo" placeholder="医生姓名" clearable />
+          </el-form-item>
+
+          <el-form-item id="buttonEl">
+            <el-button type="primary" @click="handleQuery">搜索</el-button>
+            <el-button @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </el-aside>
+
+      <el-container>
+        <el-main style="padding-left: 20px;">
+          <div>
+            <el-table v-loading="loading" border :data="dataList">
+              <el-table-column label="时间" align="center" prop="screeningTime" />
+              <el-table-column label="看诊类型" align="center" prop="visitType" />
+              <el-table-column label="门诊/住院号" align="center" prop="patientNo" />
+              <el-table-column label="营养筛查类型" align="center" prop="configName" />
+              <el-table-column label="营养筛查分数" align="center" prop="screeningScore" />
+            </el-table>
+
+            <!-- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+              v-model:limit="queryParams.pageSize" @pagination="getList" /> -->
+          </div>
+
+          <div>
+            <div class="p-2">
+              <el-menu class="el-menu-demo" mode="horizontal" @select="handleMenumSelect"
+                :default-active="currentIndex">
+                <el-menu-item index="1">三大营养素分析</el-menu-item>
+                <el-menu-item index="2">营养数据分析</el-menu-item>
+              </el-menu>
+            </div>
+
+            <el-row :gutter="10" class="mb8" v-show="leftIndex == currentIndex" style="margin: 0px;">
+              <el-col :span="13">
+                <div style="margin-top: 20px;margin-bottom: 20px;">医嘱总热量/天:--</div>
+                <div>
+                  <el-table border stripe :data="leftList">
+                    <el-table-column label="元素名称" align="center" prop="nutrientName" />
+                    <el-table-column label="单位" align="center" prop="nutrientQuantity">
+                      <template #default="scope">
+                        {{ scope.row.nutrientQuantity.toFixed(4) }}
+                      </template>
+                    </el-table-column>
+                    <el-table-column label="肠外营养含量/天" align="center" prop="nutrientRefVal" />
+                    <el-table-column label="热量占比" align="center" prop="nutrientRatio" />                    
+                  </el-table>
+                </div>
+                <div style="margin-top: 20px;margin-bottom: 20px;text-align: right;">热氮比:--</div>
+              </el-col>
+              <el-col :span="10" align="center">
+                <div style="height: 300px;">
+                  <v-chart :option="pieOption" style="width: 400px; height: 200px;" class="chart-center" />
+                </div>
+              </el-col>
+            </el-row>
+
+            <el-row :gutter="10" class="mb8" v-show="rightIndex == currentIndex">
+              <el-col :span="24">
+                <div style="height: 400px;overflow-y: scroll;">
+                  <el-table border stripe :data="rightList">
+                    <el-table-column label="元素类型" align="center" prop="nutrientName" />
+                    <el-table-column label="元素名称" align="center" prop="nutrientUnit" />
+                    <el-table-column label="单位" align="center" prop="nutrientQuantity" />
+                    <el-table-column label="肠外营养含量/天" align="center" prop="nutrientQuantity" />
+                  </el-table>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+        </el-main>
+      </el-container> 
+    </el-container>
+  </div>
+</template>
+
+<script setup name="ScreeningAssessmentConfig" lang="ts">
+import { ref, onMounted } from 'vue';
+import { listScreening  } from '@/api/patients/screening';
+import {   ScreeningQuery  } from '@/api/patients/screening/types';
+import { FoodIngredientVO   } from '@/api/system/foodIngredient/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const emit = defineEmits(['change']);
+
+const dataList = ref([{
+  screeningTime: '',
+  visitType: '',
+  patientNo: '',
+  configName: '',
+  screeningScore: ''
+}]);
+
+const loading = ref(true); 
+const total = ref(0);
+
+const leftList = ref<FoodIngredientVO[]>([]);
+const leftCalories = ref<number>(0.0);
+const rightList = ref<FoodIngredientVO[]>([]);
+
+const leftIndex = ref('1')
+const rightIndex = ref('2')
+const currentIndex = ref('1')
+
+const pieOption = ref({
+  legend: {
+    orient: 'horizontal',
+    bottom: 'bottom',
+    data: ['蛋白质 30%', '脂肪 20%', '碳水化合物 50%']
+  },
+  title: {
+    text: '三大营养素元素质量占比',
+    left: 'center'
+  },
+  series: [
+    {
+      type: 'pie',
+      radius: ['50%', '70%'],
+      avoidLabelOverlap: false,
+      label: {
+        show: false,
+        position: 'center'
+      },
+      labelLine: {
+        show: false
+      },
+      emphasis: {
+        label: {
+          show: true,
+          fontSize: '30',
+          fontWeight: 'bold'
+        }
+      },
+      data: [
+        { value: 30, name: '蛋白质 30%' },
+        { value: 20, name: '脂肪 20%' },
+        { value: 50, name: '碳水化合物 50%' },
+      ]
+    }
+  ]
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const queryParams = ref<ScreeningQuery>(
+  {
+    pageNum: 1,
+    pageSize: 3,
+    patientNo: undefined,
+    screeningTime: undefined,
+    // orderTime: undefined,
+    // doctorName: undefined,     
+  }
+);
+
+const handleMenumSelect = async (key: string, keyPath: string[]) => {
+  currentIndex.value = key.toString()
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;   
+  getList();
+}
+
+const getList = async () => {
+  loading.value = true;    
+  queryParams.value.patientId= '1937770358913093633'; 
+  const res = await listScreening(queryParams.value);
+  dataList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+ 
+onMounted(() => {
+  getList();
+});
+
+ 
+</script>
+
+<style scoped>
+.layout-container-demo .el-header {
+  position: relative;
+  background-color: var(--el-color-primary-light-7);
+  color: var(--el-text-color-primary);
+}
+
+.layout-container-demo .el-aside {
+  color: var(--el-text-color-primary);
+  background: var(--el-color-primary-light-8);
+}
+
+.layout-container-demo .el-menu {
+  border-right: none;
+}
+
+.layout-container-demo .el-main {
+  padding: 0;
+}
+
+.layout-container-demo .toolbar {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+  right: 20px;
+}
+
+:deep(#dateRangeEl .el-form-item__content) {
+  width: 215px;
+} 
+
+:deep(#doctorNameEl .el-form-item__content) {
+  width: 140px; 
+  margin-right: 0px; 
+} 
+
+:deep(#buttonEl .el-form-item__content) {
+ margin-left:-25px;
+ margin-right: 0px;  
+} 
+</style>

+ 319 - 33
src/views/patients/screening/add.vue

@@ -12,6 +12,41 @@
         </el-card>
 
         <el-card>
+            <!-- 基本信息 -->
+            <template v-if="form.baseInfo">
+                <div style="margin-bottom: 10px; padding-top: 20px;" class="zebra-row">
+                    <el-row>
+                        <el-col :span="24">
+                            <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                            <span style="font-weight: bold;">{{'1. '+  form.baseInfo.title }}</span>
+                        </el-col>
+                    </el-row>
+                    <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                        <el-col :span="24">
+                            <el-form :inline="true" label-width="100px">
+                                <template v-for="ctl,n in form.baseInfo.contentList">
+                                    <el-form-item :label="ctl.label">
+                                        <template v-if="ctl.nameEn=='birthDate'||ctl.nameEn=='admissionDate'">
+                                            <el-date-picker v-model="ctl.value" type="date" placeholder="请选择" :disabled="isView"/>
+                                        </template>
+                                        <template v-else-if="ctl.nameEn=='gender'">
+                                            <el-select v-model="ctl.value" placeholder="请选择" :disabled="isView">
+                                                <el-option v-for="dict in sys_user_sex" :key="dict.value"
+                                                    :label="dict.label" :value="dict.value"></el-option>
+                                            </el-select>
+                                        </template>
+                                        <template v-else>
+                                            <el-input clearable v-model="ctl.value" :disabled="isView" />
+                                        </template>
+                                    </el-form-item>
+                                </template>
+                            </el-form>
+                        </el-col>
+                    </el-row>
+                </div>
+            </template>
+            <!-- 基本信息 -->
+
             <template v-for="item,idx in form.otherInfo">
                 <template v-if="item.questionChildType == 'singleChoice'">
                     <template v-if="item.arrangement == '2'">
@@ -20,7 +55,7 @@
                             <el-row>
                                 <el-col :span="24">
                                     <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                                 </el-col>
                             </el-row>
                             <el-row style="margin-bottom: 20px;">
@@ -35,6 +70,10 @@
                                                                 :disabled="true" />
                                                         </span>
                                                         <span>{{ ctl.label }}</span>
+                                                        <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                                                            <el-input v-model="ctl.value" clearable
+                                                                :disabled="isView" />
+                                                        </span>
                                                     </span>
                                                 </el-radio>
                                             </template>
@@ -50,18 +89,21 @@
                             <el-row>
                                 <el-col :span="24">
                                     <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                                     <el-radio-group v-model="item.value" class="horizontal-radio-group"
                                         style="margin-top: 8px;">
                                         <template v-for="ctl,i in item.contentList">
                                             <el-radio :label="ctl.label" :value="i" :disabled="isView">
                                                 <span class="option-content">
-                                                        <span v-if="ctl.img" class="option-img">
-                                                            <miniImageUpload :limit="1" v-model="ctl.img"
-                                                                :disabled="true" />
-                                                        </span>
-                                                        <span>{{ ctl.label }}</span>
+                                                    <span v-if="ctl.img" class="option-img">
+                                                        <miniImageUpload :limit="1" v-model="ctl.img"
+                                                            :disabled="true" />
                                                     </span>
+                                                    <span>{{ ctl.label }}</span>
+                                                    <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                                                        <el-input v-model="ctl.value" clearable :disabled="isView" />
+                                                    </span>
+                                                </span>
                                             </el-radio>
                                         </template>
                                     </el-radio-group>
@@ -77,7 +119,7 @@
                             <el-row>
                                 <el-col :span="24">
                                     <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                    <span style="font-weight: bold;">{{ idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+item.title }}</span>
                                 </el-col>
                             </el-row>
                             <el-row style="margin-bottom: 20px;">
@@ -92,6 +134,10 @@
                                                                 :disabled="true" />
                                                         </span>
                                                         <span>{{ ctl.label }}</span>
+                                                        <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                                                            <el-input v-model="ctl.value" clearable
+                                                                :disabled="isView" />
+                                                        </span>
                                                     </span>
                                                 </el-checkbox>
                                             </template>
@@ -107,18 +153,21 @@
                             <el-row>
                                 <el-col :span="24">
                                     <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                                    <span style="font-weight: bold;">{{ item.title }}</span>
+                                    <span style="font-weight: bold;">{{ idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+item.title }}</span>
                                     <el-checkbox-group v-model="item.value" class="horizontal-checkbox-group"
                                         style="margin-top: 8px;">
                                         <template v-for="ctl,i in item.contentList">
                                             <el-checkbox :label="ctl.label" :value="i" :disabled="isView">
                                                 <span class="option-content">
-                                                        <span v-if="ctl.img" class="option-img">
-                                                            <miniImageUpload :limit="1" v-model="ctl.img"
-                                                                :disabled="true" />
-                                                        </span>
-                                                        <span>{{ ctl.label }}</span>
+                                                    <span v-if="ctl.img" class="option-img">
+                                                        <miniImageUpload :limit="1" v-model="ctl.img"
+                                                            :disabled="true" />
+                                                    </span>
+                                                    <span>{{ ctl.label }}</span>
+                                                    <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                                                        <el-input v-model="ctl.value" clearable :disabled="isView" />
                                                     </span>
+                                                </span>
                                             </el-checkbox>
                                         </template>
                                     </el-checkbox-group>
@@ -128,18 +177,71 @@
                     </template>
                 </template>
 
+
+                <template v-if="item.questionChildType == 'fillBlanks'">
+                    <template v-if="item.arrangement == '2'">
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                                </el-col>
+                            </el-row>
+                            <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                                <el-col :span="8">
+                                    <el-form label-width="100px">
+                                        <template v-for="ctl,n in item.contentList">
+                                            <el-form-item :label="ctl.label">
+                                                <el-input clearable v-model="ctl.value" :disabled="isView" />
+                                                <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true"
+                                                    v-if="ctl.img" />
+                                            </el-form-item>
+                                        </template>
+                                    </el-form>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                    <template v-else>
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                                </el-col>
+                            </el-row>
+                            <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                                <el-col :span="24">
+                                    <el-form :inline="true" label-width="100px">
+                                        <template v-for="ctl,n in item.contentList">
+                                            <el-form-item :label="ctl.label">
+                                                <el-input clearable v-model="ctl.value" :disabled="isView" />
+                                                <miniImageUpload :limit="1" v-model="ctl.img" :disabled="true"
+                                                    v-if="ctl.img" />
+                                            </el-form-item>
+                                        </template>
+                                    </el-form>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                </template>
+
+
                 <template v-if="item.questionChildType == 'scaleQuestions'">
                     <div style="margin-bottom: 10px;  padding-top: 20px;"
                         :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
                         <el-row>
                             <el-col :span="24">
                                 <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                                <span style="font-weight: bold;">{{ item.title }}</span>
+                                <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                                 <div style="overflow-x: scroll;margin-top: 8px;margin-left: 30px;">
                                     <div class="custom-radio-grid">
                                         <div v-for="ctl,n in item.contentList" :key="n"
                                             @click="selectScaleQuestions(idx,n)"
-                                            :class="['custom-radio-cell', {'is-selected':ctl.value!=null,'cell': item.contentList.length === n+1, 'is-last': n+1 > 1 }]">
+                                            :class="['custom-radio-cell', {'my-selected':ctl.value!=null,'cell': item.contentList.length === n+1, 'is-last': n+1 > 1 }]">
                                             {{ n+1 }}
                                         </div>
                                     </div>
@@ -162,7 +264,7 @@
                         <el-row>
                             <el-col :span="24">
                                 <span style="color: #f56c6c; margin-right: 4px;" v-show="item.required">*</span>
-                                <span style="font-weight: bold;">{{ item.title }}</span>
+                                <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
                                 <div style="border-bottom: 1px solid #e5e7eb;width: 98%;margin-left: 30px;">
                                     <el-row :gutter="10" class="mb8">
                                         <el-col :span="3" style="margin-top: 30px;">
@@ -185,14 +287,18 @@
                                                 </template>
                                             </el-col>
                                             <template v-for="clt2, i2 in item.contentList">
-                                                <el-col :span="1" align="center" style="margin-left: 15px;">
-                                                    <template v-if="clt2.optionFlag && clt.labelFlag">
-                                                        <el-radio-group v-model="clt.value" :disabled="isView">
-                                                            <el-radio :value="(i1+1)*1000+i2" size="large" />
-                                                        </el-radio-group>
-                                                    </template>
+                                                <el-col :span="1" align="center" style="margin-left: 15px;"
+                                                    v-if="clt2.optionFlag && clt.labelFlag">
+                                                    <el-radio-group v-model="clt.value" :disabled="isView">
+                                                        <el-radio :value="(i1 + 1) * 1000 + i2" size="large" />
+                                                    </el-radio-group>
                                                 </el-col>
                                             </template>
+                                            <el-col :span="3" style="margin-top: 10px;">
+                                                <span v-if="clt.allowFillBlank">
+                                                    <el-input v-model="clt.matrixFillBlank" clearable :disabled="isView" />
+                                                </span>
+                                            </el-col>
                                         </el-row>
                                     </template>
                                 </div>
@@ -201,6 +307,137 @@
                     </div>
                 </template>
 
+                <!-- 其他:人体测量、膳食状况、营养生化检查 -->
+                <template v-if="item.questionChildType == 'anthropometry'">
+                    <template v-if="item.lastType == '1'||item.lastType == '3'">
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                                </el-col>
+                            </el-row>
+                            <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                                <el-col :span="24">
+                                    <el-form :inline="true" label-width="120px">
+                                        <template v-for="ctl,n in item.contentList">
+                                            <el-form-item :label="ctl.label">
+                                                <el-input clearable v-model="ctl.value" :disabled="isView" />
+                                            </el-form-item>
+                                        </template>
+                                    </el-form>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                    <template v-else>
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                                    <el-radio-group v-model="item.value" class="horizontal-radio-group"
+                                        style="margin-top: 8px;">
+                                        <template v-for="ctl,i in item.contentList">
+                                            <el-radio :label="ctl.label" :value="i" :disabled="isView">
+                                                <span class="option-content">
+                                                    <span v-if="ctl.img" class="option-img">
+                                                        <miniImageUpload :limit="1" v-model="ctl.img"
+                                                            :disabled="true" />
+                                                    </span>
+                                                    <span>{{ ctl.label }}</span>
+                                                    <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                                                        <el-input v-model="ctl.value" clearable :disabled="isView" />
+                                                    </span>
+                                                </span>
+                                            </el-radio>
+                                        </template>
+                                    </el-radio-group>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                </template>
+
+
+                <template v-if="item.questionChildType == 'dietaryStatus'">
+                    <template v-if="item.lastType != '2'">
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                                </el-col>
+                            </el-row>
+                            <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                                <el-col :span="24">
+                                    <el-form :inline="true" label-width="120px">
+                                        <template v-for="ctl,n in item.contentList">
+                                            <el-form-item :label="ctl.label">
+                                                <el-input clearable v-model="ctl.value" :disabled="isView" />
+                                            </el-form-item>
+                                        </template>
+                                    </el-form>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                    <template v-else>
+                        <div style="margin-bottom: 10px; padding-top: 20px;"
+                            :style="{'border-top':idx==0?'none':'1px dashed #e5e7eb'}" class="zebra-row">
+                            <el-row>
+                                <el-col :span="24">
+                                    <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                    <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                                    <el-radio-group v-model="item.value" class="horizontal-radio-group"
+                                        style="margin-top: 8px;">
+                                        <template v-for="ctl,i in item.contentList">
+                                            <el-radio :label="ctl.label" :value="i" :disabled="isView">
+                                                <span class="option-content">
+                                                    <span v-if="ctl.img" class="option-img">
+                                                        <miniImageUpload :limit="1" v-model="ctl.img"
+                                                            :disabled="true" />
+                                                    </span>
+                                                    <span>{{ ctl.label }}</span>
+                                                    <span v-if="ctl.allowFillBlank" style="margin-left: 10px;">
+                                                        <el-input v-model="ctl.value" clearable :disabled="isView" />
+                                                    </span>
+                                                </span>
+                                            </el-radio>
+                                        </template>
+                                    </el-radio-group>
+                                </el-col>
+                            </el-row>
+                        </div>
+                    </template>
+                </template>
+
+
+                <template v-if="item.questionChildType == 'nutritionalBiochemical'">
+                    <div style="margin-bottom: 10px; padding-top: 20px;"
+                        :style="{ 'border-top': idx == 0 ? 'none' : '1px dashed #e5e7eb' }" class="zebra-row">
+                        <el-row>
+                            <el-col :span="24">
+                                <span style="color: #f56c6c; margin-right: 4px;">*</span>
+                                <span style="font-weight: bold;">{{idx + 1 + (form.baseInfo&&form.baseInfo.contentList&&form.baseInfo.contentList.length>0?1:0) +'. '+ item.title }}</span>
+                            </el-col>
+                        </el-row>
+                        <el-row style="margin-bottom: 20px;margin-top: 8px;">
+                            <el-col :span="24">
+                                <el-form :inline="true" label-width="120px">
+                                    <el-form-item :label="item.title">
+                                        <el-input clearable v-model="item.value" :disabled="isView" />
+                                    </el-form-item>
+                                </el-form>
+                            </el-col>
+                        </el-row>
+                    </div>
+                </template>
+                <!-- 其他:人体测量、膳食状况、营养生化检查 -->
+
             </template>
         </el-card>
 
@@ -224,6 +461,7 @@
   let paramForm = ref<ScreeningForm>({});
 
   const { proxy } = getCurrentInstance() as ComponentInternalInstance; 
+  const { sys_user_sex } = toRefs<any>(proxy?.useDict('sys_user_sex'));
  
   const screeningName = ref(''); 
   const { patientInfo } = defineProps<{ patientInfo: any }>()
@@ -260,15 +498,63 @@ const close = async () => {
   
 /** 提交按钮 */
 const submitForm = async () => {
-    for (let i = 0, len = form.value.otherInfo.length; i < len; i++) {
-        let item = form.value.otherInfo[i];
-        if (item.required && (item.value == null || item.value == undefined)) {
-            proxy?.$modal.msgError("请确保必填项(第" + (i + 1) + "题)不为空");
-            return;
+    if (form.value.baseInfo) {
+        for (let i = 0, len = form.value.baseInfo.contentList.length; i < len; i++) {
+            let item = form.value.baseInfo.contentList[i];
+            if (item.value == null || item.value == undefined) {
+                proxy?.$modal.msgError(item.label + "不为空");
+                return;
+            }
+        }
+    }
+
+    if (form.value.otherInfo) {
+        for (let i = 0, len = form.value.otherInfo.length; i < len; i++) {
+            let item = form.value.otherInfo[i];
+            if (item.questionType == 'otherInfo') {
+                if (item.questionChildType == 'anthropometry') {
+                    if (item.lastType == '1' || item.lastType == '3') {
+                        for (let k = 0, len = item.contentList.length; k < len; k++) {
+                            if (item.contentList[k].value == null || item.contentList[k].value == undefined) {
+                                proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)[" + item.contentList[k].label + "]不为空");
+                                return;
+                            }
+                        }
+                    } else if (item.value == null || item.value == undefined) {
+                        proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                        return;
+                    }
+                } else if (item.questionChildType == 'dietaryStatus') {
+                    if (item.lastType != '2') {
+                        for (let k = 0, len = item.contentList.length; k < len; k++) {
+                            if (item.contentList[k].value == null || item.contentList[k].value == undefined) {
+                                proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)[" + item.contentList[k].label + "]不为空");
+                                return;
+                            }
+                        }
+                    } else if (item.value == null || item.value == undefined) {
+                        proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                        return;
+                    }
+                } else {
+                    if (item.value == null || item.value == undefined) {
+                        proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                        return;
+                    }
+                }
+            } else {
+                if (item.required && (item.value == null || item.value == undefined)) {
+                    proxy?.$modal.msgError("请确保必填项(第" + (i + 1 + (form.value.baseInfo ? 1 : 0)) + "题)不为空");
+                    return;
+                }
+            }
         }
     }
 
-    buttonLoading.value = true;    
+
+    
+
+    buttonLoading.value = true;
     paramForm.value.content = JSON.stringify(form.value);
     if (paramForm.value.id) {
         await updateScreening(paramForm.value).finally(() => buttonLoading.value = false);
@@ -280,7 +566,7 @@ const submitForm = async () => {
 }
  
 
-const selectScaleQuestions = async (idx:number, n:number) => {
+const selectScaleQuestions = async (idx:number, n:number) => {    
     if(isView.value){
         return;
     }
@@ -289,12 +575,12 @@ const selectScaleQuestions = async (idx:number, n:number) => {
         other.value = [];
     }
 
-    let ctl = other.contentList[n];
+    let ctl = other.contentList[n];     
     if (ctl.value!=null) {
         ctl.value = null;
         let newList=[];
         for (let i = 0, len = other.value.length; i < len; i++) {             
-            if (other.value[i] != n) {                
+            if (other.value[i] != n) {
                 newList.push(other.value[i]);
             }
         }
@@ -452,7 +738,7 @@ const selectScaleQuestions = async (idx:number, n:number) => {
 }
 
 
-.is-selected {
+.my-selected{
   background-color: #ccf0a4;   /* Element Plus 主色 */
   color: #fff;  
   border-radius: 6px;

+ 42 - 14
src/views/system/screeningAssessmentConfig/add.vue

@@ -212,7 +212,7 @@
                 <template v-if="other.questionType != 'questionTypeSelection'">
                   <el-row :gutter="10" class="mb8">
                     <el-col :span="12">
-                      <el-form-item :label="(index + 1 + baseInfo.contentList.length) + '. 标题:'" required>
+                      <el-form-item :label="(index + 1 + (baseInfo.contentList.length>0?1:0)) + '. 标题:'" required>
                         <el-input readonly style="width: 100%;" v-model="other.title" size="large" />
                       </el-form-item>
                     </el-col>
@@ -229,7 +229,7 @@
                 <template v-if="other.questionType == 'questionTypeSelection'">
                   <el-row :gutter="10" class="mb8">
                     <el-col :span="12">
-                      <el-form-item :label="(index + 1 + baseInfo.contentList.length) + '. 标题:'" required>
+                      <el-form-item :label="(index + 1 + (baseInfo.contentList.length>0?1:0)) + '. 标题:'" required>
                         <el-input style="width: 100%;" v-model="other.title" placeholder="请输入标题" size="large"
                           show-word-limit maxlength="150" />
                       </el-form-item>
@@ -604,6 +604,7 @@
 import { ref, onMounted, onUnmounted } from 'vue';
 import { listScreeningAssessmentConfig, getScreeningAssessmentConfig, delScreeningAssessmentConfig, addScreeningAssessmentConfig, updateScreeningAssessmentConfig } from '@/api/system/screeningAssessmentConfig';
 import { ScreeningAssessmentConfigVO, ScreeningAssessmentConfigQuery, ScreeningAssessmentConfigForm, QuestionAttrVO, QuestionVO } from '@/api/system/screeningAssessmentConfig/types';
+import { fa } from 'element-plus/es/locale/index.mjs';
 
 const route = useRoute();
 const showSystemParam = ref(true);
@@ -701,7 +702,10 @@ const getList = async () => {
       baseInfo.value = res.data.baseInfo;
     }
     if(res.data.otherInfo){
-      otherInfo.value = res.data.otherInfo;
+      otherInfo.value = res.data.otherInfo;      
+      otherInfo.value.forEach(item=>{
+        item.increment = item.contentList.length;                 
+      });
     }
   loading.value = false;
   }
@@ -768,18 +772,23 @@ const submitForm = () => {
       let lineNum=0;
       for (let item of otherInfo.value) {
         lineNum++;
-        if (!item.title || item.title.trim().length < 1) {       
-          proxy?.$modal.msgError("第"+(baseNum+lineNum)+"行标题为空");
+        if (!item.title || item.title.trim().length < 1) {
+          proxy?.$modal.msgError("第" + (baseNum + lineNum) + "行标题为空");
           return;
         }
+
         for (let ch of item.contentList) {
-          if (!ch.label || ch.label.trim().length < 1) {
-            proxy?.$modal.msgError("第"+(baseNum+lineNum)+"行标题的选项有空值");
-            return;
-          }
-          if (item.questionChildType=='matrixScale'&&(!ch.optionContent || ch.optionContent.trim().length < 1)) {
-            proxy?.$modal.msgError("第"+(baseNum+lineNum)+"行标题的选项内容为空");
-            return;
+          if (item.questionChildType == 'matrixScale') {
+            if ((ch.optionFlag && (!ch.optionContent || ch.optionContent.trim().length < 1))
+              || (ch.labelFlag && (!ch.label || ch.label.trim().length < 1))) {
+              proxy?.$modal.msgError("第" + (baseNum + lineNum) + "行标题的选项内容为空");
+              return;
+            }
+          } else {
+            if (!ch.label || ch.label.trim().length < 1) {
+              proxy?.$modal.msgError("第" + (baseNum + lineNum) + "行标题的选项有空值");
+              return;
+            }
           }
         }
       }
@@ -1431,12 +1440,12 @@ function handleMatrixScaleDelete(index: number, childIndex: number, isLeft: bool
   let other = otherInfo.value[index];
   let child = other.contentList[childIndex];
 
-  if (other.contentList.length == 0) {
+  if (other.contentList.length == 1) {
     if (isLeft) {
       if (!child.optionFlag) {
         other.contentList = [];
       } else {
-        child.label = undefined;
+        child.labelFlag = false;     
       }
     } else {
       if (!child.labelFlag) {
@@ -1448,6 +1457,25 @@ function handleMatrixScaleDelete(index: number, childIndex: number, isLeft: bool
     return;
   }
 
+  if (other.contentList.length == childIndex + 1) {
+    if (isLeft) {
+      if (!child.optionFlag) {
+        other.contentList.pop();
+      } else {
+        child.labelFlag = false;
+        child.label = undefined;
+      }
+    } else {
+      if (!child.labelFlag) {
+        other.contentList.pop();
+      } else {
+        child.optionFlag = false;
+        child.optionContent = undefined;
+      }
+    }
+    return;
+  }
+
   for (let i = childIndex + 1, len = other.contentList.length; i < len; i++) {
     let childPre = other.contentList[i - 1];
     child = other.contentList[i];

+ 3 - 3
vite.config.ts

@@ -27,11 +27,11 @@ export default defineConfig(({mode, command}) => {
       port: Number(env.VITE_APP_PORT),
       open: true,
       proxy: {
-        '/dev-api': {
-          target: 'http://192.168.1.237',
+        [env.VITE_APP_BASE_API]: {
+          target: 'http://localhost:8080',
           changeOrigin: true,
           ws: true,
-          rewrite: (path) => path.replace(/^\/dev-api/, '')
+          rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
         }
       }
     },