chenying2100 1 月之前
父節點
當前提交
4804527dc0

+ 5 - 5
src/api/patients/nutrition/index.ts

@@ -1,6 +1,6 @@
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
-import { NutritionVO, NutritionForm, NutritionQuery } from '@/api/system/nutrition/types';
+import { EnteralNutritionVO, EnteralNutritionForm, EnteralNutritionQuery,EnteralNutritionSaveForm } from '@/api/patients/nutrition/types';
 
 /**
  * 查询肠内营养列表
@@ -8,7 +8,7 @@ import { NutritionVO, NutritionForm, NutritionQuery } from '@/api/system/nutriti
  * @returns {*}
  */
 
-export const listEnteralNutrition = (query?: NutritionQuery): AxiosPromise<NutritionVO[]> => {
+export const listEnteralNutrition = (query?: EnteralNutritionQuery): AxiosPromise<EnteralNutritionVO[]> => {
   return request({
     url: '/system/nutrition/list',
     method: 'get',
@@ -20,7 +20,7 @@ export const listEnteralNutrition = (query?: NutritionQuery): AxiosPromise<Nutri
  * 查询肠内营养详细
  * @param id
  */
-export const getEnteralNutrition = (id: string | number): AxiosPromise<NutritionVO> => {
+export const getEnteralNutrition = (id: string | number): AxiosPromise<EnteralNutritionVO> => {
   return request({
     url: '/system/nutrition/' + id,
     method: 'get'
@@ -31,7 +31,7 @@ export const getEnteralNutrition = (id: string | number): AxiosPromise<Nutrition
  * 新增肠内营养
  * @param data
  */
-export const addEnteralNutrition = (data: NutritionForm) => {
+export const addEnteralNutrition = (data: EnteralNutritionSaveForm) => {
   return request({
     url: '/system/nutrition',
     method: 'post',
@@ -43,7 +43,7 @@ export const addEnteralNutrition = (data: NutritionForm) => {
  * 修改肠内营养
  * @param data
  */
-export const updateEnteralNutrition = (data: NutritionForm) => {
+export const updateEnteralNutrition = (data: EnteralNutritionForm) => {
   return request({
     url: '/system/nutrition',
     method: 'put',

+ 43 - 2
src/api/patients/nutrition/types.ts

@@ -121,6 +121,43 @@ export interface EnteralNutritionVO {
 
 }
 
+
+export interface EnteralNutritionSaveForm extends BaseEntity {
+  /**
+   * 结算管理id
+   */
+  settlementId?: string | number;
+
+      /**
+     * 患者ID
+     */
+  patientId?: string  | number;
+
+    /**
+   * 看诊类型
+   */
+  visitType?: string | number;
+  
+    /**
+   * 收费类型
+   */
+  chargeType?: string | number;
+
+    /**
+   * 门诊/住院号
+   */
+  patientNo?: string | number;
+
+    /**
+   * 状态(0正常 1停用 2草稿)
+   */
+  status?: string | number;
+
+  nutritionList?: any[];
+
+  consumableList?: any[];
+}
+
 export interface EnteralNutritionForm extends BaseEntity {
   /**
    * 主键ID
@@ -132,6 +169,8 @@ export interface EnteralNutritionForm extends BaseEntity {
    */
   settlementId?: string | number;
 
+  productSpecUnit?: string;
+
   /**
    * 开方日期
    */
@@ -166,7 +205,7 @@ export interface EnteralNutritionForm extends BaseEntity {
   /**
    * 用量/次
    */
-  dosePerTime?: string|;
+  dosePerTime?: string;
 
   /**
    * 餐次时间
@@ -181,7 +220,7 @@ export interface EnteralNutritionForm extends BaseEntity {
   /**
    * 首日
    */
-  firstDay?: number;
+  firstDay?: number | string;
 
   /**
    * 用量/日
@@ -238,6 +277,8 @@ export interface EnteralNutritionForm extends BaseEntity {
    */
   amount?: number;
 
+
+
   /**
    * 状态(0正常 1停用)
    */

+ 189 - 19
src/views/patients/enteralNutrition/components/LeftCard.vue

@@ -8,13 +8,20 @@
           <div class="operation-bar">
             <!-- 日期选择 -->
             <el-row>
-              <el-col :span="10">
+              <el-col :span="8">
                 <span class="label">日期时间:</span>
-                <el-date-picker v-model="dateRange" type="date"  placeholder="请选择" />
+                <el-date-picker v-model="prescriptionDate" :clearable="false" type="date" 
+                :disabled-date="disabledBeforeToday"  placeholder="请选择"  value-format="YYYY-MM-DD"/>
               </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 :span="4">
+                
+              </el-col>
+              <el-col class="right_btn" :span="12">
+                <el-button type="primary" plain @click="submitForm('2')">存为草稿</el-button>
+                <el-button type="primary" @click="submitForm('0')" :loading="buttonLoading">提交</el-button>
+                <el-button type="danger" @click="deleteFrom">删除</el-button>
+                <el-button type="primary" plain>打印知情同意书</el-button>
+                <el-button type="success" @click="goHistoryPrescription">历史处方</el-button>                
               </el-col>
             </el-row>
 
@@ -29,31 +36,31 @@
             </div>
 
             <!-- 开方原因 -->
-            <div class="prescription-reason">
+            <!-- <div class="prescription-reason">
               <span class="reason-label">开方原因:</span>
               <span class="reason-value">1111</span>
-            </div>
+            </div> -->
           </div>
 
           <!-- 处方提示信息 -->
-          <div class="prescription-info">
+          <!-- <div class="prescription-info">
             <div class="warning-box">
               当前处方中的脂肪、维生素A、维生素D、维生素E、维生素B1、维生素B2、维生素B6、维生素B12、硒(尼克黄)、维生素C、生物素、泛酸元素可能过量
             </div>
-          </div>
+          </div> -->
 
           <!-- 处方表格 -->
           <div class="prescription-tables">
             <template v-if="tableType === 'normal'">
-              <ConfigureTable @change="updateConfigureData"/>
-              <MaterialTable v-model="configData"/>
+              <ConfigureTable @change="updateConfigureData" v-model="configData"/>
+              <MaterialTable v-model="configData" @change="updateMaterialData"/>
             </template>
             <template v-else-if="tableType === 'package'">
-              <PackageTable/>
+              <PackageTable @change="updatePackageData"/>
             </template>
             <template v-else>
-              <NutritionTable/>
-              <MaterialTable/>
+              <NutritionTable @change="updateLongTermData" v-model="longTermData" :prescriptionDate="prescriptionDate"/>
+              <MaterialTable2 v-model="longTermData" @change="updateMaterial2Data"/>
             </template>
           </div>
         </div>
@@ -69,33 +76,175 @@
 import {ref} from 'vue';
 import NutritionTable from './table/NutritionTable.vue';
 import MaterialTable from './table/MaterialTable.vue';
+import MaterialTable2 from './table/MaterialTable2.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';
+import { EnteralNutritionVO, EnteralNutritionQuery, EnteralNutritionForm, EnteralNutritionSaveForm } from '@/api/patients/nutrition/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  
 const emit = defineEmits(['gotoTop']);
+const buttonLoading = ref(false);
+const { patientInfo } = defineProps<{ patientInfo: any }>()
+
 
 // 顶部tab切换
-const activeTab = ref('nutrition');
+const activeTab = ref('nutrition'); 
 const configData= ref('');
+const packageData= ref('');
+const longTermData= ref('');
+const materialData= ref('');
+const materialData2= ref('');
 
 // 表格类型
 const tableType = ref<'normal' | 'package' | 'long-term'>('normal');
 
 // 日期范围
-const dateRange = ref([]);
+const prescriptionDate = ref('');
 
 // 处方类型
 const prescriptionType = ref<'normal' | 'package' | 'long-term'>('normal');
 
 const updateConfigureData = (val:string) => {  
-  configData.value=val;  
+  configData.value=val; 
+};
+
+const updateLongTermData = (val:string) => {  
+  longTermData.value=val;   
+};
+
+const updatePackageData = (val:string) => {  
+  packageData.value=val;    
+};
+
+const updateMaterialData = (val:string) => {  
+  materialData.value=val;          
+};
+
+const updateMaterial2Data = (val:string) => {  
+  materialData2.value=val;  
+};
+
+const deleteFrom =async ( ) => {
+  configData.value=JSON.stringify([]);         
 };
 
+ 
+
+const submitForm = async (status: string) => {
+  let param = ref<EnteralNutritionSaveForm>({});
+  param.value.patientId = patientInfo.id;
+  param.value.visitType = patientInfo.type;
+
+  param.value.patientNo = patientInfo.outpatientNo;
+  param.value.status = status;
+
+  if (prescriptionType.value == 'normal') {
+    param.value.chargeType = '3';
+    if (!configData.value || configData.value.length == 0) {
+      proxy?.$modal.msgError("营养产品不为空");
+      return;
+    }
+    param.value.nutritionList = JSON.parse(configData.value);
+
+    if (!materialData.value || materialData.value.length == 0) {
+      proxy?.$modal.msgError("耗材不为空");
+      return;
+    }
+    param.value.consumableList = JSON.parse(materialData.value);
+
+  } else if (prescriptionType.value == 'package') {
+    param.value.chargeType = '2';
+    if (!packageData.value || packageData.value.length == 0) {
+      proxy?.$modal.msgError("营养产品不为空");
+      return;
+    }
+    param.value.nutritionList = JSON.parse(packageData.value);
+
+  } else {
+    param.value.chargeType = '4';
+    if (!longTermData.value || longTermData.value.length == 0) {
+      proxy?.$modal.msgError("营养产品不为空");
+      return;
+    }
+    param.value.nutritionList = JSON.parse(longTermData.value);
+
+    if (!materialData2.value || materialData2.value.length == 0) {
+      proxy?.$modal.msgError("耗材不为空");
+      return;
+    }
+    param.value.consumableList = JSON.parse(materialData2.value);
+  }
+
+  if (param.value.chargeType != '2') {
+    for (let item of param.value.consumableList) {
+      if (!item.consumableId) {
+        proxy?.$modal.msgError("耗材没有选择");
+        return;
+      }
+
+      item.groupNo = item.sn;
+      let arr = item.consumableId.split("_");
+      item.consumableId = arr[0];
+    }
+    
+    for (let item of param.value.nutritionList) {
+      if (!item.products || item.products.length == 0) {
+        proxy?.$modal.msgError("营养产品没有记录");
+        return;
+      }
+
+      let tsList = []
+      item.timeSlots.forEach(ts => {
+        tsList.push(ts.checked ? ts.time : '');
+      });
+      item.mealTime = tsList.join(',');
+      item.prescriptionDate = prescriptionDate.value;
+      item.prescriptionType = param.value.chargeType;
+
+      for (let pd of item.products) {
+        if (!pd.nutritionProductId) {
+          proxy?.$modal.msgError("营养产品没有选择");
+          return;
+        }
+
+        let arr = pd.nutritionProductId.split("_");
+        pd.nutritionProductId = arr[0];
+
+        pd.prescriptionDate = prescriptionDate.value;
+        pd.groupNo = item.sn;
+      }
+    }
+  }else{
+    for (let item of param.value.nutritionList) {
+      let tsList = []
+      item.timeSlots.forEach(ts => {
+        tsList.push(ts.checked ? ts.time : '');
+      });
+      item.mealTime = tsList.join(',');
+      item.prescriptionDate = prescriptionDate.value;
+      item.prescriptionType = param.value.chargeType;
+
+      if (!item.nutritionProductId) {
+          proxy?.$modal.msgError("营养产品没有选择");
+          return;
+        }
+
+        let arr = item.nutritionProductId.split("_");
+        item.nutritionProductId = arr[0];
+
+        item.prescriptionDate = prescriptionDate.value;
+        item.groupNo = item.sn;
+    }
+  }
+ 
+  await addEnteralNutrition(param.value).finally(() => buttonLoading.value = false);
+  proxy?.$modal.msgSuccess("操作成功");
+};
+
+
 
 // 添加配置处方
 const addPrescription = () => {
@@ -120,6 +269,27 @@ const goHistoryPrescription = () => {
   emit('gotoTop')
 };
 
+function formatDate(date) {
+  const pad = n => n < 10 ? '0' + n : n;
+  return date.getFullYear() + '-' +
+    pad(date.getMonth() + 1) + '-' +
+    pad(date.getDate()) ;
+}
+
+// 禁用今天之前的日期
+const disabledBeforeToday = (date) => {
+  const today = new Date()
+  // 设置时间为今天凌晨,确保比较的是日期而非具体时间
+  today.setHours(0, 0, 0, 0)
+  return date < today
+}
+
+onMounted(() => {
+  let now=new Date();
+  let start=formatDate(now);
+  prescriptionDate.value=start;
+});
+
 </script>
 
 <style lang="scss" scoped>
@@ -142,7 +312,7 @@ const goHistoryPrescription = () => {
   .operation-bar {
     margin-bottom: 16px;
     .right_btn {
-      margin-left: 268px;
+      margin-left: 0px;
     }
 
     .add-buttons {

+ 98 - 29
src/views/patients/enteralNutrition/components/table/ConfigureTable.vue

@@ -98,7 +98,8 @@
       <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>             
+            <span>{{product.dosePerDay }}</span>   
+            <span class="unit">{{ product.productSpecUnit }}</span> 
           </div>
         </template>
       </el-table-column>
@@ -113,7 +114,8 @@
       <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>            
+            <span>{{product.totalDose }}</span>  
+            <span class="unit">{{ product.productSpecUnit }}</span>            
           </div>
         </template>
       </el-table-column>
@@ -128,7 +130,7 @@
 
       <el-table-column label="用法" width="150" align="center">
         <template #default="{row}">
-          <el-select v-model="row.usage" placeholder="请选择" >
+          <el-select v-model="row.usage" placeholder="请选择" @change="changeUsage(row.usage,row.sn)">
             <el-option v-for="dict in default_usage" :key="dict.value" :label="dict.label"
               :value="dict.value"></el-option>
           </el-select>
@@ -137,7 +139,7 @@
 
       <el-table-column label="制剂液量/次" width="170" align="center">
         <template #default="{row}">
-          <el-input v-model="row.preparationVolumePerTime">
+          <el-input v-model="row.preparationVolumePerTime" @change="changePreparationVolumePerTime(row.preparationVolumePerTime,row.sn)">
             <template #append>ml</template>
           </el-input>
         </template>
@@ -154,7 +156,7 @@
 
       <el-table-column label="能量密度/次" width="200" align="center">
         <template #default="{row}">
-          <el-input v-model="row.energyDensityPerTime">
+          <el-input v-model="row.energyDensityPerTime" @change="changeEnergyDensityPerTime(row.energyDensityPerTime,row.sn)">
             <template #append>kcal/ml</template>
           </el-input>
         </template>
@@ -163,7 +165,8 @@
       <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" />
+            <el-input v-model="product.prescriptionRemark" :maxlength="100" :show-word-limit="true" 
+            @change="changePrescriptionRemark(product.prescriptionRemark,row.sn)"/>
           </template>          
         </template>
       </el-table-column>
@@ -212,12 +215,37 @@ import { listEnteralNutrition, getEnteralNutrition, delEnteralNutrition, addEnte
 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 prop=defineProps({
+  modelValue: {
+    type: String,
+    default: () => undefined
+  },
+});
+
+
+watch(
+  () => prop.modelValue,
+  async (val: string) => {
+    if (!val || val.trim().length == 0) {
+      return;
+    }
+
+    let arr =JSON.parse(val);
+    if(Array.isArray(arr)&&arr.length==0){
+      tableData.value=[];
+    }
+  },
+  { deep: true, immediate: true }
+);
+
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { default_usage } = toRefs < any > (proxy ?.useDict('default_usage'));
 
 let productNutritionList=ref<NutritionVO[]>([]);
+let tableId=ref<number>(0);
 
 const getProductNutritionList = async () => {
   const res = await listAllNutrition();
@@ -234,11 +262,12 @@ interface TableRow  extends EnteralNutritionForm {
   products: EnteralNutritionForm[];
   timeSlots: TimeSlot[];
   sn: number;
+  tableId: number;
 }
 
 // 创建默认行数据的函数
 const createDefaultRow = (): TableRow => ({
-  products: [{specification:'g',totalDose:'g',dosePerDay:'g'}],
+  products: [{specification:'',totalDose:'',dosePerDay:''}],
   timeSlots: [
     {checked: true, time: '08:00'},
     {checked: false, time: '08:30'},
@@ -249,8 +278,9 @@ const createDefaultRow = (): TableRow => ({
   ],
   usageDays:1,
   frequency:3,
-  firstDay:1,
+  firstDay:2,
   sn:0,
+  tableId:tableId.value++,
 });
 
 const emit = defineEmits(['change']);
@@ -278,12 +308,16 @@ const changeProductSelect = async (id: string) => {
     pt.specification=item.productSpec;
     pt.dosePerTime=null;     
     pt.dailyCalories=null;
+    pt.productSpecUnit=item.productSpecUnit;
     pt.amount=null; 
     row.usage=item.defaultUsage;
-    pt.totalDose='0'+item.productSpecUnit;
-    pt.dosePerDay='0'+item.productSpecUnit;
+    pt.totalDose='0' ;
+    pt.dosePerDay='0';
+    pt.firstDay=Math.ceil(row.frequency/2.0);
     break;
   }
+
+  emit('change',JSON.stringify(tableData.value))
 };
 
 // 新增产品输入框
@@ -299,6 +333,7 @@ const removeProduct = (row: TableRow, index: number) => {
     if (rowIndex !== -1) {
       tableData.value.splice(rowIndex, 1);
     }
+    emit('change',JSON.stringify(tableData.value))
   } else {
     // 否则只删除当前输入框
     row.products.splice(index, 1);
@@ -309,39 +344,67 @@ const removeProduct = (row: TableRow, index: number) => {
 // 复制行
 const copyRow = (index: number) => {
   const newRow = JSON.parse(JSON.stringify(tableData.value[index]));
+  newRow.tableId = tableId.value++
   tableData.value.splice(index + 1, 0, newRow);
-  emit('change',JSON.stringify(tableData.value))
+  tableData.value.forEach((item, index) => {
+    item.sn = index;
+    item.products.forEach((ch, idx) => {
+      if(ch.nutritionProductId){
+        let arr = ch.nutritionProductId.split('_');
+        ch.nutritionProductId = arr[0] + '_' + index + '_' + idx;
+      }     
+    });
+  });
+  emit('change', JSON.stringify(tableData.value))
 };
 
 // 删除行
-const deleteRow = (index: number) => {
-  if (tableData.value.length === 1) return;
+const deleteRow = (index: number) => {   
   tableData.value.splice(index, 1);
+
+  tableData.value.forEach((item, index) => {
+    item.sn = index;
+  });  
+
   emit('change',JSON.stringify(tableData.value))
 };
  
 const changeUsageDays = (value: string, sn:string) => { 
-  changeTimeSelection(value,sn);
-  emit('change',JSON.stringify(tableData.value))  
+  changeTimeSelection(null,sn);   
+}
+
+const changeUsage = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changePreparationVolumePerTime = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changeEnergyDensityPerTime = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
 }
 
+const changePrescriptionRemark = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+
 const firstDayInput = (value: string, sn:string) => { 
-  changeTimeSelection(value,sn);  
-  emit('change',JSON.stringify(tableData.value))
+  changeTimeSelection(null,sn);
 }
 
 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))
+  if(value!=null){
+    row.firstDay=Math.ceil(row.frequency/2.0);
   }
 
   row.products.forEach(pt => {
@@ -359,18 +422,21 @@ const changeTimeSelection = (value: string, sn:string) => {
     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)
+    let firstDay=Number(row.firstDay.toString());
+    val=(row.frequency*(row.usageDays-1)+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*(row.usageDays-1)+firstDay)*Number(pt.dosePerTime)
+    pt.totalDose=val.toFixed(4) ;
 
     val=row.frequency*Number(pt.dosePerTime)
-    pt.dosePerDay=val.toFixed(4)+item.productSpecUnit;
+    pt.dosePerDay=val.toFixed(4) ;
     break;
   }
 
   });  
+
+  emit('change',JSON.stringify(tableData.value));
 };
 
 const dosePerTimeInput = (value: string, str:string) => {
@@ -393,16 +459,19 @@ const dosePerTimeInput = (value: string, str:string) => {
     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)
+    let firstDay=Number(row.firstDay.toString());
+    val=(row.frequency*(row.usageDays-1)+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*(row.usageDays-1)+firstDay)*Number(pt.dosePerTime)
+    pt.totalDose=val.toFixed(4) ;
 
     val=row.frequency*Number(pt.dosePerTime)
-    pt.dosePerDay=val.toFixed(4)+item.productSpecUnit;
+    pt.dosePerDay=val.toFixed(4) ;
     break;
   }
+
+  emit('change',JSON.stringify(tableData.value))
 };
 
 

+ 158 - 44
src/views/patients/enteralNutrition/components/table/MaterialTable.vue

@@ -25,7 +25,7 @@
         <template #default="{row}">
           <div class="dosage-group">
             <div class="dosage-input">
-              <el-input v-model="row.dosePerTime" placeholder="请输入" class="input-center" >
+              <el-input v-model="row.dosePerTime" placeholder="请输入" class="input-center" @input="dosePerTimeInput(row.dosePerTime,row.sn)">
                 <template #append>袋</template>
               </el-input>              
             </div>             
@@ -63,7 +63,7 @@
 
       <el-table-column label="处方备注" width="200" align="center">
         <template #default="{row}">
-          <el-input v-model="row.prescriptionRemark" :maxlength="100" :show-word-limit="true" />        
+          <el-input v-model="row.prescriptionRemark" :maxlength="100" :show-word-limit="true" @change="prescriptionRemark"/>        
         </template>
       </el-table-column>
 
@@ -84,15 +84,15 @@
         <div class="summary-list">
           <div class="summary-item">
             <span class="label">处方费用:</span>
-            <span class="value">¥0.00</span>
+            <span class="value">¥{{ nutritionalFee + otherlFee  }}</span>
           </div>
           <div class="summary-item">
             <span class="label">营养配置费:</span>
-            <span class="value">¥39.00</span>
+            <span class="value">¥{{ prescriptionFee }}</span>
           </div>
           <div class="summary-item total">
             <span class="label">总计:</span>
-            <span class="value">¥39.00</span>
+            <span class="value">¥{{ totalFee+otherlFee }}</span>
           </div>
         </div>
       </div>
@@ -106,10 +106,13 @@ 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';
+ 
+let prescriptionFee=ref(1.0);
+let nutritionalFee=ref(0.0);
+let otherlFee=ref(0.0);
+let totalFee=ref(1.0);
 
-const emit = defineEmits(['update:modelValue']);
+const emit = defineEmits(['change']);
 
 const prop=defineProps({
   modelValue: {
@@ -121,19 +124,21 @@ const prop=defineProps({
 
 interface TableRow extends NutritionConsumableForm {  
   sn?: number;   
+  tableId?: number;   
 }
 
 // 示例数据
 const tableData = ref<TableRow[]>([
-  {           
-    firstDay:1,
-    frequency:3,
-    dosePerTime:1,
-    dosePerDay:3,
-    usageDays:1,
-    quantity:1,
-    sn: 0    
-  }     
+  {
+    firstDay: 1,
+    frequency: 3,
+    dosePerTime: 1,
+    dosePerDay: 3,
+    usageDays: 1,
+    quantity: 1,
+    sn: 0,
+    tableId: 0
+  }
 ]);
 
 
@@ -147,59 +152,168 @@ const getSuppliesList = async () => {
 
  
 
-// 复制行
-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) {
+    let row = tableData.value[Number(arr[1])];
     if (item.id.toString() != arr[0]) {
+      otherlFee.value+=item.sellPrice * row.quantity;;
       continue
     }
+
+    let dosePerTime = 0;
+    if (row.dosePerTime) {
+      dosePerTime = row.dosePerTime;
+    }
     
-    
-    let row = tableData.value[Number(arr[1])];
     row.specification=item.suppliesSpec;
-    row.amount=item.sellPrice;
+    row.dosePerDay = row.frequency * dosePerTime;
+    row.quantity = ((row.usageDays - 1) * row.frequency + row.firstDay) * dosePerTime;   
+
+    if (row.consumableId) {
+      let consumableId = row.consumableId.split('_')[0];
+      for (let item of suppliesList.value) {
+        if (item.id.toString() != consumableId) {
+          continue
+        }
+
+        row.amount = item.sellPrice * row.quantity;       
+        break;
+      }
+    }
+
     break;
   }
+
+  otherlFee.value=0;
+  tableData.value.forEach(row => {
+    if(row.amount){
+      otherlFee.value+=row.amount;
+    }
+  });
+
+  emit('change',JSON.stringify(tableData.value))
 };
 
 
 watch(
   () => prop.modelValue,
   async (val: string) => {
-    if(val&&val.trim().length>0){
-      let configData=JSON.parse(val);
-    const tableData = ref<TableRow[]>([]);
+    if (!val || val.trim().length == 0) {
+      return;
+    }
+
+    let configData = JSON.parse(val);
+    let tableDataMap = {}
+    tableData.value.forEach((item: any) => {
+      tableDataMap[item.tableId] = item;
+    });
 
-    configData.forEach((item:any) => { 
-      let row: TableRow = {        
-        frequency: item.frequency,         
+    const newTableList = ref<TableRow[]>([]);
+    prescriptionFee.value = 0;
+    totalFee.value = 0;
+    otherlFee.value = 0;
+    nutritionalFee.value = 0;
+    prescriptionFee.value+=configData.length;
+    totalFee.value+=configData.length;
+
+    configData.forEach((item: any) => {
+      item.products.forEach(pd => {        
+        if (pd.amount) {
+          nutritionalFee.value += pd.amount;
+          totalFee.value += pd.amount;
+        }
+      });
+
+      let row: TableRow = {
+        frequency: item.frequency,
         usageDays: item.usageDays,
         firstDay: item.firstDay,
-        sn: tableData.value.length
+        dosePerTime: 1,
+        tableId: item.tableId,
+        sn: newTableList.value.length
       };
-      row.dosePerTime=0;
 
-      tableData.value.push(row);
+      let tmpData = tableDataMap[item.tableId];
+      if (tmpData) {
+        row = tmpData;
+      }
+      let dosePerTime=0;
+      if (row.dosePerTime) {
+        dosePerTime = row.dosePerTime;
+      }
+
+      row.frequency = item.frequency;
+      row.usageDays = item.usageDays;
+      row.firstDay = item.firstDay;
+      row.dosePerDay = item.frequency * dosePerTime;
+      row.quantity = ((row.usageDays - 1) * row.frequency + row.firstDay) * dosePerTime;
+
+      if (row.consumableId) {
+        let consumableId = row.consumableId.split('_')[0];
+        for (let item of suppliesList.value) {
+          if (item.id.toString() != consumableId) {
+            continue
+          }
+
+          row.amount = item.sellPrice * row.quantity;                    
+          break;
+        }
+      }
+
+      if(row.amount){
+        otherlFee.value+=row.amount; 
+      }     
+
+      newTableList.value.push(row);
     });
-    }
-    
-    console.log(configData, "?????*************????????????????");
+
+    tableData.value = newTableList.value;
+    emit('change', JSON.stringify(tableData.value));
   },
   { deep: true, immediate: true }
 );
 
+
+const dosePerTimeInput = (value: string, sn: number) => {
+  let row = tableData.value[sn];
+  let dosePerTime=0;
+  if (row.dosePerTime) {
+    dosePerTime=row.dosePerTime;
+  }
+  row.dosePerDay = row.frequency * dosePerTime;
+  row.quantity = ((row.usageDays - 1) * row.frequency + row.firstDay) * dosePerTime;
+  otherlFee.value=0;
+
+  if (row.consumableId) {
+    let consumableId = row.consumableId.split('_')[0];
+    for (let item of suppliesList.value) {
+      if (item.id.toString() != consumableId) {
+        otherlFee.value+=item.sellPrice * row.quantity;
+        continue
+      }
+
+      row.amount = item.sellPrice * row.quantity;
+      otherlFee.value+=row.amount;
+      break;
+    }
+  }
+
+  otherlFee.value=0;
+  tableData.value.forEach(row => {
+    if(row.amount){
+      otherlFee.value+=row.amount;
+    }
+  });
+
+  emit('change', JSON.stringify(tableData.value))
+};
+
+const prescriptionRemark = (value: string) => {
+  emit('change',JSON.stringify(tableData.value))
+};
+
+
 onMounted(() => { 
   getSuppliesList();  
 });

+ 536 - 0
src/views/patients/enteralNutrition/components/table/MaterialTable2.vue

@@ -0,0 +1,536 @@
+<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" @input="dosePerTimeInput(row.dosePerTime,row.sn)">
+                <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" @change="prescriptionRemark"/>        
+        </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">¥{{ nutritionalFee + otherlFee  }}</span>
+          </div>
+          <div class="summary-item">
+            <span class="label">营养配置费:</span>
+            <span class="value">¥{{ prescriptionFee }}</span>
+          </div>
+          <div class="summary-item total">
+            <span class="label">总计:</span>
+            <span class="value">¥{{ totalFee+otherlFee }}</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';
+ 
+let prescriptionFee=ref(1.0);
+let nutritionalFee=ref(0.0);
+let otherlFee=ref(0.0);
+let totalFee=ref(1.0);
+
+const emit = defineEmits(['change']);
+
+const prop=defineProps({
+  modelValue: {
+    type: String,
+    default: () => undefined
+  },
+});
+
+
+interface TableRow extends NutritionConsumableForm {  
+  sn?: number;   
+  tableId?: number;   
+}
+
+// 示例数据
+const tableData = ref<TableRow[]>([
+  {
+    firstDay: 2,
+    frequency: 3,
+    dosePerTime: 1,
+    dosePerDay: 3,
+    usageDays: 0,
+    quantity: 0,
+    sn: 0,
+    tableId: 0
+  }
+]);
+
+
+let suppliesList=ref<SuppliesManageVO[]>([]);
+ 
+
+const getSuppliesList = async () => {
+  const res = await listAll();
+  suppliesList.value = res.rows;
+}
+
+ 
+
+const changeConsumableSelect = async (id: string) => {
+  let arr=id.split('_');
+  for (let item of suppliesList.value) {
+    let row = tableData.value[Number(arr[1])];
+    if (item.id.toString() != arr[0]) {
+      otherlFee.value+=item.sellPrice * row.quantity;;
+      continue
+    }
+
+    let dosePerTime = 0;
+    if (row.dosePerTime) {
+      dosePerTime = row.dosePerTime;
+    }
+    
+    row.specification=item.suppliesSpec;
+    row.dosePerDay = row.frequency * dosePerTime;
+    row.quantity =Math.max(0,((row.usageDays - 1) * row.frequency + row.firstDay) * dosePerTime) ;   
+
+    if (row.consumableId) {
+      let consumableId = row.consumableId.split('_')[0];
+      for (let item of suppliesList.value) {
+        if (item.id.toString() != consumableId) {
+          continue
+        }
+
+        row.amount = item.sellPrice * row.quantity;       
+        break;
+      }
+    }
+
+    break;
+  }
+
+  otherlFee.value=0;
+  tableData.value.forEach(row => {
+    if(row.amount){
+      otherlFee.value+=row.amount;
+    }
+  });
+
+  emit('change',JSON.stringify(tableData.value))
+};
+
+
+watch(
+  () => prop.modelValue,
+  async (val: string) => {
+    if (!val || val.trim().length == 0) {
+      return;
+    }
+
+    let configData = JSON.parse(val);
+    let tableDataMap = {}
+    tableData.value.forEach((item: any) => {
+      tableDataMap[item.tableId] = item;
+    });
+
+    const newTableList = ref<TableRow[]>([]);
+    prescriptionFee.value = 0;
+    totalFee.value = 0;
+    otherlFee.value = 0;
+    nutritionalFee.value = 0;
+    prescriptionFee.value+=configData.length;
+    totalFee.value+=configData.length;
+
+    configData.forEach((item: any) => {
+      item.products.forEach(pd => {        
+        if (pd.amount) {
+          nutritionalFee.value += pd.amount;
+          totalFee.value += pd.amount;
+        }
+      });
+
+      let row: TableRow = {
+        frequency: item.frequency,
+        usageDays: item.usageDays,
+        firstDay: item.firstDay,
+        dosePerTime: 1,
+        tableId: item.tableId,
+        sn: newTableList.value.length
+      };
+
+      let tmpData = tableDataMap[item.tableId];
+      if (tmpData) {
+        row = tmpData;
+      }
+      let dosePerTime=0;
+      if (row.dosePerTime) {
+        dosePerTime = row.dosePerTime;
+      }
+
+      row.frequency = item.frequency;
+      row.usageDays = item.usageDays;
+      row.firstDay = item.firstDay;
+      row.dosePerDay = item.frequency * dosePerTime;
+      row.quantity =Math.max(0,((row.usageDays - 1) * row.frequency + row.firstDay) * dosePerTime) ;
+
+      if (row.consumableId) {
+        let consumableId = row.consumableId.split('_')[0];
+        for (let item of suppliesList.value) {
+          if (item.id.toString() != consumableId) {
+            continue
+          }
+
+          row.amount = item.sellPrice * row.quantity;                    
+          break;
+        }
+      }
+
+      if(row.amount){
+        otherlFee.value+=row.amount; 
+      }     
+
+      newTableList.value.push(row);
+    });
+
+    tableData.value = newTableList.value;
+    emit('change', JSON.stringify(tableData.value));
+  },
+  { deep: true, immediate: true }
+);
+
+
+const dosePerTimeInput = (value: string, sn: number) => {
+  let row = tableData.value[sn];
+  let dosePerTime=0;
+  if (row.dosePerTime) {
+    dosePerTime=row.dosePerTime;
+  }
+  row.dosePerDay = row.frequency * dosePerTime;
+  row.quantity =Math.max(0,((row.usageDays - 1) * row.frequency + row.firstDay) * dosePerTime) ;
+  otherlFee.value=0;
+
+  if (row.consumableId) {
+    let consumableId = row.consumableId.split('_')[0];
+    for (let item of suppliesList.value) {
+      if (item.id.toString() != consumableId) {
+        otherlFee.value+=item.sellPrice * row.quantity;
+        continue
+      }
+
+      row.amount = item.sellPrice * row.quantity;
+      otherlFee.value+=row.amount;
+      break;
+    }
+  }
+
+  otherlFee.value=0;
+  tableData.value.forEach(row => {
+    if(row.amount){
+      otherlFee.value+=row.amount;
+    }
+  });
+
+  emit('change', JSON.stringify(tableData.value))
+};
+
+const prescriptionRemark = (value: string) => {
+  emit('change',JSON.stringify(tableData.value))
+};
+
+
+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>

+ 387 - 142
src/views/patients/enteralNutrition/components/table/NutritionTable.vue

@@ -1,62 +1,48 @@
 <template>
   <div class="nutrition-table">
     <!-- 停嘱日期 (仅长期医嘱显示) -->
-    <div v-if="type === 'long-term'" class="stop-date">
+    <div  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>
+      <el-date-picker v-model="stopDate" type="date" placeholder="请选择" format="YYYY-MM-DD" value-format="YYYY-MM-DD" :clearable="false"
+      @change="handleStopDateChange" :disabled-date="disabledBeforeToday"/>
+      <span class="days">(使用天数:{{daysDifference}}天)</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 class="product-group">             
               <div v-for="(product, index) in row.products" :key="index" class="product-row">
-                <el-input v-model="product.value" placeholder="请输入" />
+                <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-icon>
+                      <Plus />
+                    </el-icon>
                   </el-button>
                   <el-button class="icon-btn" @click="removeProduct(row, index)">
-                    <el-icon><Delete /></el-icon>
+                    <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>  
           </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 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>
@@ -65,98 +51,138 @@
           <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"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[1].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[1].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[2].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[2].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[3].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[3].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[4].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[4].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[5].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[5].checked"
-                />
+                <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>
-          <span>一天3次</span>
+        <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="150" align="center">
+        <template #default="{row}">
+          <div class="daily-dosage" v-for="(product, index) in row.products" :key="index">
+            <span>{{product.dosePerDay }}</span>   
+            <span class="unit">{{ product.productSpecUnit }}</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="请选择" @change="changeUsage(row.usage,row.sn)">
+            <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" @change="changePreparationVolumePerTime(row.preparationVolumePerTime,row.sn)">
+            <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.dailyDosage }}</span>
-            <span class="unit">袋</span>
+            <span>{{ row.preparationConcentrationPerTime }}</span>
+            <span class="unit">%</span>
           </div>
         </template>
       </el-table-column>
-      <el-table-column label="使用天数" width="120" align="center">
+
+      <el-table-column label="能量密度/次" width="200" align="center">
+        <template #default="{row}">
+          <el-input v-model="row.energyDensityPerTime" @change="changeEnergyDensityPerTime(row.energyDensityPerTime,row.sn)">
+            <template #append>kcal/ml</template>
+          </el-input>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="处方备注" width="200" align="center">
         <template #default="{row}">
-          <div class="days">
-            <span>{{ row.days }}</span>
-            <span class="unit">天</span>
+          <template v-for="(product, index) in row.products" >
+            <el-input v-model="product.prescriptionRemark" :maxlength="100" :show-word-limit="true" 
+            @change="changePrescriptionRemark(product.prescriptionRemark,row.sn)"/>
+          </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">
@@ -168,7 +194,9 @@
     </el-table>
     <div class="table-footer">
       <el-button type="primary" class="add-prescription-btn" @click="addNewRow">
-        <el-icon><CirclePlus /></el-icon>
+        <el-icon>
+          <CirclePlus />
+        </el-icon>
         开具多处方
       </el-button>
     </div>
@@ -178,65 +206,104 @@
 <script setup lang="ts">
 import {ref, defineProps} 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';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { default_usage } = toRefs < any > (proxy ?.useDict('default_usage'));
+
+let productNutritionList=ref<NutritionVO[]>([]);
+let tableId=ref<number>(0);
+
+const prop=defineProps({
+  prescriptionDate: {
+    type: String,
+    default: () => undefined
+  },
+});
 
-const props = defineProps<{
-  type?: 'normal' | 'long-term';
-}>();
+const emit = defineEmits(['change']);
 
 // 停嘱日期
 const stopDate = ref('');
+const daysDifference = ref(0);
 
 interface TimeSlot {
   checked: boolean;
   time: string;
 }
 
-interface Product {
-  value: string;
-  dosage: string;
-}
-
-interface TableRow {
-  products: Product[];
+interface TableRow  extends EnteralNutritionForm {
+  products: EnteralNutritionForm[];
   timeSlots: TimeSlot[];
-  dailyDosage: number;
-  days: number;
-  isNewRow?: boolean;
+  sn: number;
+  tableId: number;
 }
 
 // 创建默认行数据的函数
-const createDefaultRow = (isNew: boolean = false): TableRow => ({
-  products: isNew
-    ? [{value: '', dosage: ''}]
-    : [
-        {value: '', dosage: ''},
-        {value: '', dosage: ''},
-        {value: '', dosage: ''}
-      ],
+const createDefaultRow = (): TableRow => ({
+  products: [{specification:'',totalDose:'',dosePerDay:''}],
   timeSlots: [
-    {checked: false, time: '08:00'},
+    {checked: true, time: '08:00'},
     {checked: false, time: '08:30'},
-    {checked: false, time: '12:00'},
+    {checked: true, time: '12:00'},
     {checked: false, time: '12:30'},
-    {checked: false, time: '18:00'},
+    {checked: true, time: '18:00'},
     {checked: false, time: '18:30'}
   ],
-  dailyDosage: 2.0,
-  days: 1,
-  isNewRow: isNew
+  usageDays:0,
+  frequency:3,
+  firstDay:2,
+  sn:0,
+  tableId:tableId.value++,
 });
 
 // 示例数据
-const tableData = ref<TableRow[]>([createDefaultRow(), createDefaultRow()]);
+const tableData = ref<TableRow[]>([createDefaultRow()]);
+
+
+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.productSpecUnit=item.productSpecUnit;
+    pt.amount=null; 
+    row.usage=item.defaultUsage;
+    pt.totalDose='0' ;
+    pt.dosePerDay='0';
+    pt.firstDay=Math.ceil(row.frequency/2.0);
+    break;
+  } 
+
+  emit('change',JSON.stringify(tableData.value))
+};
+
+const getProductNutritionList = async () => {
+  const res = await listAllNutrition();
+  productNutritionList.value = res.rows;
+}
 
 // 新增行
 const addNewRow = () => {
-  tableData.value.push(createDefaultRow(true));
+  let row: TableRow = createDefaultRow();
+  row.sn = tableData.value.length ;
+  tableData.value.push(row);
+  emit('change',JSON.stringify(tableData.value))
 };
 
 // 新增产品输入框
 const addProduct = (row: TableRow) => {
-  row.products.push({value: '', dosage: ''});
+  row.products.push({});
 };
 
 // 删除产品输入框
@@ -247,35 +314,213 @@ const removeProduct = (row: TableRow, index: number) => {
     if (rowIndex !== -1) {
       tableData.value.splice(rowIndex, 1);
     }
+    emit('change',JSON.stringify(tableData.value))
   } 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]));
+  newRow.tableId = tableId.value++
   tableData.value.splice(index + 1, 0, newRow);
+  tableData.value.forEach((item, index) => {
+    item.sn = index;
+    item.products.forEach((ch, idx) => {
+      if(ch.nutritionProductId){
+        let arr = ch.nutritionProductId.split('_');
+        ch.nutritionProductId = arr[0] + '_' + index + '_' + idx;
+      }     
+    });
+  });
+  emit('change', JSON.stringify(tableData.value))
 };
 
 // 删除行
-const deleteRow = (index: number) => {
-  if (tableData.value.length === 1) return;
+const deleteRow = (index: number) => {   
   tableData.value.splice(index, 1);
+
+  tableData.value.forEach((item, index) => {
+    item.sn = index;
+  });  
+  
+  emit('change',JSON.stringify(tableData.value))
+};
+
+
+const changeUsageDays = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);   
+}
+
+const changeUsage = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changePreparationVolumePerTime = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changeEnergyDensityPerTime = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changePrescriptionRemark = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+
+const firstDayInput = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changeTimeSelection = (value: string, sn:string) => {
+  let row = tableData.value[sn];
+  let frequency=0;
+  row.timeSlots.forEach(item=>{
+    if(item.checked){
+      frequency++;
+    }
+  })
+  row.frequency=frequency;
+  if(value!=null){
+    row.firstDay=Math.ceil(row.frequency/2.0);
+  }
+
+  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);
+
+    let firstDay=Number(row.firstDay.toString());
+    val=(row.frequency*(daysDifference.value-1)+firstDay)*item.configSalePrice*Number(pt.dosePerTime);
+    val=Math.max(0,val);
+    pt.amount=Math.round(val*100)/100;
+
+    val=(row.frequency*(daysDifference.value-1)+firstDay)*Number(pt.dosePerTime);
+    val=Math.max(0,val);
+    pt.totalDose=val.toFixed(4) ;
+
+    val=row.frequency*Number(pt.dosePerTime)
+    pt.dosePerDay=val.toFixed(4) ;
+    break;
+  }
+
+  });  
+
+  emit('change',JSON.stringify(tableData.value));
+};
+
+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);
+
+    let firstDay=Number(row.firstDay.toString());
+    val=(row.frequency*(daysDifference.value-1)+firstDay)*item.configSalePrice*Number(pt.dosePerTime);
+    val=Math.max(0,val);
+    pt.amount=Math.round(val*100)/100;
+
+    val=(row.frequency*(daysDifference.value-1)+firstDay)*Number(pt.dosePerTime);
+    val=Math.max(0,val);
+    pt.totalDose=val.toFixed(4) ;
+
+    val=row.frequency*Number(pt.dosePerTime)
+    pt.dosePerDay=val.toFixed(4) ;
+    break;
+  }
+
+  emit('change',JSON.stringify(tableData.value))
 };
+
+// 禁用今天之前的日期
+const disabledBeforeToday = (date) => {
+  const start = new Date(prop.prescriptionDate);
+  const today = new Date();
+  // 设置时间为今天凌晨,确保比较的是日期而非具体时间
+  today.setHours(0, 0, 0, 0)
+  today.setDate(start.getDate() + 1);
+  return date < today
+}
+
+watch(
+  () => prop.prescriptionDate,
+  async (val: string) => {
+    if (!val || val.trim().length == 0||!stopDate.value||stopDate.value.trim().length == 0) {
+      return;
+    }
+
+    const end = new Date(stopDate.value);
+    const start = new Date(prop.prescriptionDate);
+    if(start>=end){
+      stopDate.value='';
+    }else{
+      handleStopDateChange(stopDate.value);
+    }    
+  },
+  { deep: true, immediate: true }
+);
+
+const handleStopDateChange = (dateVal: any) => {
+  // 定义两个日期
+  const end = new Date(dateVal);
+  const start = new Date(prop.prescriptionDate);
+
+  // 计算时间差(毫秒)
+  const timeDifference = end.getTime() - start.getTime();
+
+  // 将毫秒差转换为天数差  
+  daysDifference.value = timeDifference / (1000 * 60 * 60 * 24) + 1;
+  if (daysDifference.value <= 0) {
+    daysDifference.value = 0;
+    stopDate.value = '';
+  }
+
+  tableData.value.forEach(item=>{
+    item.stopDate=stopDate.value;
+    item.prescriptionDate=prop.prescriptionDate;
+    item.usageDays=daysDifference.value;
+  });
+
+  emit('change',JSON.stringify(tableData.value));
+}
+
+
+onMounted(() => { 
+  getProductNutritionList();
+  tableData.value.forEach(item=>{
+    item.stopDate=stopDate.value;
+    item.prescriptionDate=prop.prescriptionDate;
+    item.usageDays=daysDifference.value;
+  });
+});
 </script>
 
 <style lang="scss" scoped>

+ 277 - 112
src/views/patients/enteralNutrition/components/table/PackageTable.vue

@@ -5,13 +5,17 @@
       <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="product-row" style="margin-bottom:5px;">
+              <el-select v-model="row.nutritionProductId" placeholder="请选择" @change="changeProductSelect">
+                <el-option v-for="pn in productNutritionList" :key="pn.id" :label="pn.productName"
+                  :value="pn.id+'_'+row.sn"></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="deleteProduct(row, index)">
+                <el-button class="icon-btn" @click="deleteProduct(row, row.sn)">
                   <el-icon><Delete /></el-icon>
                 </el-button>
               </div>
@@ -22,8 +26,8 @@
       <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" />
+            <div  class="quantity-input">
+              <el-input v-model="row.quantity" placeholder="请输入" class="input-center" @change="changeQuantityInput"/>
               <span class="unit">袋</span>
             </div>
           </div>
@@ -32,8 +36,8 @@
       <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" />
+            <div  class="dosage-input">
+              <el-input v-model="row.dosePerTime" placeholder="请输入" class="input-center" @input="dosePerTimeInput(row.dosePerTime,row.sn)"/>
               <span class="unit">g</span>
             </div>
           </div>
@@ -44,107 +48,118 @@
           <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"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[1].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[1].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[2].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[2].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[3].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[3].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[4].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[4].checked"
-                />
+                <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" />
-                <el-time-select
-                  v-model="row.timeSlots[5].time"
-                  start="06:00"
-                  step="00:30"
-                  end="22:00"
-                  placeholder="选择时间"
-                  :disabled="!row.timeSlots[5].checked"
-                />
+                <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>
-          <span>一天3次</span>
+        <template #default="{row}">
+          <span>一天{{row.frequency}}次</span>
         </template>
       </el-table-column>
-      <el-table-column label="首日" width="100" align="center">
+      <el-table-column label="首日" width="150" 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>
+          <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}">
-          <span>{{ row.dailyDosage }}g</span>
+          <div class="daily-dosage">
+            <span>{{row.dosePerDay }}</span>
+            <span class="unit">{{ row.productSpecUnit }}</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"  >
+            <span>{{row.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="请选择" @change="changeUsage(row.usage,row.sn)">
+            <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="120" align="center">
+
+      <el-table-column label="处方备注" width="200" align="center">
+        <template #default="{row}">
+          <el-input v-model="row.prescriptionRemark" :maxlength="100" :show-word-limit="true" @change="changePrescriptionRemark(row.usage,row.sn)"/>         
+        </template>
+      </el-table-column>
+
+      <el-table-column label="每日热量" width="100" 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 class="daily-dosage">
+            <span>{{row.dailyCalories }}</span>             
           </div>
         </template>
       </el-table-column>
+
+      <el-table-column label="金额" width="100" align="center">
+        <template #default="{row}"> 
+          <div class="daily-dosage"  >
+            <span>{{row.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="primary" link @click="copyRow($index)">复制餐次</el-button> -->
             <el-button type="danger" link @click="deleteRow($index)">删除</el-button>
           </div>
         </template>
@@ -168,11 +183,11 @@
         <div class="summary-list">
           <div class="summary-item">
             <span class="label">处方费用:</span>
-            <span class="value">¥0.00</span>
+            <span class="value">¥{{ nutritionalFee}}</span>
           </div>
           <div class="summary-item total">
             <span class="label">总计:</span>
-            <span class="value">¥0.00</span>
+            <span class="value">¥{{ totalFee }}</span>
           </div>
         </div>
       </div>
@@ -183,58 +198,59 @@
 <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';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { default_usage } = toRefs < any > (proxy ?.useDict('default_usage'));
+
+
+let productNutritionList=ref<NutritionVO[]>([]);
+let tableId=ref<number>(0);
+ 
+let nutritionalFee=ref(0.0); 
+let totalFee=ref(0.0);
 
 interface TimeSlot {
   checked: boolean;
   time: string;
-}
+} 
 
-interface Product {
-  value: string;
-  quantity: string;
-  dosage: string;
-}
 
-interface TableRow {
-  products: Product[];
+interface TableRow  extends EnteralNutritionForm {
+  products: EnteralNutritionForm[];
   timeSlots: TimeSlot[];
-  firstDayTimes: number;
-  dailyDosage: number;
-  days: number;
+  sn: number;
+  tableId: number;
 }
 
 // 创建默认行数据
 const createDefaultRow = (): TableRow => ({
-  products: [
-    {
-      value: '',
-      quantity: '',
-      dosage: ''
-    }
-  ],
+  products: [{specification:'', dosePerDay:''}],
   timeSlots: [
-    {checked: false, time: '08:00'},
+    {checked: true, time: '08:00'},
     {checked: false, time: '08:30'},
-    {checked: false, time: '12:00'},
+    {checked: true, time: '12:00'},
     {checked: false, time: '12:30'},
-    {checked: false, time: '18:00'},
+    {checked: true, time: '18:00'},
     {checked: false, time: '18:30'}
   ],
-  firstDayTimes: 2,
-  dailyDosage: 2.0,
-  days: 1
+  usageDays:1,
+  frequency:3,
+  firstDay:2,
+  sn:0,
+  tableId:tableId.value++,
 });
 
 // 表格数据
 const tableData = ref<TableRow[]>([createDefaultRow()]);
+const emit = defineEmits(['change']); 
 
 // 添加产品输入框
 const addProduct = (row: TableRow) => {
-  row.products.push({
-    value: '',
-    quantity: '',
-    dosage: ''
-  });
+  addRow();
 };
 
 // 删除产品输入框
@@ -245,28 +261,177 @@ const deleteProduct = (row: TableRow, index: number) => {
     if (rowIndex !== -1) {
       tableData.value.splice(rowIndex, 1);
     }
+    totalFee.value=0.0;
+    nutritionalFee.value=0.0;
   } 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);
+  tableData.value.forEach((item, index) => {
+    item.sn = index;
+  });   
+
+  if(tableData.value.length==0){
+    totalFee.value=0.0;
+    nutritionalFee.value=0.0;
+  }
+
+  emit('change',JSON.stringify(tableData.value))
 };
 
 // 添加行
 const addRow = () => {
-  tableData.value.push(createDefaultRow());
+  let row: TableRow = createDefaultRow();
+  row.sn = tableData.value.length ;
+  tableData.value.push(row);  
+  emit('change',JSON.stringify(tableData.value))
+};
+
+
+
+const getProductNutritionList = async () => {
+  const res = await listAllNutrition();
+  productNutritionList.value = res.rows;
+}
+
+const changeQuantityInput = async () => {
+  emit('change',JSON.stringify(tableData.value));
+}
+
+const dosePerTimeInput = (value: string, sn: number) => {  
+  let row = tableData.value[sn];
+
+  if (!row.dosePerTime || row.dosePerTime.trim().length == 0) {
+    row.dailyCalories = null;
+    row.amount = null;
+    return;
+  }
+
+  totalFee.value=0.0;
+  nutritionalFee.value=0.0;
+
+  let arr = row.nutritionProductId.split('_');
+  for (let item of productNutritionList.value) {
+    if (item.id.toString() != arr[0]) {
+      continue
+    }
+
+
+    let val = item.calorie * row.frequency * Number(row.dosePerTime) / 100.0
+    row.dailyCalories = val.toFixed(4);
+
+    let  firstDay=Number(row.firstDay.toString());
+    val = (row.frequency * (row.usageDays - 1) + firstDay) * item.configSalePrice * Number(row.dosePerTime)
+    row.amount = Math.round(val * 100) / 100;
+    totalFee.value+=row.amount;
+    nutritionalFee.value+=row.amount;
+
+    val = row.frequency * Number(row.dosePerTime)
+    row.dosePerDay = val.toFixed(4);
+    break;
+  }
+
+  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])];
+    row.specification=item.productSpec;
+    row.dosePerTime=null;     
+    row.dailyCalories=null;
+    row.amount=null; 
+    row.productSpecUnit=item.productSpecUnit;
+    row.usage=item.defaultUsage;     
+    row.dosePerDay='0';
+    row.firstDay=Math.ceil(row.frequency/2.0);
+    break;
+  }
+
+  emit('change',JSON.stringify(tableData.value))
+};
+
+const changeUsageDays = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changeUsage = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const changePrescriptionRemark = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);
+}
+
+const firstDayInput = (value: string, sn:string) => { 
+  changeTimeSelection(null,sn);    
+}
+
+const changeTimeSelection = (value: string, sn:string) => {
+  let row = tableData.value[sn];
+  let frequency=0;  
+  row.timeSlots.forEach(item=>{
+    if(item.checked){
+      frequency++;
+    }
+  })
+  row.frequency=frequency;
+   
+  if(value!=null){
+    row.firstDay=Math.ceil(row.frequency/2.0);
+  }  
+
+  if (!row.dosePerTime || row.dosePerTime.trim().length == 0) {
+    return;
+  }
+
+  totalFee.value=0.0;
+  nutritionalFee.value=0.0;
+  let arr=row.nutritionProductId.split('_');
+
+  for (let item of productNutritionList.value) {
+    if (item.id.toString() != arr[0]) {
+      continue
+    }
+
+
+    let val = item.calorie * row.frequency * Number(row.dosePerTime) / 100.0
+    row.dailyCalories = val.toFixed(4);
+
+    let firstDay=Number(row.firstDay.toString());
+    val = (row.frequency * (row.usageDays - 1) + firstDay) * item.configSalePrice * Number(row.dosePerTime)
+     
+    row.amount = Math.round(val * 100) / 100;
+    totalFee.value+=row.amount;
+    nutritionalFee.value+=row.amount;
+
+    val = row.frequency * Number(row.dosePerTime)
+    row.dosePerDay = val.toFixed(4);
+    break;
+  }
+ 
+
+  emit('change',JSON.stringify(tableData.value))
 };
+
+
+onMounted(() => { 
+  getProductNutritionList();
+});
+
 </script>
 
 <style lang="scss" scoped>

+ 2 - 1
src/views/patients/enteralNutrition/index.vue

@@ -2,7 +2,7 @@
   <div class="container">
     <div class="main-content">
       <!-- 左侧卡片 -->
-      <LeftCard  @gotoTop="goHistoryPrescription"/>
+      <LeftCard  @gotoTop="goHistoryPrescription" :patientInfo="patientInfo"/>
       <!-- 右侧卡片 -->
       <RightCard />
     </div>
@@ -13,6 +13,7 @@
 import LeftCard from './components/LeftCard.vue';
 import RightCard from './components/RightCard.vue';
 
+const { patientInfo } = defineProps<{ patientInfo: any }>()
 // 解决bug核心
 const emit = defineEmits(['change']);