소스 검색

膳食治疗ui界面完成

lujh 2 달 전
부모
커밋
c7cf915b2c

+ 4 - 3
eslint.config.ts

@@ -1,7 +1,7 @@
 import pluginVue from 'eslint-plugin-vue';
 import globals from 'globals';
 import prettier from 'eslint-plugin-prettier';
-import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript';
+import {defineConfigWithVueTs, vueTsConfigs} from '@vue/eslint-config-typescript';
 import skipFormatting from '@vue/eslint-config-prettier/skip-formatting';
 
 export default defineConfigWithVueTs(
@@ -23,7 +23,7 @@ export default defineConfigWithVueTs(
   vueTsConfigs.recommended,
   skipFormatting,
   {
-    plugins: { prettier },
+    plugins: {prettier},
     rules: {
       '@typescript-eslint/no-empty-function': 'off',
       '@typescript-eslint/no-explicit-any': 'off',
@@ -38,7 +38,8 @@ export default defineConfigWithVueTs(
       'prettier/prettier': 'error',
       // 允许使用空Object类型 {}
       '@typescript-eslint/no-empty-object-type': 'off',
-      '@typescript-eslint/no-unused-expressions': 'off'
+      '@typescript-eslint/no-unused-expressions': 'off',
+      'vue/no-mutating-props': 'off'
     }
   }
 );

+ 19 - 19
src/utils/request.ts

@@ -1,21 +1,21 @@
-import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
-import { useUserStore } from '@/store/modules/user';
-import { getToken } from '@/utils/auth';
-import { tansParams, blobValidate } from '@/utils/ruoyi';
+import axios, {AxiosResponse, InternalAxiosRequestConfig} from 'axios';
+import {useUserStore} from '@/store/modules/user';
+import {getToken} from '@/utils/auth';
+import {tansParams, blobValidate} from '@/utils/ruoyi';
 import cache from '@/plugins/cache';
-import { HttpStatus } from '@/enums/RespEnum';
-import { errorCode } from '@/utils/errorCode';
-import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
+import {HttpStatus} from '@/enums/RespEnum';
+import {errorCode} from '@/utils/errorCode';
+import {LoadingInstance} from 'element-plus/es/components/loading/src/loading';
 import FileSaver from 'file-saver';
-import { getLanguage } from '@/lang';
-import { encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64 } from '@/utils/crypto';
-import { encrypt, decrypt } from '@/utils/jsencrypt';
+import {getLanguage} from '@/lang';
+import {encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64} from '@/utils/crypto';
+import {encrypt, decrypt} from '@/utils/jsencrypt';
 import router from '@/router';
 
 const encryptHeader = 'encrypt-key';
 let downloadLoadingInstance: LoadingInstance;
 // 是否显示重新登录
-export const isRelogin = { show: false };
+export const isRelogin = {show: false};
 export const globalHeaders = () => {
   return {
     Authorization: 'Bearer ' + getToken(),
@@ -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: import.meta.env.VITE_APP_BASE_API,
+  baseURL: 'http://192.168.1.237/dev-api',
   timeout: 50000
 });
 
@@ -148,20 +148,20 @@ service.interceptors.response.use(
       }
       return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
     } else if (code === HttpStatus.SERVER_ERROR) {
-      ElMessage({ message: msg, type: 'error' });
+      ElMessage({message: msg, type: 'error'});
       return Promise.reject(new Error(msg));
     } else if (code === HttpStatus.WARN) {
-      ElMessage({ message: msg, type: 'warning' });
+      ElMessage({message: msg, type: 'warning'});
       return Promise.reject(new Error(msg));
     } else if (code !== HttpStatus.SUCCESS) {
-      ElNotification.error({ title: msg });
+      ElNotification.error({title: msg});
       return Promise.reject('error');
     } else {
       return Promise.resolve(res.data);
     }
   },
   (error: any) => {
-    let { message } = error;
+    let {message} = error;
     if (message == 'Network Error') {
       message = '后端接口连接异常';
     } else if (message.includes('timeout')) {
@@ -169,13 +169,13 @@ service.interceptors.response.use(
     } else if (message.includes('Request failed with status code')) {
       message = '系统接口' + message.substr(message.length - 3) + '异常';
     }
-    ElMessage({ message: message, type: 'error', duration: 5 * 1000 });
+    ElMessage({message: message, type: 'error', duration: 5 * 1000});
     return Promise.reject(error);
   }
 );
 // 通用下载方法
 export function download(url: string, params: any, fileName: string) {
-  downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
+  downloadLoadingInstance = ElLoading.service({text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)'});
   // prettier-ignore
   return service.post(url, params, {
       transformRequest: [
@@ -207,7 +207,7 @@ export function download(url: string, params: any, fileName: string) {
 
 // GET下载方法
 export function getDownload(url: string, params: any, fileName: string) {
-  downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
+  downloadLoadingInstance = ElLoading.service({text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)'});
   // prettier-ignore
   return service.get(url, {
       params: params,

+ 409 - 0
src/views/patients/dietTherapy/addBalance.vue

@@ -0,0 +1,409 @@
+<template>
+  <div class="container">
+    <div class="header">
+      <el-button @click="goBack" type="primary" plain class="back-btn">
+        <el-icon><ArrowLeft /></el-icon>
+        返回
+      </el-button>
+      <span class="title">平衡膳食</span>
+    </div>
+
+    <el-card class="content-card">
+      <div class="card-title">基本信息</div>
+      <el-row class="form-row">
+        <el-col :span="1">
+          <div class="label">性别:</div>
+        </el-col>
+        <el-col :span="2">
+          <span>女</span>
+        </el-col>
+        <el-col :span="1">
+          <div class="label">年龄:</div>
+        </el-col>
+        <el-col :span="2">
+          <div class="value">44岁3月</div>
+        </el-col>
+        <el-col :span="1">
+          <div class="label required">身高:</div>
+        </el-col>
+        <el-col :span="4">
+          <el-input v-model="form.height" class="with-unit">
+            <template #append>cm</template>
+          </el-input>
+        </el-col>
+        <el-col :span="1" style="margin-left: 20px">
+          <div class="label required">体重:</div>
+        </el-col>
+        <el-col :span="4">
+          <el-input v-model="form.weight" class="with-unit">
+            <template #append>kg</template>
+          </el-input>
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20" class="form-row">
+        <el-col :span="2">
+          <div class="label">禁忌食材:</div>
+        </el-col>
+        <el-col :span="12">
+          <el-select v-model="form.forbiddenFood" placeholder="请选择" style="width: 100%">
+            <el-option label="请选择" value="" />
+          </el-select>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <el-card class="content-card">
+      <div class="card-title">热量计算</div>
+      <el-row class="form-row">
+        <el-col :span="2">
+          <div class="label">理想体重:</div>
+        </el-col>
+        <el-col :span="2">
+          <div class="value">60kg</div>
+        </el-col>
+        <el-col :span="1" style="margin-left: 20px">
+          <div class="label">BMI:</div>
+        </el-col>
+        <el-col :span="2">
+          <div class="value">20.20</div>
+        </el-col>
+        <el-col :span="3" style="margin-left: 20px">
+          <div class="label required">每日所需能量:</div>
+        </el-col>
+        <el-col :span="4">
+          <el-input v-model="form.dailyEnergy" class="with-unit">
+            <template #append>kcal/d</template>
+          </el-input>
+        </el-col>
+        <el-col :span="1">
+          <el-tooltip class="box-item" effect="dark" content="这里是提示信息" placement="top">
+            <el-icon class="info-icon"><QuestionFilled /></el-icon>
+          </el-tooltip>
+        </el-col>
+        <el-col :span="4">
+          <el-tag type="success" class="status-tag">营养状况:正常</el-tag>
+        </el-col>
+      </el-row>
+
+      <el-row class="form-row">
+        <el-col :span="2">
+          <div class="label">体力活动:</div>
+        </el-col>
+        <el-col :span="22">
+          <el-radio-group v-model="form.activity">
+            <el-radio label="1">
+              <el-icon><CircleCheck /></el-icon>
+              静态活动
+            </el-radio>
+            <el-radio label="2">
+              <el-icon><CircleCheck /></el-icon>
+              轻体力活动
+            </el-radio>
+            <el-radio label="3">
+              <el-icon><CircleCheck /></el-icon>
+              中体力活动
+            </el-radio>
+            <el-radio label="4">
+              <el-icon><CircleCheck /></el-icon>
+              重体力活动
+            </el-radio>
+          </el-radio-group>
+        </el-col>
+      </el-row>
+
+      <el-row class="form-row">
+        <el-col :span="2">
+          <div class="label required">应激状态:</div>
+        </el-col>
+        <el-col :span="4">
+          <el-select v-model="form.stressState" placeholder="请选择">
+            <el-option label="低度应激" value="low" />
+          </el-select>
+        </el-col>
+        <el-col :span="2" style="margin-left: 20px">
+          <div class="label">基础代谢:</div>
+        </el-col>
+        <el-col :span="4">
+          <div class="value">897.30kcal/d</div>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <el-card class="content-card">
+      <div class="card-title">比例设置</div>
+      <div class="ratio-section">
+        <div class="ratio-row">
+          <div class="ratio-item">
+            <div class="label">早餐:</div>
+            <el-input v-model="form.breakfast" class="ratio-input">
+              <template #append>%</template>
+            </el-input>
+          </div>
+          <div class="ratio-item">
+            <div class="label">中餐:</div>
+            <el-input v-model="form.lunch" class="ratio-input">
+              <template #append>%</template>
+            </el-input>
+          </div>
+          <div class="ratio-item">
+            <div class="label">晚餐:</div>
+            <el-input v-model="form.dinner" class="ratio-input">
+              <template #append>%</template>
+            </el-input>
+          </div>
+        </div>
+
+        <div class="ratio-row">
+          <div class="ratio-item">
+            <div class="label">碳水化合物:</div>
+            <el-input v-model="form.carbs" class="ratio-input">
+              <template #append>%</template>
+            </el-input>
+          </div>
+          <div class="ratio-item">
+            <div class="label">蛋白质:</div>
+            <el-input v-model="form.protein" class="ratio-input">
+              <template #append>%</template>
+            </el-input>
+          </div>
+          <div class="ratio-item">
+            <div class="label">脂肪:</div>
+            <el-input v-model="form.fat" class="ratio-input">
+              <template #append>%</template>
+            </el-input>
+          </div>
+        </div>
+      </div>
+    </el-card>
+
+    <div class="bottom-btn-card">
+      <div class="btn-wrapper">
+        <el-button>取消</el-button>
+        <el-button type="primary">生成推荐方案</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref} from 'vue';
+import {QuestionFilled, CircleCheck, ArrowLeft} from '@element-plus/icons-vue';
+
+const emit = defineEmits(['goBack']);
+
+const goBack = () => {
+  emit('goBack');
+};
+
+const form = ref({
+  gender: '女',
+  height: '165.00',
+  weight: '55.00',
+  forbiddenFood: '',
+  dailyEnergy: '1800.00',
+  activity: '2',
+  stressState: 'low',
+  breakfast: '30',
+  lunch: '40',
+  dinner: '30',
+  carbs: '60',
+  protein: '15',
+  fat: '25'
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+  padding: 16px;
+  min-height: 100vh;
+  position: relative;
+  padding-bottom: 76px;
+}
+
+.header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+
+  .back-btn {
+    margin-right: 16px;
+    padding: 8px 16px;
+    display: flex;
+    align-items: center;
+
+    .el-icon {
+      margin-right: 4px;
+    }
+  }
+
+  .title {
+    font-size: 16px;
+    font-weight: 500;
+    color: #333;
+  }
+}
+
+.content-card {
+  margin-bottom: 16px;
+
+  :deep(.el-card__body) {
+    padding: 20px;
+  }
+}
+
+.card-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+  margin-bottom: 20px;
+  position: relative;
+  padding-left: 12px;
+
+  &::before {
+    content: '';
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 4px;
+    height: 16px;
+    background: #409eff;
+    border-radius: 2px;
+  }
+}
+
+.form-row {
+  margin-bottom: 20px;
+  align-items: center;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+
+  .label {
+    color: #606266;
+    line-height: 32px;
+    white-space: nowrap;
+
+    &.required::before {
+      content: '*';
+      color: #f56c6c;
+      margin-right: 4px;
+    }
+  }
+
+  .value {
+    line-height: 32px;
+  }
+
+  .unit {
+    margin-left: 8px;
+    color: #606266;
+  }
+
+  :deep(.el-input-number) {
+    width: 120px;
+  }
+}
+
+.with-unit {
+  :deep(.el-input__wrapper) {
+    width: 120px;
+  }
+  :deep(.el-input-group__append) {
+    padding: 0 12px;
+    color: #606266;
+  }
+}
+
+.bottom-btn-card {
+  position: fixed;
+  left: 228px;
+  right: 0;
+  bottom: 50px;
+  padding: 8px 16px;
+  background: #fff;
+  box-shadow: 0 -2px 8px rgba(64, 158, 255, 0.08);
+  z-index: 2000;
+
+  .btn-wrapper {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    gap: 16px;
+
+    .el-button {
+      margin-top: 30px;
+      min-width: 120px;
+      height: 44px;
+      padding: 0 24px;
+    }
+  }
+}
+
+.info-icon {
+  color: #909399;
+  font-size: 16px;
+  cursor: pointer;
+  margin-left: 4px;
+  margin-top: 8px;
+}
+
+.status-tag {
+  padding: 0 12px;
+  height: 32px;
+  line-height: 32px;
+  font-size: 14px;
+}
+
+:deep(.el-radio) {
+  margin-right: 32px;
+  .el-icon {
+    margin-right: 4px;
+    font-size: 16px;
+  }
+}
+
+:deep(.el-select) {
+  width: 100%;
+}
+
+.ratio-section {
+  .ratio-row {
+    display: flex;
+    margin-bottom: 24px;
+
+    &:last-child {
+      margin-bottom: 0;
+    }
+
+    .ratio-item {
+      margin-right: 80px;
+
+      &:last-child {
+        margin-right: 0;
+      }
+
+      .label {
+        color: #606266;
+        margin-bottom: 8px;
+      }
+
+      .ratio-input {
+        width: 200px;
+
+        :deep(.el-input__wrapper) {
+          padding-right: 0;
+        }
+
+        :deep(.el-input-group__append) {
+          padding: 0 12px;
+          color: #606266;
+          background-color: #f5f7fa;
+        }
+      }
+    }
+  }
+}
+</style>

+ 439 - 0
src/views/patients/dietTherapy/addDaily.vue

@@ -0,0 +1,439 @@
+<template>
+  <div class="container">
+    <!-- 中间卡片 -->
+    <div class="add-hospital-wrapper">
+      <div class="header-bar">
+        <el-button @click="goBack" type="primary" plain class="back-btn">
+          <el-icon><ArrowLeft /></el-icon>
+          返回
+        </el-button>
+        <span class="title">日常膳食</span>
+      </div>
+      <div class="form-bar">
+        <el-row :gutter="20" align="middle">
+          <el-col :span="3">
+            <span>配餐日期:</span>
+          </el-col>
+          <el-col :span="8">
+            <el-date-picker
+              v-model="dateRange"
+              type="daterange"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              style="width: 100%"
+            />
+          </el-col>
+          <el-col :span="3">
+            <el-button type="primary">新增食谱</el-button>
+          </el-col>
+          <el-col :span="3">
+            <el-button>食谱模板</el-button>
+          </el-col>
+          <el-col :span="3">
+            <el-button type="danger">全部删除</el-button>
+          </el-col>
+        </el-row>
+      </div>
+      <div class="tab-bar">
+        <el-button type="success" plain icon="Document" class="tab-btn" style="background: #4cd964; color: #fff; border: none">食谱一</el-button>
+      </div>
+      <el-alert
+        title="周食谱模板的食谱数量小于7时,食谱可循环使用"
+        type="warning"
+        show-icon
+        class="mb-2 info-alert"
+        :closable="false"
+        style="background: transparent; border: none; color: #ff9900"
+      />
+
+      <el-table :data="tableData" class="diet-table" border>
+        <el-table-column prop="meal" label="餐次" width="100" align="center" />
+        <el-table-column prop="time" label="用餐时间" width="140" align="center">
+          <template #default="{row}">
+            <el-time-select v-model="row.time" start="06:00" step="00:30" end="22:00" placeholder="选择时间" />
+          </template>
+        </el-table-column>
+        <el-table-column prop="menuName" label="食谱名称">
+          <template #default="{row}">
+            <el-select v-model="row.menuName" placeholder="请选择" style="width: 100%">
+              <el-option label="请选择" value="" />
+            </el-select>
+          </template>
+        </el-table-column>
+        <el-table-column prop="menuCategory" label="食谱分类" width="120" align="center">
+          <template #default="{row}">
+            <el-tag size="small" type="info" v-if="row.menuCategory">{{ row.menuCategory }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="count" label="份数" width="150" align="center">
+          <template #default="{row}">
+            <el-input-number v-model="row.count" :min="1" :max="99" size="small" />
+          </template>
+        </el-table-column>
+        <el-table-column prop="weight" label="食材重量" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.weight || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="calorie" label="热量" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.calorie || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="amount" label="金额" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.amount || '0.00' }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="footer-bar">
+        <span>费用:</span>
+        <span class="amount">0.00元</span>
+      </div>
+    </div>
+    <!-- 饼状图表卡片 -->
+    <el-card>
+      <el-tabs v-model="activeTab" class="mt-4">
+        <el-tab-pane label="三大营养分析" name="nutrition">
+          <div class="nutrition-analysis">
+            <div class="nutrition-header">
+              <div class="nutrition-target">
+                <span>营养设定:</span>
+                <span class="value">{{ nutritionTarget }}kcal/d</span>
+              </div>
+              <div class="nutrition-actual">
+                <span>实际热量:</span>
+                <span class="value">{{ actualCalories }}kcal/d</span>
+              </div>
+            </div>
+
+            <el-row :gutter="24">
+              <el-col :span="14">
+                <el-table :data="nutritionData" border class="mt-4">
+                  <el-table-column prop="name" label="三大营养素" width="180" />
+                  <el-table-column prop="weight" label="质量(g)" width="180" />
+                  <el-table-column prop="ratio" label="热量占比">
+                    <template #default="{row}">
+                      <span>{{ row.ratio }}%</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="reference" label="参考值">
+                    <template #default="{row}">
+                      <span>{{ row.reference }}</span>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-col>
+
+              <el-col :span="10">
+                <div class="chart-container">
+                  <div class="chart-title">三大营养素元素质量占比</div>
+                  <div id="nutritionChart" ref="chartRef" class="chart-content"></div>
+                  <div class="chart-legend">
+                    <span class="legend-item">
+                      <span class="color-block protein"></span>
+                      蛋白质 {{ proteinRatio }}%
+                    </span>
+                    <span class="legend-item">
+                      <span class="color-block fat"></span>
+                      脂肪 {{ fatRatio }}%
+                    </span>
+                    <span class="legend-item">
+                      <span class="color-block carbs"></span>
+                      碳水化合物 {{ carbsRatio }}%
+                    </span>
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+        </el-tab-pane>
+
+        <el-tab-pane label="营养数据分析" name="data">
+          <!-- 营养数据分析内容 -->
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+
+    <!-- 底部按钮卡片 -->
+    <div class="bottom-btn-card">
+      <div class="btn-wrapper">
+        <el-button type="info" plain>存为草稿</el-button>
+        <el-button type="primary">提交</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref, onMounted} from 'vue';
+import * as echarts from 'echarts';
+import {ArrowLeft} from '@element-plus/icons-vue';
+
+const dateRange = ref([]);
+const activeTab = ref('nutrition');
+const nutritionTarget = ref(897.3);
+const actualCalories = ref(0.0);
+const proteinRatio = ref(0);
+const fatRatio = ref(0);
+const carbsRatio = ref(0);
+
+const nutritionData = ref([
+  {name: '蛋白质', weight: '', ratio: 0, reference: '10% - 15%'},
+  {name: '脂肪', weight: '', ratio: 0, reference: '20% - 30%'},
+  {name: '碳水化合物', weight: '', ratio: 0, reference: '50% - 65%'}
+]);
+
+const tableData = ref([
+  {meal: '早餐', time: '08:00', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '早加', time: '08:30', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '中餐', time: '12:00', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '中加', time: '12:30', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '晚餐', time: '18:00', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '晚加', time: '18:30', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''}
+]);
+
+const chartRef = ref<HTMLElement | null>(null);
+let myChart: echarts.ECharts | null = null;
+
+// 初始化图表
+const initChart = () => {
+  if (!chartRef.value) return;
+
+  myChart = echarts.init(chartRef.value);
+  const option = {
+    tooltip: {
+      show: false
+    },
+    legend: {
+      show: false
+    },
+    color: ['#00D1D1', '#FFC53D', '#2F54EB'],
+    series: [
+      {
+        name: '营养元素',
+        type: 'pie',
+        radius: ['70%', '90%'],
+        avoidLabelOverlap: false,
+        silent: true,
+        itemStyle: {
+          borderWidth: 0
+        },
+        label: {
+          show: false
+        },
+        emphasis: {
+          disabled: true
+        },
+        labelLine: {
+          show: false
+        },
+        data: [
+          {value: 33.33, name: '蛋白质'},
+          {value: 33.33, name: '脂肪'},
+          {value: 33.34, name: '碳水化合物'}
+        ]
+      }
+    ]
+  };
+
+  myChart.setOption(option);
+};
+
+const emit = defineEmits(['goBack']);
+// 返回上一页按钮
+const goBack = () => {
+  emit('goBack');
+};
+
+onMounted(() => {
+  initChart();
+  window.addEventListener('resize', () => {
+    myChart?.resize();
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+  position: relative;
+  min-height: 100vh;
+  padding-bottom: 76px; // 底部按钮的高度 + padding
+
+  .el-card {
+    margin-top: 16px;
+    height: 500px;
+  }
+}
+
+.add-hospital-wrapper {
+  background: #fff;
+  border-radius: 12px;
+  padding: 20px 24px 12px 24px;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
+}
+
+.header-bar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+  .back-btn {
+    margin-right: 16px;
+    display: flex;
+    align-items: center;
+    .el-icon {
+      margin-right: 4px;
+    }
+  }
+  .title {
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+
+.form-bar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 12px;
+  .ml-2 {
+    margin-left: 12px;
+  }
+}
+
+.tab-bar {
+  margin-bottom: 8px;
+}
+
+.info-alert {
+  margin-bottom: 8px;
+  font-size: 14px;
+}
+
+.diet-table {
+  margin-bottom: 12px;
+}
+
+.footer-bar {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  font-size: 16px;
+  font-weight: 600;
+  margin: 8px 0;
+  .amount {
+    color: #ff3a00;
+    margin-left: 8px;
+  }
+}
+
+.nutrition-analysis {
+  padding: 12px;
+
+  .nutrition-header {
+    display: flex;
+    gap: 24px;
+    margin-bottom: 12px;
+    font-size: 14px;
+
+    .nutrition-target,
+    .nutrition-actual {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .value {
+        color: #409eff;
+        font-weight: 600;
+      }
+    }
+  }
+}
+
+.chart-container {
+  margin-top: 16px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  text-align: center;
+
+  .chart-title {
+    font-size: 16px;
+    font-weight: 600;
+    margin-bottom: 16px;
+    color: #333;
+  }
+
+  .chart-content {
+    width: 180px;
+    height: 180px;
+    margin: 0 auto;
+  }
+
+  .chart-legend {
+    display: flex;
+    justify-content: center;
+    gap: 32px;
+    margin-top: 24px;
+
+    .legend-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #666;
+      font-size: 13px;
+
+      .color-block {
+        width: 12px;
+        height: 12px;
+        border-radius: 2px;
+
+        &.protein {
+          background-color: #00d1d1;
+        }
+
+        &.fat {
+          background-color: #ffc53d;
+        }
+
+        &.carbs {
+          background-color: #2f54eb;
+        }
+      }
+    }
+  }
+}
+
+.mt-4 {
+  margin-top: 12px;
+}
+
+.bottom-btn-card {
+  position: fixed;
+  left: 228px; // 左侧菜单的宽度
+  right: 0;
+  bottom: 50px;
+  padding: 8px 16px;
+  background: #fff;
+  box-shadow: 0 -2px 8px rgba(64, 158, 255, 0.08);
+  z-index: 2000;
+
+  .btn-wrapper {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .el-button {
+      margin-top: 30px;
+      min-width: 120px;
+      height: 44px;
+      padding: 0 24px;
+    }
+  }
+}
+
+:deep(.el-main) {
+  overflow-x: hidden;
+}
+</style>

+ 0 - 0
src/views/patients/dietTherapy/addForm.vue


+ 423 - 0
src/views/patients/dietTherapy/addHospital.vue

@@ -0,0 +1,423 @@
+<template>
+  <div class="container">
+    <!-- 中间卡片 -->
+    <div class="add-hospital-wrapper">
+      <div class="header-bar">
+        <el-button @click="goBack" type="default" icon="ArrowLeft" class="back-btn">返回</el-button>
+        <span class="title">院内膳食</span>
+      </div>
+      <div class="form-bar">
+        <el-row :gutter="20" align="middle">
+          <el-col :span="3">
+            <span>配餐日期:</span>
+          </el-col>
+          <el-col :span="8">
+            <el-date-picker
+              v-model="dateRange"
+              type="daterange"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              style="width: 100%"
+            />
+          </el-col>
+          <el-col :span="3">
+            <el-button type="primary">新增食谱</el-button>
+          </el-col>
+          <el-col :span="3">
+            <el-button>食谱模板</el-button>
+          </el-col>
+          <el-col :span="3">
+            <el-button type="danger">全部删除</el-button>
+          </el-col>
+        </el-row>
+      </div>
+      <div class="tab-bar">
+        <el-button type="success" plain icon="Document" class="tab-btn" style="background: #4cd964; color: #fff; border: none">食谱一</el-button>
+      </div>
+      <el-alert
+        title="周食谱模板的食谱数量小于7时,食谱可循环使用"
+        type="warning"
+        show-icon
+        class="mb-2 info-alert"
+        :closable="false"
+        style="background: transparent; border: none; color: #ff9900"
+      />
+
+      <el-table :data="tableData" class="diet-table" border>
+        <el-table-column prop="meal" label="餐次" width="100" align="center" />
+        <el-table-column prop="time" label="用餐时间" width="140" align="center">
+          <template #default="{row}">
+            <el-time-select v-model="row.time" start="06:00" step="00:30" end="22:00" placeholder="选择时间" />
+          </template>
+        </el-table-column>
+        <el-table-column prop="menuName" label="食谱名称">
+          <template #default="{row}">
+            <el-select v-model="row.menuName" placeholder="请选择" style="width: 100%">
+              <el-option label="请选择" value="" />
+            </el-select>
+          </template>
+        </el-table-column>
+        <el-table-column prop="menuCategory" label="食谱分类" width="120" align="center">
+          <template #default="{row}">
+            <el-tag size="small" type="info" v-if="row.menuCategory">{{ row.menuCategory }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="count" label="份数" width="150" align="center">
+          <template #default="{row}">
+            <el-input-number v-model="row.count" :min="1" :max="99" size="small" />
+          </template>
+        </el-table-column>
+        <el-table-column prop="weight" label="食材重量" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.weight || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="calorie" label="热量" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.calorie || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="amount" label="金额" width="120" align="center">
+          <template #default="{row}">
+            <span>{{ row.amount || '0.00' }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="footer-bar">
+        <span>费用:</span>
+        <span class="amount">0.00元</span>
+      </div>
+    </div>
+    <!-- 饼状图表卡片 -->
+    <el-card>
+      <el-tabs v-model="activeTab" class="mt-4">
+        <el-tab-pane label="三大营养分析" name="nutrition">
+          <div class="nutrition-analysis">
+            <div class="nutrition-header">
+              <div class="nutrition-target">
+                <span>营养设定:</span>
+                <span class="value">{{ nutritionTarget }}kcal/d</span>
+              </div>
+              <div class="nutrition-actual">
+                <span>实际热量:</span>
+                <span class="value">{{ actualCalories }}kcal/d</span>
+              </div>
+            </div>
+
+            <el-row :gutter="24">
+              <el-col :span="14">
+                <el-table :data="nutritionData" border class="mt-4">
+                  <el-table-column prop="name" label="三大营养素" width="180" />
+                  <el-table-column prop="weight" label="质量(g)" width="180" />
+                  <el-table-column prop="ratio" label="热量占比">
+                    <template #default="{row}">
+                      <span>{{ row.ratio }}%</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="reference" label="参考值">
+                    <template #default="{row}">
+                      <span>{{ row.reference }}</span>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-col>
+
+              <el-col :span="10">
+                <div class="chart-container">
+                  <div class="chart-title">三大营养素元素质量占比</div>
+                  <div id="nutritionChart" class="chart-content"></div>
+                  <div class="chart-legend">
+                    <span class="legend-item">
+                      <span class="color-block protein"></span>
+                      蛋白质 {{ proteinRatio }}%
+                    </span>
+                    <span class="legend-item">
+                      <span class="color-block fat"></span>
+                      脂肪 {{ fatRatio }}%
+                    </span>
+                    <span class="legend-item">
+                      <span class="color-block carbs"></span>
+                      碳水化合物 {{ carbsRatio }}%
+                    </span>
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+        </el-tab-pane>
+
+        <el-tab-pane label="营养数据分析" name="data">
+          <!-- 营养数据分析内容 -->
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+
+    <!-- 底部按钮卡片 -->
+    <div class="bottom-btn-card">
+      <div class="btn-wrapper">
+        <el-button type="info" plain>存为草稿</el-button>
+        <el-button type="primary">提交</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import {ref, onMounted} from 'vue';
+import * as echarts from 'echarts';
+
+const dateRange = ref([]);
+const activeTab = ref('nutrition');
+const nutritionTarget = ref(897.3);
+const actualCalories = ref(0.0);
+const proteinRatio = ref(0);
+const fatRatio = ref(0);
+const carbsRatio = ref(0);
+
+const nutritionData = ref([
+  {name: '蛋白质', weight: '', ratio: 0, reference: '10% - 15%'},
+  {name: '脂肪', weight: '', ratio: 0, reference: '20% - 30%'},
+  {name: '碳水化合物', weight: '', ratio: 0, reference: '50% - 65%'}
+]);
+
+const tableData = ref([
+  {meal: '早餐', time: '08:00', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '早加', time: '08:30', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '中餐', time: '12:00', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '中加', time: '12:30', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '晚餐', time: '18:00', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''},
+  {meal: '晚加', time: '18:30', menuName: '', menuCategory: '', count: 1, weight: '', calorie: '', amount: ''}
+]);
+
+// 初始化图表
+const initChart = () => {
+  const chartDom = document.getElementById('nutritionChart');
+  if (!chartDom) return;
+
+  const myChart = echarts.init(chartDom);
+  const option = {
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      show: false
+    },
+    color: ['#00D1D1', '#FFC53D', '#2F54EB'],
+    series: [
+      {
+        name: '营养元素',
+        type: 'pie',
+        radius: ['60%', '80%'],
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 0,
+          borderColor: '#fff',
+          borderWidth: 2
+        },
+        label: {
+          show: false
+        },
+        emphasis: {
+          disabled: true
+        },
+        labelLine: {
+          show: false
+        },
+        data: [
+          {value: proteinRatio.value || 1, name: '蛋白质'},
+          {value: fatRatio.value || 1, name: '脂肪'},
+          {value: carbsRatio.value || 1, name: '碳水化合物'}
+        ]
+      }
+    ]
+  };
+
+  option && myChart.setOption(option);
+};
+
+const emit = defineEmits(['goBack']);
+// 返回上一页按钮
+const goBack = () => {
+  emit('goBack');
+};
+
+onMounted(() => {
+  initChart();
+});
+</script>
+<style lang="scss" scoped>
+.container {
+  position: relative;
+  min-height: 100vh;
+  padding-bottom: 76px; // 底部按钮的高度 + padding
+
+  .el-card {
+    margin-top: 16px;
+    height: 500px;
+  }
+}
+
+.add-hospital-wrapper {
+  background: #fff;
+  border-radius: 12px;
+  padding: 20px 24px 12px 24px;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
+}
+
+.header-bar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+  .back-btn {
+    margin-right: 16px;
+  }
+  .title {
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+
+.form-bar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 12px;
+  .ml-2 {
+    margin-left: 12px;
+  }
+}
+
+.tab-bar {
+  margin-bottom: 8px;
+}
+
+.info-alert {
+  margin-bottom: 8px;
+  font-size: 14px;
+}
+
+.diet-table {
+  margin-bottom: 12px;
+}
+
+.footer-bar {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  font-size: 16px;
+  font-weight: 600;
+  margin: 8px 0;
+  .amount {
+    color: #ff3a00;
+    margin-left: 8px;
+  }
+}
+
+.nutrition-analysis {
+  padding: 12px;
+
+  .nutrition-header {
+    display: flex;
+    gap: 24px;
+    margin-bottom: 12px;
+    font-size: 14px;
+
+    .nutrition-target,
+    .nutrition-actual {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      .value {
+        color: #409eff;
+        font-weight: 600;
+      }
+    }
+  }
+}
+
+.chart-container {
+  margin-top: 16px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  text-align: center;
+
+  .chart-title {
+    font-size: 16px;
+    font-weight: 600;
+    margin-bottom: 16px;
+    color: #333;
+  }
+
+  .chart-content {
+    height: 200px;
+    width: 200px;
+  }
+
+  .chart-legend {
+    display: flex;
+    justify-content: center;
+    gap: 24px;
+    margin-top: 16px;
+
+    .legend-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      color: #666;
+      font-size: 14px;
+
+      .color-block {
+        width: 12px;
+        height: 12px;
+        border-radius: 2px;
+
+        &.protein {
+          background-color: #00d1d1;
+        }
+
+        &.fat {
+          background-color: #ffc53d;
+        }
+
+        &.carbs {
+          background-color: #2f54eb;
+        }
+      }
+    }
+  }
+}
+
+.mt-4 {
+  margin-top: 12px;
+}
+
+.bottom-btn-card {
+  position: fixed;
+  left: 228px; // 左侧菜单的宽度
+  right: 0;
+  bottom: 50px;
+  padding: 8px 16px;
+  background: #fff;
+  box-shadow: 0 -2px 8px rgba(64, 158, 255, 0.08);
+  z-index: 2000;
+
+  .btn-wrapper {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .el-button {
+      margin-top: 30px;
+      min-width: 120px;
+      height: 44px;
+      padding: 0 24px;
+    }
+  }
+}
+
+:deep(.el-main) {
+  overflow-x: hidden;
+}
+</style>

+ 706 - 0
src/views/patients/dietTherapy/addSmartRec.vue

@@ -0,0 +1,706 @@
+<template>
+  <div class="container">
+    <div class="header-bar">
+      <el-button @click="goBack" type="primary" plain class="back-btn">
+        <el-icon><ArrowLeft /></el-icon>
+        返回
+      </el-button>
+      <span class="title">智能推荐</span>
+    </div>
+
+    <!-- 基本信息 -->
+    <el-card class="content-card">
+      <div class="card-title">基本信息</div>
+      <div class="form-content">
+        <div class="diet-type">
+          <span class="required">基本膳食</span>
+          <el-checkbox-group v-model="dietTypes">
+            <el-checkbox label="普食">普食</el-checkbox>
+            <el-checkbox label="软食">软食</el-checkbox>
+            <el-checkbox label="半流食">半流食</el-checkbox>
+            <el-checkbox label="流食">流食</el-checkbox>
+          </el-checkbox-group>
+        </div>
+        <div class="forbidden-food">
+          <span>禁忌食材</span>
+          <el-select v-model="forbiddenFoods" placeholder="请选择" style="width: 50%">
+            <el-option label="请选择" value="" />
+          </el-select>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 热量计算 -->
+    <el-card class="content-card">
+      <div class="card-title">热量计算</div>
+      <div class="form-content">
+        <div class="form-row">
+          <div class="form-item">
+            <span class="required">身高</span>
+            <div class="input-with-unit">
+              <el-input v-model="height" placeholder="请输入" />
+              <span class="unit">cm</span>
+            </div>
+          </div>
+          <div class="form-item">
+            <span class="required">体重</span>
+            <div class="input-with-unit">
+              <el-input v-model="weight" placeholder="请输入" />
+              <span class="unit">kg</span>
+            </div>
+          </div>
+          <div class="form-item">
+            <span>理想体重:</span>
+            <span class="value">{{ idealWeight }}kg</span>
+          </div>
+        </div>
+
+        <div class="form-row">
+          <div class="form-item physical-activity">
+            <span class="required">体力活动</span>
+            <el-radio-group v-model="activityLevel">
+              <el-radio label="静养活动">静养活动</el-radio>
+              <el-radio label="轻体力活动">轻体力活动</el-radio>
+              <el-radio label="中体力活动">中体力活动</el-radio>
+              <el-radio label="重体力活动">重体力活动</el-radio>
+            </el-radio-group>
+          </div>
+        </div>
+
+        <div class="form-row">
+          <div class="form-item">
+            <span class="required">热量</span>
+            <el-input v-model="calories" placeholder="请输入" style="width: 120px" />
+            <span class="unit">kcal/(kg*d)</span>
+          </div>
+          <div class="form-item">
+            <span>参考范围</span>
+            <el-icon class="info-icon"><QuestionFilled /></el-icon>
+          </div>
+          <div class="form-item">
+            <span>总热量</span>
+            <span class="value">{{ totalCalories }} kcal/d</span>
+          </div>
+          <div class="form-item">
+            <span>体质指标(BMI):</span>
+            <span class="value">{{ bmi }}</span>
+            <span class="status" :style="{color: bmiColor}">正常</span>
+          </div>
+          <div class="form-item bmi-slider">
+            <el-slider
+              v-model="bmiValue"
+              :min="18.5"
+              :max="23.9"
+              :step="0.1"
+              :show-tooltip="false"
+              :marks="{
+                18.5: '18.5',
+                23.9: '23.9'
+              }"
+              style="width: 160px"
+            />
+            <div class="bmi-status-text">
+              <span>20.20(正常)</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 比例设置 -->
+    <el-card class="content-card">
+      <div class="card-title">比例设置</div>
+      <div class="form-content">
+        <div class="ratio-section">
+          <div class="ratio-header">
+            <span>各餐比例:</span>
+            <el-progress :stroke-width="10" :percentage="100" :format="() => '100.00%'" :color="'#00B42A'" :striped="true" :striped-flow="true" />
+          </div>
+
+          <div class="meal-ratios">
+            <div class="ratio-items">
+              <div class="ratio-item">
+                <span>早餐</span>
+                <div class="input-with-unit">
+                  <el-input v-model="breakfast" style="width: 120px" />
+                  <span class="unit">%</span>
+                </div>
+              </div>
+              <div class="ratio-item">
+                <span>早加</span>
+                <div class="input-with-unit">
+                  <el-input v-model="morningSnack" style="width: 120px" />
+                  <span class="unit">%</span>
+                </div>
+              </div>
+              <div class="ratio-item">
+                <span>中餐</span>
+                <div class="input-with-unit">
+                  <el-input v-model="lunch" style="width: 120px" />
+                  <span class="unit">%</span>
+                </div>
+              </div>
+              <div class="ratio-item">
+                <span>中加</span>
+                <div class="input-with-unit">
+                  <el-input v-model="afternoonSnack" style="width: 120px" />
+                  <span class="unit">%</span>
+                </div>
+              </div>
+              <div class="ratio-item">
+                <span>晚餐</span>
+                <div class="input-with-unit">
+                  <el-input v-model="dinner" style="width: 120px" />
+                  <span class="unit">%</span>
+                </div>
+              </div>
+              <div class="ratio-item">
+                <span>晚加</span>
+                <div class="input-with-unit">
+                  <el-input v-model="eveningSnack" style="width: 120px" />
+                  <span class="unit">%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <div class="nutrition-ratio">
+            <span>三大营养素供能比:</span>
+            <el-progress :stroke-width="10" :percentage="95" :format="() => '95%'" :color="'#00B42A'" :striped="true" :striped-flow="true" />
+          </div>
+
+          <div class="nutrition-ratios">
+            <div class="ratio-item">
+              <span>碳水化合物</span>
+              <div class="input-with-unit">
+                <el-input v-model="carbs" style="width: 120px" />
+                <span class="unit">%</span>
+              </div>
+            </div>
+            <div class="ratio-item">
+              <span>蛋白质</span>
+              <div class="input-with-unit">
+                <el-input v-model="protein" style="width: 120px" />
+                <span class="unit">%</span>
+              </div>
+            </div>
+            <div class="ratio-item">
+              <span>脂肪</span>
+              <div class="input-with-unit">
+                <el-input v-model="fat" style="width: 120px" />
+                <span class="unit">%</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 底部按钮 -->
+    <div class="bottom-btn-card">
+      <div class="btn-wrapper">
+        <el-button>取消</el-button>
+        <el-button type="primary">生成推荐方案</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {ref, computed} from 'vue';
+import {ArrowLeft, CircleCheck, QuestionFilled} from '@element-plus/icons-vue';
+
+// 基本信息
+const dietTypes = ref(['普食']);
+const forbiddenFoods = ref('');
+
+// 热量计算
+const height = ref('165.00');
+const weight = ref('55.00');
+const idealWeight = ref(60);
+const activityLevel = ref('静养活动');
+const calories = ref('15.00');
+const totalCalories = computed(() => {
+  const cal = parseFloat(calories.value) || 0;
+  const w = parseFloat(weight.value) || 0;
+  return (cal * w).toFixed(2);
+});
+
+// BMI计算
+const bmi = computed(() => {
+  const h = parseFloat(height.value) || 0;
+  const w = parseFloat(weight.value) || 0;
+  if (!h || !w) return '0.00';
+  return (w / Math.pow(h / 100, 2)).toFixed(2);
+});
+
+const bmiStatus = computed(() => {
+  const bmiValue = parseFloat(bmi.value);
+  if (bmiValue < 18.5) return '偏瘦';
+  if (bmiValue <= 23.9) return '正常';
+  return '偏胖';
+});
+
+const bmiPercentage = computed(() => {
+  const bmiValue = parseFloat(bmi.value);
+  return Math.min(Math.max(((bmiValue - 18.5) / (23.9 - 18.5)) * 100, 0), 100);
+});
+
+const bmiColor = computed(() => {
+  const bmiValue = parseFloat(bmi.value);
+  if (bmiValue < 18.5) return '#FF9900';
+  if (bmiValue <= 23.9) return '#00B42A';
+  return '#FF3A00';
+});
+
+// 比例设置
+const breakfast = ref('30.00');
+const morningSnack = ref('0.00');
+const lunch = ref('40.00');
+const afternoonSnack = ref('0.00');
+const dinner = ref('30.00');
+const eveningSnack = ref('0.00');
+
+// 营养素比例
+const carbs = ref('50.00');
+const protein = ref('15.00');
+const fat = ref('30.00');
+
+const bmiValue = ref(20.2);
+
+const emit = defineEmits(['goBack']);
+// 返回上一页
+const goBack = () => {
+  emit('goBack');
+};
+</script>
+
+<style lang="scss" scoped>
+.container {
+  padding-bottom: 76px;
+}
+
+.header-bar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 16px;
+
+  .back-btn {
+    margin-right: 16px;
+    display: flex;
+    align-items: center;
+    .el-icon {
+      margin-right: 4px;
+    }
+  }
+
+  .title {
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+
+.content-card {
+  margin-bottom: 16px;
+
+  .card-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #1d2129;
+    margin-bottom: 16px;
+    position: relative;
+    padding-left: 12px;
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: 0;
+      top: 50%;
+      transform: translateY(-50%);
+      width: 4px;
+      height: 16px;
+      background-color: #165dff;
+      border-radius: 2px;
+    }
+  }
+
+  .form-content {
+    padding: 0 12px;
+
+    .form-row {
+      display: flex;
+      align-items: center;
+      margin-bottom: 24px;
+      gap: 32px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .form-item {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        &:not(.physical-activity) {
+          min-width: auto;
+        }
+
+        .input-with-unit {
+          display: flex;
+          align-items: center;
+          gap: 8px;
+
+          .el-input {
+            width: 160px;
+          }
+
+          .unit {
+            color: #4e5969;
+            font-size: 14px;
+            white-space: nowrap;
+          }
+        }
+
+        .value {
+          color: #1d2129;
+          font-weight: 600;
+        }
+
+        .info-icon {
+          color: #86909c;
+          cursor: pointer;
+        }
+
+        .bmi-status {
+          font-size: 14px;
+        }
+      }
+    }
+  }
+}
+
+.diet-type {
+  margin-bottom: 16px;
+  display: flex;
+  align-items: center;
+  gap: 16px;
+}
+
+.forbidden-food {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+
+  span {
+    min-width: 70px;
+  }
+}
+
+.form-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-bottom: 16px;
+
+  .input-with-unit {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+  }
+
+  .unit {
+    color: #4e5969;
+    font-size: 14px;
+  }
+
+  .value {
+    color: #1d2129;
+    font-weight: 600;
+  }
+
+  .info-icon {
+    color: #86909c;
+    cursor: pointer;
+  }
+}
+
+.required {
+  position: relative;
+  padding-left: 8px;
+
+  &::before {
+    content: '*';
+    color: #ff3a00;
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+  }
+}
+
+.physical-activity {
+  width: 100%;
+
+  :deep(.el-radio-group) {
+    display: flex;
+    gap: 32px;
+  }
+
+  :deep(.el-radio) {
+    margin-right: 0;
+    height: 32px;
+    .el-radio__label {
+      font-size: 14px;
+      color: #4e5969;
+    }
+  }
+}
+
+.calorie-info {
+  display: flex;
+  align-items: center;
+  flex-wrap: nowrap;
+  gap: 32px;
+  margin-bottom: 16px;
+
+  .info-item {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    white-space: nowrap;
+    color: #4e5969;
+    font-size: 14px;
+
+    .required {
+      position: relative;
+      padding-left: 8px;
+
+      &::before {
+        content: '*';
+        color: #ff3a00;
+        position: absolute;
+        left: 0;
+        top: 50%;
+        transform: translateY(-50%);
+      }
+    }
+
+    .unit {
+      color: #4e5969;
+    }
+
+    .value {
+      color: #1d2129;
+      font-weight: 600;
+    }
+
+    .info-icon {
+      color: #86909c;
+      cursor: pointer;
+    }
+
+    .status {
+      color: #00b42a;
+    }
+  }
+}
+
+.bmi-info {
+  width: 600px;
+  margin: 0 auto;
+
+  .bmi-header {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    margin-bottom: 8px;
+
+    .value {
+      color: #1d2129;
+      font-weight: 600;
+    }
+
+    .bmi-status {
+      font-size: 14px;
+    }
+  }
+
+  .bmi-progress {
+    margin-bottom: 4px;
+
+    :deep(.el-progress) {
+      .el-progress-bar__outer {
+        background-color: #e5e6eb;
+        height: 8px;
+        border-radius: 4px;
+      }
+    }
+
+    .bmi-range {
+      display: flex;
+      justify-content: space-between;
+      color: #86909c;
+      font-size: 13px;
+      margin-top: 4px;
+    }
+  }
+
+  .bmi-status-text {
+    display: flex;
+    align-items: center;
+    gap: 4px;
+    color: #00b42a;
+    font-size: 13px;
+    justify-content: flex-end;
+  }
+}
+
+.total-ratio,
+.nutrition-ratio {
+  margin-bottom: 24px;
+
+  :deep(.el-progress) {
+    margin-top: 8px;
+    .el-progress-bar__outer {
+      background-color: #e5e6eb;
+      height: 8px;
+    }
+  }
+}
+
+.ratio-section {
+  .ratio-header {
+    margin-bottom: 24px;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+
+    span {
+      color: #1d2129;
+      white-space: nowrap;
+    }
+
+    :deep(.el-progress) {
+      width: 240px;
+      .el-progress-bar__outer {
+        background-color: #e5e6eb;
+        height: 10px;
+        border-radius: 20px;
+      }
+      .el-progress-bar__inner {
+        border-radius: 20px;
+        background-color: rgb(28, 202, 141) !important;
+      }
+      .el-progress__text {
+        font-size: 13px !important;
+        color: #fff;
+        margin-left: 4px;
+        background: #2cda9b;
+        padding: 2px 8px;
+        border-radius: 10px;
+      }
+    }
+  }
+
+  .meal-ratios {
+    margin-bottom: 24px;
+
+    .ratio-items {
+      display: flex;
+      flex-wrap: nowrap;
+      gap: 16px;
+      align-items: flex-start;
+    }
+
+    .ratio-item {
+      display: flex;
+      flex-direction: column;
+      gap: 8px;
+      flex: 0 0 auto;
+
+      span {
+        color: #4e5969;
+        font-size: 14px;
+      }
+
+      .input-with-unit {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        .el-input {
+          width: 120px;
+        }
+
+        .unit {
+          color: #4e5969;
+          font-size: 14px;
+        }
+      }
+    }
+  }
+
+  .nutrition-ratio {
+    margin-bottom: 24px;
+    display: flex;
+    align-items: center;
+    gap: 8px;
+
+    span {
+      color: #1d2129;
+      white-space: nowrap;
+    }
+
+    :deep(.el-progress) {
+      width: 240px;
+      .el-progress-bar__outer {
+        background-color: #e5e6eb;
+        height: 10px;
+        border-radius: 20px;
+      }
+      .el-progress-bar__inner {
+        border-radius: 20px;
+        background-color: rgb(28, 202, 141) !important;
+      }
+      .el-progress__text {
+        font-size: 13px !important;
+        color: #fff;
+        margin-left: 4px;
+        background: #2cda9b;
+        padding: 2px 8px;
+        border-radius: 10px;
+      }
+    }
+  }
+
+  .nutrition-ratios {
+    display: flex;
+    gap: 80px;
+  }
+}
+
+.bottom-btn-card {
+  position: fixed;
+  left: 228px;
+  right: 0;
+  bottom: 50px;
+  padding: 8px 16px;
+  background: #fff;
+  box-shadow: 0 -2px 8px rgba(64, 158, 255, 0.08);
+  z-index: 2000;
+
+  .btn-wrapper {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    gap: 16px;
+
+    .el-button {
+      min-width: 120px;
+      height: 44px;
+      padding: 0 24px;
+    }
+  }
+}
+</style>

+ 182 - 1
src/views/patients/dietTherapy/index.vue

@@ -1 +1,182 @@
-<template>膳食治疗</template>
+<template>
+  <div class="container">
+    <!-- 首页的tab列表区域 -->
+    <div v-show="type === PageType.LIST">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+        <el-tab-pane label="院内膳食" name="hospital">
+          <div class="btn_content" @click="handleHospital()">
+            <el-button type="primary">新增{{ tabLabelMap[activeName] }}</el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="平衡膳食" name="balance">
+          <div class="btn_content" @click="handleBalance()">
+            <el-button type="primary">新增{{ tabLabelMap[activeName] }}</el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="日常膳食" name="daily">
+          <div class="btn_content" @click="handleDaily()">
+            <el-button type="primary">新增{{ tabLabelMap[activeName] }}</el-button>
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="智能推荐" name="smart">
+          <div class="btn_content" @click="handleSmartRecommend()">
+            <el-button type="primary">新增{{ tabLabelMap[activeName] }}</el-button>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+
+    <!-- 院内膳食 -->
+    <div v-show="type === PageType.HOSPITAL">
+      <AddHospital @goBack="isType" />
+    </div>
+
+    <!-- 平衡膳食 -->
+    <div v-show="type === PageType.BALANCE">
+      <AddBalance @goBack="isType" />
+    </div>
+
+    <!-- 日常膳食 -->
+    <div v-show="type === PageType.DAILY">
+      <AddDaily @goBack="isType" />
+    </div>
+
+    <!-- 智能推荐 -->
+    <div v-show="type === PageType.SMART">
+      <AddSmartRec @goBack="isType" />
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import {ref} from 'vue';
+import type {TabsPaneContext} from 'element-plus';
+import AddHospital from './addHospital.vue';
+import AddBalance from './addBalance.vue';
+import AddDaily from './addDaily.vue';
+import AddSmartRec from './addSmartRec.vue';
+
+// 使用枚举定义页面类型
+enum PageType {
+  LIST = 'list',
+  HOSPITAL = 'addForm',
+  BALANCE = 'addBalance',
+  DAILY = 'addDaily',
+  SMART = 'addSmart'
+}
+
+// 当前页面类型
+const type = ref<PageType>(PageType.LIST);
+const activeName = ref('hospital');
+
+// tab标签映射
+const tabLabelMap: Record<string, string> = {
+  hospital: '院内膳食',
+  balance: '平衡膳食',
+  daily: '日常膳食',
+  smart: '智能推荐'
+};
+
+// 点击标签
+const handleClick = (tab: TabsPaneContext) => {
+  console.log(tab.paneName);
+};
+
+// 页面跳转处理
+const handlePageChange = (pageType: PageType) => {
+  type.value = pageType;
+};
+
+// 各个按钮的点击处理
+const handleHospital = () => {
+  handlePageChange(PageType.HOSPITAL);
+};
+// 平衡膳食
+const handleBalance = () => {
+  handlePageChange(PageType.BALANCE);
+};
+
+// 日常膳食
+const handleDaily = () => {
+  handlePageChange(PageType.DAILY);
+};
+
+// 智能推荐
+const handleSmartRecommend = () => {
+  handlePageChange(PageType.SMART);
+};
+
+// 返回列表页
+const isType = () => {
+  handlePageChange(PageType.LIST);
+};
+</script>
+<style scoped>
+.demo-tabs {
+  background: #f7f9fb;
+  border-radius: 12px 12px 0 0;
+  padding: 16px 0 0 16px;
+  min-height: 80px;
+}
+
+.btn_content {
+  margin-top: 20px;
+}
+:deep(.el-tabs__header) {
+  border-bottom: none !important;
+  margin-bottom: 0 !important;
+  background: transparent;
+}
+:deep(.el-tabs__nav) {
+  background: transparent;
+  border: none;
+  align-items: center;
+  height: 72px;
+  display: flex;
+}
+:deep(.el-tabs__content) {
+  background: #fff !important;
+  height: 600px;
+}
+:deep(.el-tabs__item) {
+  background: transparent !important;
+  position: relative;
+  z-index: 1;
+  font-size: 16px;
+  color: #333;
+  padding: 0 48px !important;
+  height: 64px;
+  line-height: 64px;
+  display: flex;
+  align-items: center;
+  transition: color 0.2s;
+  border: none !important;
+}
+:deep(.el-tabs__item.is-active) {
+  color: #409eff !important;
+  z-index: 2;
+}
+:deep(.el-tabs__item.is-active)::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  background: #fff;
+  border-radius: 12px 12px 0 0;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.08);
+  z-index: -1;
+}
+
+.diet-content-area {
+  background: #fff;
+  border-radius: 0 0 16px 16px;
+  min-height: 300px;
+  /* 让内容区和Tabs无缝衔接 */
+  margin-top: -24px;
+  padding: 32px 40px;
+  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.04);
+  position: relative;
+  z-index: 1;
+}
+</style>

+ 525 - 524
src/views/patients/medicalRecord/index.vue

@@ -1,539 +1,540 @@
 <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-click="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="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-click="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">
-                    <el-row>
-                        <span>门诊号:{{ patientInfo.outpatientNo }}</span>
-                        <span style="margin-left:30px">科室:{{ patientInfo.deptName }}</span>
-                        <span style="margin-left:30px">营养诊断:</span>
-                    </el-row>
-                    <el-row>
-                        <span>会诊结果:</span>
-                    </el-row>
-                </div>
-            </el-row>
-            <component 
-                :is="currentComponent" 
-                v-if="currentComponent" 
-                :patient-info="patientInfo"
-                @change="handleSelect"
-            />
+        <div class="patient-right-info">
+          <el-row>
+            <span>门诊号:{{ patientInfo.outpatientNo }}</span>
+            <span style="margin-left: 30px">科室:{{ patientInfo.deptName }}</span>
+            <span style="margin-left: 30px">营养诊断:</span>
+          </el-row>
+          <el-row>
+            <span>会诊结果:</span>
+          </el-row>
         </div>
-
-        <!-- 患者详情弹窗 -->
-        <DetailDialog v-model:visible="showDetailDialog" :detail-data="detailData" :physical-activity-dict="physicalActivityDict" @close="handleDetailClose" />
-        <!-- 新增:编辑弹窗 -->
-        <EditDialog v-model:visible="showEditDialog" :edit-data="editData" @close="handleEditClose" @save="handleEditSave" />
+      </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"
+    />
+    <!-- 新增:编辑弹窗 -->
+    <EditDialog v-model:visible="showEditDialog" :edit-data="editData" @close="handleEditClose" @save="handleEditSave" />
+  </div>
 </template>
 
 <script setup lang="ts">
-    import { ref, onMounted, getCurrentInstance, toRefs, defineAsyncComponent } from 'vue';
-    import { useRoute, useRouter } from 'vue-router';
-    import { ArrowLeft } from '@element-plus/icons-vue';
-    import { listTreatmentUser, getTreatmentUser } from '@/api/workbench/treatmentUser';
-    import DetailDialog from './detailDialog.vue';
-    import EditDialog from './editDialog.vue';
-
-    // 动态导入组件
-    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, // “营养病例”对应MedicalRecord.vue
-        checkLabel: CheckLabel, // “检查标签”对应CheckLabel.vue
-        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 ComponentInternalInstance;
-
-    const activeMenu = ref('medicalRecord');
-
-    const patientInfo = ref({
-        id: '',
-        name: '',
-        age: '',
-        gender: '',
-        type: '',
-        deptId: '',
-        deptName: '',
-        outpatientNo: '',
-
-    });
-
-    // 弹窗控制
-    const showDetailDialog = ref(false);
-    const detailData = ref({});
-    const physicalActivityDict = ref([]);
-
-    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 goBack = () => {
-        router.back();
-    };
-
-    const searchValue = ref('');
-    const patientTab = ref('wait');
-    const patientList = ref([]);
-    const loading = ref(false);
-
-    const currentPatientIndex = ref(0);
-
-    const tableRowClassName = ({ row, rowIndex }) => {
-        return rowIndex === currentPatientIndex.value ? 'current-row' : '';
-    };
-
-    const handleRowClick = (row, column, event) => {
-        activeMenu.value = 'medicalRecord';
-        currentComponent.value = componentMap['medicalRecord'];
-        const idx = patientList.value.findIndex(item => item === row);
-        patientInfo.value = row;
-        patientInfo.value.type=route.query.type;
-        patientInfo.value.outpatientNo=route.query.outpatientNo;  
-        if (idx !== -1) {
-            currentPatientIndex.value = idx;
-        }
-    };
-
-    const handlePrev = () => {
-        activeMenu.value = 'medicalRecord';
-        currentComponent.value = componentMap['medicalRecord']
-        if (currentPatientIndex.value > 0) {
-            patientInfo.value = patientList.value[currentPatientIndex.value - 1];
-            patientInfo.value.type=route.query.type;
-            patientInfo.value.outpatientNo=route.query.outpatientNo;  
-            currentPatientIndex.value--;
-        }
+import {ref, onMounted, getCurrentInstance, toRefs, defineAsyncComponent} from 'vue';
+import {useRoute, useRouter} from 'vue-router';
+import {ArrowLeft} from '@element-plus/icons-vue';
+import {listTreatmentUser, getTreatmentUser} from '@/api/workbench/treatmentUser';
+import DetailDialog from './detailDialog.vue';
+import EditDialog from './editDialog.vue';
+
+// 动态导入组件
+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, // “营养病例”对应MedicalRecord.vue
+  checkLabel: CheckLabel, // “检查标签”对应CheckLabel.vue
+  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 ComponentInternalInstance;
+
+const activeMenu = ref('medicalRecord');
+
+const patientInfo = ref({
+  id: '',
+  name: '',
+  age: '',
+  gender: '',
+  type: '',
+  deptId: '',
+  deptName: '',
+  outpatientNo: ''
+});
+
+// 弹窗控制
+const showDetailDialog = ref(false);
+const detailData = ref({});
+const physicalActivityDict = ref([]);
+
+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 goBack = () => {
+  router.back();
+};
+
+const searchValue = ref('');
+const patientTab = ref('wait');
+const patientList = ref([]);
+const loading = ref(false);
+
+const currentPatientIndex = ref(0);
+
+const tableRowClassName = ({row, rowIndex}) => {
+  return rowIndex === currentPatientIndex.value ? 'current-row' : '';
+};
+
+const handleRowClick = (row, column, event) => {
+  activeMenu.value = 'medicalRecord';
+  currentComponent.value = componentMap['medicalRecord'];
+  const idx = patientList.value.findIndex((item) => item === row);
+  patientInfo.value = row;
+  patientInfo.value.type = route.query.type;
+  patientInfo.value.outpatientNo = route.query.outpatientNo;
+  if (idx !== -1) {
+    currentPatientIndex.value = idx;
+  }
+};
+
+const handlePrev = () => {
+  activeMenu.value = 'medicalRecord';
+  currentComponent.value = componentMap['medicalRecord'];
+  if (currentPatientIndex.value > 0) {
+    patientInfo.value = patientList.value[currentPatientIndex.value - 1];
+    patientInfo.value.type = route.query.type;
+    patientInfo.value.outpatientNo = route.query.outpatientNo;
+    currentPatientIndex.value--;
+  }
+};
+
+const handleNext = () => {
+  activeMenu.value = 'medicalRecord';
+  currentComponent.value = componentMap['medicalRecord'];
+  patientInfo.value = patientList.value[currentPatientIndex.value + 1];
+  patientInfo.value.type = route.query.type;
+  patientInfo.value.outpatientNo = route.query.outpatientNo;
+  if (currentPatientIndex.value < patientList.value.length - 1) {
+    currentPatientIndex.value++;
+  }
+};
+const handleTabChange = (tab: string) => {
+  if (tab == 'wait') {
+    getList();
+  } else {
+    patientList.value = [];
+  }
+};
+// 编辑按钮处理
+const handleEdit = async () => {
+  if (!patientInfo.value.id) {
+    proxy?.$modal.msgError('请先选择患者');
+    return;
+  }
+
+  try {
+    // 获取患者详细信息
+    const res = await getTreatmentUser(patientInfo.value.id);
+    editData.value = res.data;
+    showEditDialog.value = true;
+  } catch (error) {
+    console.error('获取患者详情失败:', error);
+    proxy?.$modal.msgError('获取患者详情失败');
+  }
+};
+
+// 详情按钮处理
+const handleDetail = async () => {
+  if (!patientInfo.value.id) {
+    proxy?.$modal.msgError('请先选择患者');
+    return;
+  }
+
+  try {
+    // 获取患者详细信息
+    const res = await getTreatmentUser(patientInfo.value.id);
+    detailData.value = res.data;
+    showDetailDialog.value = true;
+  } catch (error) {
+    console.error('获取患者详情失败:', error);
+    proxy?.$modal.msgError('获取患者详情失败');
+  }
+};
+
+// 详情弹窗关闭处理
+const handleDetailClose = () => {
+  showDetailDialog.value = false;
+  detailData.value = {};
+};
+
+const handleEditClose = () => {
+  showEditDialog.value = false;
+  editData.value = {};
+};
+
+const handleEditSave = (data) => {
+  // 可在此处调用保存API,保存后刷新列表
+  showEditDialog.value = false;
+  proxy?.$modal.msgSuccess('保存成功');
+  getList();
+};
+
+const waitingCount = ref(0);
+const treatingCount = ref(0);
+const treatedCount = ref(0);
+
+const getList = async () => {
+  loading.value = true;
+  try {
+    const params: any = {
+      pageNum: 1,
+      pageSize: 10
     };
-
-    const handleNext = () => {
-        activeMenu.value = 'medicalRecord';
-        currentComponent.value = componentMap['medicalRecord']
-        patientInfo.value = patientList.value[currentPatientIndex.value + 1];
-        patientInfo.value.type=route.query.type;
-        patientInfo.value.outpatientNo=route.query.outpatientNo;  
-        if (currentPatientIndex.value < patientList.value.length - 1) {
-            currentPatientIndex.value++;
-        }
-    };
-    const handleTabChange = (tab: string) => {
-        if (tab == 'wait') {
-            getList();
+    if (searchValue.value) {
+      params.searchFlag = searchValue.value;
+    }
+    const res = await listTreatmentUser(params);
+    console.log('res', JSON.stringify(res));
+
+    patientList.value = (res.rows || []).map((item) => ({
+      id: item.id,
+      name: item.treatName,
+      type: item.type, // 0: 门诊,1: 住院
+      deptId: item.doorId,
+      deptName: item.deptName,
+      outpatientNo: item.outpatientNo,
+      gender: item.sex === '0' ? '男' : item.sex === '1' ? '女' : '',
+      age: item.age
+    }));
+    waitingCount.value = patientList.value.length;
+
+    // 如果有患者数据,根据路由参数或默认选中第一个
+    if (patientList.value.length > 0) {
+      const {id} = route.query;
+      if (id) {
+        // 查找从工作台点击进入的患者
+        const targetIndex = patientList.value.findIndex((patient) => patient.id === id);
+        if (targetIndex !== -1) {
+          patientInfo.value = patientList.value[targetIndex];
+          patientInfo.value.type = route.query.type;
+          patientInfo.value.outpatientNo = route.query.outpatientNo;
+          currentPatientIndex.value = targetIndex;
         } else {
-            patientList.value = [];
+          // 如果没找到,默认选中第一个
+          patientInfo.value = patientList.value[0];
+          currentPatientIndex.value = 0;
         }
-
+      } else {
+        // 没有路由参数,默认选中第一个
+        patientInfo.value = patientList.value[0];
+        patientInfo.value.type = route.query.type;
+        patientInfo.value.outpatientNo = route.query.outpatientNo;
+        currentPatientIndex.value = 0;
+      }
     }
-    // 编辑按钮处理
-    const handleEdit = async () => {
-        if (!patientInfo.value.id) {
-            proxy ?.$modal.msgError('请先选择患者');
-            return;
-        }
 
-        try {
-            // 获取患者详细信息
-            const res = await getTreatmentUser(patientInfo.value.id);
-            editData.value = res.data;
-            showEditDialog.value = true;
-        } catch (error) {
-            console.error('获取患者详情失败:', error);
-            proxy ?.$modal.msgError('获取患者详情失败');
-        }
-    };
-
-    // 详情按钮处理
-    const handleDetail = async () => {
-        if (!patientInfo.value.id) {
-            proxy ?.$modal.msgError('请先选择患者');
-            return;
-        }
-
-        try {
-            // 获取患者详细信息
-            const res = await getTreatmentUser(patientInfo.value.id);
-            detailData.value = res.data;
-            showDetailDialog.value = true;
-        } catch (error) {
-            console.error('获取患者详情失败:', error);
-            proxy ?.$modal.msgError('获取患者详情失败');
-        }
-    };
-
-    // 详情弹窗关闭处理
-    const handleDetailClose = () => {
-        showDetailDialog.value = false;
-        detailData.value = {};
-    };
-
-    const handleEditClose = () => {
-        showEditDialog.value = false;
-        editData.value = {};
-    };
-
-    const handleEditSave = (data) => {
-        // 可在此处调用保存API,保存后刷新列表
-        showEditDialog.value = false;
-        proxy ?.$modal.msgSuccess('保存成功');
-        getList();
-    };
-
-    const waitingCount = ref(0);
-    const treatingCount = ref(0);
-    const treatedCount = ref(0);
-
-
-
-    const getList = async () => {
-        loading.value = true;
-        try {
-            const params: any = {
-                pageNum: 1,
-                pageSize: 10
-            };
-            if (searchValue.value) {
-                params.searchFlag = searchValue.value;
-            }
-            const res = await listTreatmentUser(params);
-            console.log("res", JSON.stringify(res));
-
-            patientList.value = (res.rows || []).map(item => ({
-                id: item.id,
-                name: item.treatName,
-                type: item.type, // 0: 门诊,1: 住院
-                deptId: item.doorId,
-                deptName: item.deptName,
-                outpatientNo: item.outpatientNo,
-                gender: item.sex === '0' ? '男' : item.sex === '1' ? '女' : '',
-                age: item.age
-            }));
-            waitingCount.value = patientList.value.length;
-
-            // 如果有患者数据,根据路由参数或默认选中第一个
-            if (patientList.value.length > 0) {
-                const { id } = route.query;
-                if (id) {
-                    // 查找从工作台点击进入的患者
-                    const targetIndex = patientList.value.findIndex(patient => patient.id === id);
-                    if (targetIndex !== -1) {
-                        patientInfo.value = patientList.value[targetIndex];
-                        patientInfo.value.type=route.query.type;
-                        patientInfo.value.outpatientNo=route.query.outpatientNo;  
-                        currentPatientIndex.value = targetIndex;
-                    } else {
-                        // 如果没找到,默认选中第一个
-                        patientInfo.value = patientList.value[0];
-                        currentPatientIndex.value = 0;
-                    }
-                } else {
-                    // 没有路由参数,默认选中第一个
-                    patientInfo.value = patientList.value[0];
-                    patientInfo.value.type=route.query.type;
-                    patientInfo.value.outpatientNo=route.query.outpatientNo;  
-                    currentPatientIndex.value = 0;
-                }
-            }
-
-            loading.value = false;
-        } catch (error) {
-            console.error('获取列表失败:', error);
-            loading.value = false;
-        }
-    };
-
-    const handleSearch = () => {
-        getList();
-    };
-
-
-
-    onMounted(() => {
-        // 获取体力活动字典
-        const { physical_activity } = toRefs(proxy ?.useDict('physical_activity'));
-        physicalActivityDict.value = physical_activity ?.value || [];
-        patientInfo.value.type=route.query.type;
-        patientInfo.value.outpatientNo=route.query.outpatientNo;   
-        getList();        
-    });
+    loading.value = false;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+    loading.value = false;
+  }
+};
+
+const handleSearch = () => {
+  getList();
+};
+
+onMounted(() => {
+  // 获取体力活动字典
+  const {physical_activity} = toRefs(proxy?.useDict('physical_activity'));
+  physicalActivityDict.value = physical_activity?.value || [];
+  patientInfo.value.type = route.query.type;
+  patientInfo.value.outpatientNo = route.query.outpatientNo;
+  getList();
+});
 </script>
 
 <style lang="scss" scoped>
-    .app-container {
-        display: flex;
-        height: calc(100vh - 50px);
-        background-color: #f5f7fa;
-        margin: -10px;
-    }
-
-    .left-menu {
-        width: 220px;
-        background-color: #fff;
-        border-right: 1px solid #e6e6e6;
-        display: flex;
-        flex-direction: column;
-        padding-bottom: 60px;
-        /* 增加底部padding,为按钮留出空间 */
-        position: relative;
-        overflow: hidden;
-        /* 防止内容溢出 */
-    }
-
-    .back-button {
-        padding: 16px;
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        cursor: pointer;
-        color: #409EFF;
-        border-bottom: 1px solid #e6e6e6;
-        font-size: 14px;
-
-        .el-icon {
-            font-size: 16px;
-        }
-
-        &:hover {
-            background-color: #f5f7fa;
-        }
-    }
-
-    .medical-menu {
-        border-right: none;
-
-        :deep(.el-menu-item) {
-            font-size: 14px;
-            height: 40px;
-            line-height: 40px;
-        }
-    }
-
-    .search-bar {
-        display: flex;
-        align-items: center;
-        padding: 8px 12px 0 12px;
-        gap: 6px;
-    }
-
-    .search-input {
-        flex: 1;
-    }
-
-    .search-btn {
-        margin-left: 0;
-    }
-
-    .patient-tabs {
-        padding: 0 12px;
-        margin-top: 8px;
-    }
-
-    .patient-table {
-        min-width: 220px;
-        overflow-x: auto;
-    }
-
-    .table-patients {
-        table-layout: fixed;
-        width: 100%;
-        min-width: 220px;
-        white-space: nowrap;
-        .el-table__header th {
-            background: #f5f7fa;
-            color: #409eff;
-            font-weight: bold;
-            font-size: 13px;
-            padding: 4px 0;
-        }
-        .el-table__row {
-            cursor: pointer;
-        }
-        .el-table__row.current-row {
-            background: #eaf4ff !important;
-        }
-    }
-
-    .nav-btns {
-        display: flex;
-        justify-content: space-between;
-        gap: 8px;
-        position: absolute;
-        left: 0;
-        right: 0;
-        bottom: 12px;
-        padding: 0 12px;
-        background: #fff;
-        z-index: 1;
-        width: calc(100% - 24px);
-        margin: 0 auto;
-    }
-
-    .main-content {
-        flex: 1;
-        padding: 20px;
-        overflow-y: auto;
-    }
-
-    .patient-left-info {
-        background-color: #fff;
-        height: 100px;
-        padding: 10px;
-        border-radius: 4px;
-        margin-bottom: 20px;
-        width: 11%;
-
-    }
-
-    .patient-right-info {
-        background-color: #fff;
-        height: 100px;
-        padding: 20px;
-        border-radius: 4px;
-        margin-bottom: 20px;
-        width: 86%;
-        margin-left: 30px;
-
-    }
-
-    .info-row {
-        display: flex;
-        align-items: center;
-        white-space: nowrap;
-    }
-    .info-row .name {
-        font-size: 22px;
-    }
-    .info-row .age {
-        margin-left: 30px;
-    }
-    .gender-icon {
-        margin-left: 30px;
-        font-size: 25px;
-        font-weight: bold;
-        line-height: 1;
-        display: inline-block;
-        vertical-align: middle;
-    }
-    .gender-icon.female {
-        color: #ff4949;
-    }
-    .gender-icon.male {
-        color: #409eff;
-    }
-</style>
+.app-container {
+  display: flex;
+  height: calc(100vh - 50px);
+  background-color: #f5f7fa;
+  margin: -10px;
+}
+
+.left-menu {
+  width: 220px;
+  background-color: #fff;
+  border-right: 1px solid #e6e6e6;
+  display: flex;
+  flex-direction: column;
+  padding-bottom: 60px;
+  /* 增加底部padding,为按钮留出空间 */
+  position: relative;
+  overflow: hidden;
+  /* 防止内容溢出 */
+}
+
+.back-button {
+  padding: 16px;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  cursor: pointer;
+  color: #409eff;
+  border-bottom: 1px solid #e6e6e6;
+  font-size: 14px;
+
+  .el-icon {
+    font-size: 16px;
+  }
+
+  &:hover {
+    background-color: #f5f7fa;
+  }
+}
+
+.medical-menu {
+  border-right: none;
+
+  :deep(.el-menu-item) {
+    font-size: 14px;
+    height: 40px;
+    line-height: 40px;
+  }
+}
+
+.search-bar {
+  display: flex;
+  align-items: center;
+  padding: 8px 12px 0 12px;
+  gap: 6px;
+}
+
+.search-input {
+  flex: 1;
+}
+
+.search-btn {
+  margin-left: 0;
+}
+
+.patient-tabs {
+  padding: 0 12px;
+  margin-top: 8px;
+}
+
+.patient-table {
+  min-width: 220px;
+  overflow-x: auto;
+}
+
+.table-patients {
+  table-layout: fixed;
+  width: 100%;
+  min-width: 220px;
+  white-space: nowrap;
+  .el-table__header th {
+    background: #f5f7fa;
+    color: #409eff;
+    font-weight: bold;
+    font-size: 13px;
+    padding: 4px 0;
+  }
+  .el-table__row {
+    cursor: pointer;
+  }
+  .el-table__row.current-row {
+    background: #eaf4ff !important;
+  }
+}
+
+.nav-btns {
+  display: flex;
+  justify-content: space-between;
+  gap: 8px;
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 12px;
+  padding: 0 12px;
+  background: #fff;
+  z-index: 1;
+  width: calc(100% - 24px);
+  margin: 0 auto;
+}
+
+.main-content {
+  flex: 1;
+  padding: 20px;
+  overflow-y: auto;
+}
+
+.patient-left-info {
+  background-color: #fff;
+  height: 100px;
+  padding: 10px;
+  border-radius: 4px;
+  margin-bottom: 20px;
+  width: 11%;
+}
+
+.patient-right-info {
+  background-color: #fff;
+  height: 100px;
+  padding: 20px;
+  border-radius: 4px;
+  margin-bottom: 20px;
+  width: 86%;
+  margin-left: 30px;
+}
+
+.info-row {
+  display: flex;
+  align-items: center;
+  white-space: nowrap;
+}
+.info-row .name {
+  font-size: 22px;
+}
+.info-row .age {
+  margin-left: 30px;
+}
+.gender-icon {
+  margin-left: 30px;
+  font-size: 25px;
+  font-weight: bold;
+  line-height: 1;
+  display: inline-block;
+  vertical-align: middle;
+}
+.gender-icon.female {
+  color: #ff4949;
+}
+.gender-icon.male {
+  color: #409eff;
+}
+</style>

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

@@ -145,9 +145,9 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue';
-import { addSetting, updateSetting } from '@/api/patients/nutritionSetting';
-import type { FormInstance } from 'element-plus';
+import {ref} from 'vue';
+import {addSetting, updateSetting} from '@/api/patients/nutritionSetting';
+import type {FormInstance} from 'element-plus';
 
 // 接收父组件传递的参数
 const props = defineProps({
@@ -178,10 +178,10 @@ const NutritionSettingFormRef = ref<FormInstance>();
 
 // 新增
 const handleAdd = async () => {
-  await addSetting({ ...props.form });
+  await addSetting({...props.form});
 };
 // 更新
 const handleUpdate = async () => {
-  await updateSetting({ ...props.form });
+  await updateSetting({...props.form});
 };
 </script>

+ 346 - 297
src/views/patients/nutritionSetting/index.vue

@@ -1,42 +1,48 @@
 <template>
-    <div class="p-2">
-        <div v-show="type=='list'">
-            <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
-                <div v-show="showSearch" class="mb-[10px]">
-                    <el-card shadow="hover">
-                        <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
-                            <el-form-item label="时间:">
-                                <el-date-picker v-model="queryParams.dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
-                            </el-form-item>
-                            <el-form-item label="看诊类型:">
-                                <el-select v-model="queryParams.type" class="spec-unit-select">
-                                    <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-                                </el-select>
-                            </el-form-item>
-                            <el-form-item label="营养设定方式:">
-                                <el-select v-model="queryParams.type" class="spec-unit-select">
-                                    <el-option v-for="dict in nutrition_setting_type" :key="dict.value" :label="dict.label" :value="dict.value" />
-                                </el-select>
-                            </el-form-item>
-                            <el-form-item>
-                                <el-input v-model="queryParams.searchValue" placeholder="门诊/住院号、医生" style="width: 240px; " clearable />
-                            </el-form-item>
-                            <el-form-item>
-                                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-                            </el-form-item>
-                        </el-form>
-                    </el-card>
-                </div>
-            </transition>
+  <div class="p-2">
+    <div v-show="type == 'list'">
+      <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+        <div v-show="showSearch" class="mb-[10px]">
+          <el-card shadow="hover">
+            <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
+              <el-form-item label="时间:">
+                <el-date-picker
+                  v-model="queryParams.dateRange"
+                  type="daterange"
+                  range-separator="-"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                />
+              </el-form-item>
+              <el-form-item label="看诊类型:">
+                <el-select v-model="queryParams.type" class="spec-unit-select">
+                  <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="营养设定方式:">
+                <el-select v-model="queryParams.type" class="spec-unit-select">
+                  <el-option v-for="dict in nutrition_setting_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-input v-model="queryParams.searchValue" placeholder="门诊/住院号、医生" style="width: 240px" clearable />
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-form-item>
+            </el-form>
+          </el-card>
+        </div>
+      </transition>
 
-            <el-card shadow="never">
-                <template #header>
-                    <el-row :gutter="10" class="mb8">
-                        <el-col :span="1.5">
-                            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patients:nutritionSetting:add']">新增营养设定</el-button>
-                        </el-col>
-                        <!-- <el-col :span="1.5">
+      <el-card shadow="never">
+        <template #header>
+          <el-row :gutter="10" class="mb8">
+            <el-col :span="1.5">
+              <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patients:nutritionSetting:add']">新增营养设定</el-button>
+            </el-col>
+            <!-- <el-col :span="1.5">
                             <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['patients:nutritionSetting:edit']">修改</el-button>
                         </el-col>
                         <el-col :span="1.5">
@@ -45,293 +51,336 @@
                         <el-col :span="1.5">
                             <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['patients:nutritionSetting:export']">导出</el-button>
                         </el-col> -->
-                        <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
-                    </el-row>
-                </template>
+            <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+          </el-row>
+        </template>
 
-                <el-table v-loading="loading" border :data="settingList" @selection-change="handleSelectionChange">
-                    <el-table-column type="selection" width="55" align="center" />
-                    <el-table-column label="时间" align="center" prop="createTime" />
-                    <el-table-column label="看诊类型" align="center" prop="type" />
-                    <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
-                    <el-table-column label="营养设定方式" align="center" prop="settingType" />
-                    <el-table-column label="所需热量(kcal/d)" align="center" prop="type" />
-                    <el-table-column label="评估医生" align="center" prop="createByUser" />
-                    <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-                        <template #default="scope">
-                            <el-tooltip content="修改" placement="top">
-                                <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['patients:nutritionSetting:edit']"></el-button>
-                            </el-tooltip>
-                            <el-tooltip content="删除" placement="top">
-                                <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['patients:nutritionSetting:remove']"></el-button>
-                            </el-tooltip>
-                        </template>
-                    </el-table-column>
-                </el-table>
+        <el-table v-loading="loading" border :data="settingList" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="时间" align="center" prop="createTime" />
+          <el-table-column label="看诊类型" align="center" prop="type" />
+          <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
+          <el-table-column label="营养设定方式" align="center" prop="settingType" />
+          <el-table-column label="所需热量(kcal/d)" align="center" prop="type" />
+          <el-table-column label="评估医生" align="center" prop="createByUser" />
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template #default="scope">
+              <el-tooltip content="修改" placement="top">
+                <el-button
+                  link
+                  type="primary"
+                  icon="Edit"
+                  @click="handleUpdate(scope.row)"
+                  v-hasPermi="['patients:nutritionSetting:edit']"
+                ></el-button>
+              </el-tooltip>
+              <el-tooltip content="删除" placement="top">
+                <el-button
+                  link
+                  type="primary"
+                  icon="Delete"
+                  @click="handleDelete(scope.row)"
+                  v-hasPermi="['patients:nutritionSetting:remove']"
+                ></el-button>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+        </el-table>
 
-                <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
-            </el-card>
-        </div>
-        <div>
-            <el-dialog :title="'选择营养设定'" v-model="dialog.visible" width="737px" append-to-body :close-on-click-modal="false" :show-close="true" class="nutrition-setting-dialog">
-                <el-row :gutter="20" style="margin-bottom: 10px;">
-                    <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '1' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('1')">BEE</el-button>
-                    </el-col>
-                    <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '2' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('2')">DRIS</el-button>
-                    </el-col>
-                </el-row>
-                <el-row :gutter="20">
-                    <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '3' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('3')">拇指测法</el-button>
-                    </el-col>
-                    <el-col :span="12">
-                        <el-button :class="['setting-type-btn', form.settingType === '4' ? 'active' : '']" style="width: 100%; height: 46px;" @click="handleSelectSettingType('4')">烧伤公式</el-button>
-                    </el-col>
-                </el-row>
-            </el-dialog>
-        </div>
-        <div v-show="type=='addForm'">
-            <!-- 添加或修改营养设定对话框 -->
-            <add-form :form="form" :rules="rules" :buttonLoading="buttonLoading" :submitForm="submitForm" :cancel="cancel" />
-        </div>
+        <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      </el-card>
     </div>
+    <div>
+      <el-dialog
+        :title="'选择营养设定'"
+        v-model="dialog.visible"
+        width="737px"
+        append-to-body
+        :close-on-click-modal="false"
+        :show-close="true"
+        class="nutrition-setting-dialog"
+      >
+        <el-row :gutter="20" style="margin-bottom: 10px">
+          <el-col :span="12">
+            <el-button
+              :class="['setting-type-btn', form.settingType === '1' ? 'active' : '']"
+              style="width: 100%; height: 46px"
+              @click="handleSelectSettingType('1')"
+              >BEE</el-button
+            >
+          </el-col>
+          <el-col :span="12">
+            <el-button
+              :class="['setting-type-btn', form.settingType === '2' ? 'active' : '']"
+              style="width: 100%; height: 46px"
+              @click="handleSelectSettingType('2')"
+              >DRIS</el-button
+            >
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-button
+              :class="['setting-type-btn', form.settingType === '3' ? 'active' : '']"
+              style="width: 100%; height: 46px"
+              @click="handleSelectSettingType('3')"
+              >拇指测法</el-button
+            >
+          </el-col>
+          <el-col :span="12">
+            <el-button
+              :class="['setting-type-btn', form.settingType === '4' ? 'active' : '']"
+              style="width: 100%; height: 46px"
+              @click="handleSelectSettingType('4')"
+              >烧伤公式</el-button
+            >
+          </el-col>
+        </el-row>
+      </el-dialog>
+    </div>
+    <div v-show="type == 'addForm'">
+      <!-- 添加或修改营养设定对话框 -->
+      <add-form :form="form" :rules="rules" :buttonLoading="buttonLoading" :submitForm="submitForm" :cancel="cancel" />
+    </div>
+  </div>
 </template>
 
 <script setup name="NutritionSetting" lang="ts">
-    import { listSetting, getSetting, delSetting, addSetting, updateSetting } from '@/api/patients/nutritionSetting';
-    import { NutritionSettingVO, NutritionSettingQuery, NutritionSettingForm } from '@/api/patients/nutritionSetting/types';
-    import AddForm from './addForm.vue';
+import {listSetting, getSetting, delSetting, addSetting, updateSetting} from '@/api/patients/nutritionSetting';
+import {NutritionSettingVO, NutritionSettingQuery, NutritionSettingForm} from '@/api/patients/nutritionSetting/types';
+import AddForm from './addForm.vue';
 
-    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-    const { treatment_user_type, nutrition_setting_type } = toRefs < any > (proxy ?.useDict('treatment_user_type', 'nutrition_setting_type'));
+const {proxy} = getCurrentInstance() as ComponentInternalInstance;
+const {treatment_user_type, nutrition_setting_type} = toRefs<any>(proxy?.useDict('treatment_user_type', 'nutrition_setting_type'));
 
-    const settingList = ref < NutritionSettingVO[] > ([]);
-    const buttonLoading = ref(false);
-    const loading = ref(true);
-    const showSearch = ref(true);
-    const ids = ref < Array < string | number >> ([]);
-    const single = ref(true);
-    const multiple = ref(true);
-    const total = ref(0);
-    const type = ref('list');
+const settingList = ref<NutritionSettingVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const type = ref('list');
 
-    const queryFormRef = ref < ElFormInstance > ();
-    const NutritionSettingFormRef = ref < ElFormInstance > ();
+const queryFormRef = ref<ElFormInstance>();
+const NutritionSettingFormRef = ref<ElFormInstance>();
 
-    const dialog = reactive < DialogOption > ({
-        visible: false,
-        title: ''
-    });
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
 
-    // 声明接收的 props
-    const props = defineProps({
-        patientInfo: {
-            type: Object,
-            required: true,
-            default: () => ({
-                id: '',
-                name: '',
-                age: '',
-                deptId: '',
-                gender: ''
-            })
-        }
-    });
+// 声明接收的 props
+const props = defineProps({
+  patientInfo: {
+    type: Object,
+    required: true,
+    default: () => ({
+      id: '',
+      name: '',
+      age: '',
+      deptId: '',
+      gender: ''
+    })
+  }
+});
 
-    const initFormData: NutritionSettingForm = {
-        id: undefined,
-        caloriesKcalPerDay: undefined,
-        caloriesKcalPerKgDay: undefined,
-        caloriesKjPerDay: undefined,
-        proteinCaloriePercentage: undefined,
-        fatCaloriePercentage: undefined,
-        carbohydrateCaloriePercentage: undefined,
-        proteinGPerKgDay: undefined,
-        proteinGPerDay: undefined,
-        fatGPerKgDay: undefined,
-        fatGPerDay: undefined,
-        carbohydrateGPerKgDay: undefined,
-        carbohydrateGPerDay: undefined,
-        calcium: undefined,
-        potassium: undefined,
-        sodium: undefined,
-        magnesium: undefined,
-        phosphorus: undefined,
-        chloride: undefined,
-        iron: undefined,
-        selenium: undefined,
-        manganese: undefined,
-        fluoride: undefined,
-        molybdenum: undefined,
-        zinc: undefined,
-        copper: undefined,
-        iodine: undefined,
-        chromium: undefined,
-        vitaminA: undefined,
-        vitaminD: undefined,
-        vitaminE: undefined,
-        vitaminK: undefined,
-        vitaminBOne: undefined,
-        vitaminBTwo: undefined,
-        vitaminBSix: undefined,
-        vitaminBTwelve: undefined,
-        niacin: undefined,
-        vitaminC: undefined,
-        folicAcid: undefined,
-        choline: undefined,
-        biotin: undefined,
-        pantothenicAcid: undefined,
-        dietaryFiber: undefined,
-        settingType: undefined,
-        type: props.patientInfo ?.type,
-        deptId: props.patientInfo ?.deptId,
-        deptName: undefined,
-        outpatientNo: props.patientInfo ?.outpatientNo,
-    }
-    const data = reactive < PageData < NutritionSettingForm,
-        NutritionSettingQuery >> ({
-            form: { ...initFormData },
-            queryParams: {
-                pageNum: 1,
-                pageSize: 10,
-                patientId: props.patientInfo ?.id,
-                dateRange: undefined,
-                searchValue: undefined,
-                settingType: undefined,
-                type: undefined,
-                deptId: undefined,
-                outpatientNo: undefined,
-                params: {}
-            },
-            rules: {
-                id: [
-                    { required: true, message: "主键不能为空", trigger: "blur" }
-                ],
-            }
-        });
+const initFormData: NutritionSettingForm = {
+  id: undefined,
+  caloriesKcalPerDay: undefined,
+  caloriesKcalPerKgDay: undefined,
+  caloriesKjPerDay: undefined,
+  proteinCaloriePercentage: undefined,
+  fatCaloriePercentage: undefined,
+  carbohydrateCaloriePercentage: undefined,
+  proteinGPerKgDay: undefined,
+  proteinGPerDay: undefined,
+  fatGPerKgDay: undefined,
+  fatGPerDay: undefined,
+  carbohydrateGPerKgDay: undefined,
+  carbohydrateGPerDay: undefined,
+  calcium: undefined,
+  potassium: undefined,
+  sodium: undefined,
+  magnesium: undefined,
+  phosphorus: undefined,
+  chloride: undefined,
+  iron: undefined,
+  selenium: undefined,
+  manganese: undefined,
+  fluoride: undefined,
+  molybdenum: undefined,
+  zinc: undefined,
+  copper: undefined,
+  iodine: undefined,
+  chromium: undefined,
+  vitaminA: undefined,
+  vitaminD: undefined,
+  vitaminE: undefined,
+  vitaminK: undefined,
+  vitaminBOne: undefined,
+  vitaminBTwo: undefined,
+  vitaminBSix: undefined,
+  vitaminBTwelve: undefined,
+  niacin: undefined,
+  vitaminC: undefined,
+  folicAcid: undefined,
+  choline: undefined,
+  biotin: undefined,
+  pantothenicAcid: undefined,
+  dietaryFiber: undefined,
+  settingType: undefined,
+  type: props.patientInfo?.type,
+  deptId: props.patientInfo?.deptId,
+  deptName: undefined,
+  outpatientNo: props.patientInfo?.outpatientNo
+};
+const data = reactive<PageData<NutritionSettingForm, NutritionSettingQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    patientId: props.patientInfo?.id,
+    dateRange: undefined,
+    searchValue: undefined,
+    settingType: undefined,
+    type: undefined,
+    deptId: undefined,
+    outpatientNo: undefined,
+    params: {}
+  },
+  rules: {
+    id: [{required: true, message: '主键不能为空', trigger: 'blur'}]
+  }
+});
 
-    const { queryParams, form, rules } = toRefs(data);
+const {queryParams, form, rules} = toRefs(data);
 
-    /** 查询营养设定列表 */
-    const getList = async () => {
-        loading.value = true;
-        const res = await listSetting(queryParams.value);
-        settingList.value = res.rows;
-        total.value = res.total;
-        loading.value = false;
-    }
+/** 查询营养设定列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listSetting(queryParams.value);
+  settingList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
 
-    const handleSelectSettingType = (settingType) => {
-        form.value.settingType = settingType;
-        
-        dialog.visible = false;
-        // 切换到表单填写界面
-        nextTick(() => {
-            type.value = 'addForm';
-        });
-    };
+const handleSelectSettingType = (settingType) => {
+  form.value.settingType = settingType;
 
-    /** 取消按钮 */
-    const cancel = () => {
-        reset();
-        dialog.visible = false;
-    }
+  dialog.visible = false;
+  // 切换到表单填写界面
+  nextTick(() => {
+    type.value = 'addForm';
+  });
+};
 
-    /** 表单重置 */
-    const reset = () => {
-        form.value = { ...initFormData };
-        NutritionSettingFormRef.value ?.resetFields();
-    }
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
 
-    /** 搜索按钮操作 */
-    const handleQuery = () => {
-        queryParams.value.pageNum = 1;
-        getList();
-    }
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  NutritionSettingFormRef.value?.resetFields();
+};
 
-    /** 重置按钮操作 */
-    const resetQuery = () => {
-        queryFormRef.value ?.resetFields();
-        handleQuery();
-    }
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
 
-    /** 多选框选中数据 */
-    const handleSelectionChange = (selection: NutritionSettingVO[]) => {
-        ids.value = selection.map(item => item.id);
-        single.value = selection.length != 1;
-        multiple.value = !selection.length;
-    }
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
 
-    /** 新增按钮操作 */
-    const handleAdd = () => {
-        reset();
-        dialog.visible = true;
-        dialog.title = "添加营养设定";
-    }
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: NutritionSettingVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
 
-    /** 修改按钮操作 */
-    const handleUpdate = async (row ? : NutritionSettingVO) => {
-        reset();
-        const _id = row ?.id || ids.value[0]
-        const res = await getSetting(_id);
-        Object.assign(form.value, res.data);
-        dialog.visible = true;
-        dialog.title = "修改营养设定";
-    }
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = '添加营养设定';
+};
 
-    /** 提交按钮 */
-    const submitForm = () => {
-        NutritionSettingFormRef.value ?.validate(async (valid: boolean) => {
-            if (valid) {
-                buttonLoading.value = true;
-                if (form.value.id) {
-                    await updateSetting(form.value).finally(() => buttonLoading.value = false);
-                } else {
-                    await addSetting(form.value).finally(() => buttonLoading.value = false);
-                }
-                proxy ?.$modal.msgSuccess("操作成功");
-                dialog.visible = false;
-                await getList();
-            }
-        });
-    }
+/** 修改按钮操作 */
+const handleUpdate = async (row?: NutritionSettingVO) => {
+  reset();
+  const _id = row?.id || ids.value[0];
+  const res = await getSetting(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = '修改营养设定';
+};
 
-    /** 删除按钮操作 */
-    const handleDelete = async (row ? : NutritionSettingVO) => {
-        const _ids = row ?.id || ids.value;
-        await proxy ?.$modal.confirm('是否确认删除营养设定编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
-        await delSetting(_ids);
-        proxy ?.$modal.msgSuccess("删除成功");
-        await getList();
+/** 提交按钮 */
+const submitForm = () => {
+  NutritionSettingFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateSetting(form.value).finally(() => (buttonLoading.value = false));
+      } else {
+        await addSetting(form.value).finally(() => (buttonLoading.value = false));
+      }
+      proxy?.$modal.msgSuccess('操作成功');
+      dialog.visible = false;
+      await getList();
     }
+  });
+};
 
-    /** 导出按钮操作 */
-    const handleExport = () => {
-        proxy ?.download('/patients/nutritionSetting/export', {
-            ...queryParams.value
-        }, `setting_${new Date().getTime()}.xlsx`)
-    }
+/** 删除按钮操作 */
+const handleDelete = async (row?: NutritionSettingVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除营养设定编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delSetting(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    '/patients/nutritionSetting/export',
+    {
+      ...queryParams.value
+    },
+    `setting_${new Date().getTime()}.xlsx`
+  );
+};
 
-    onMounted(() => {
-        getList();
-    });
+onMounted(() => {
+  getList();
+});
 </script>
 <style scoped>
-    .nutrition-setting-dialog .setting-type-btn {
-        font-size: 18px;
-        border: 1.5px solid #409EFF;
-        color: #409EFF;
-        background: #fff;
-        transition: background 0.2s, color 0.2s;
-    }
+.nutrition-setting-dialog .setting-type-btn {
+  font-size: 18px;
+  border: 1.5px solid #409eff;
+  color: #409eff;
+  background: #fff;
+  transition:
+    background 0.2s,
+    color 0.2s;
+}
 
-    .nutrition-setting-dialog .setting-type-btn.active,
-    .nutrition-setting-dialog .setting-type-btn:active,
-    .nutrition-setting-dialog .setting-type-btn:focus {
-        background: #e6f0ff;
-        color: #409EFF;
-        border-color: #409EFF;
-    }
-</style>
+.nutrition-setting-dialog .setting-type-btn.active,
+.nutrition-setting-dialog .setting-type-btn:active,
+.nutrition-setting-dialog .setting-type-btn:focus {
+  background: #e6f0ff;
+  color: #409eff;
+  border-color: #409eff;
+}
+</style>

+ 7 - 10
vite.config.ts

@@ -1,11 +1,10 @@
-import { defineConfig, loadEnv } from 'vite';
+import {defineConfig, loadEnv} from 'vite';
 import createPlugins from './vite/plugins';
 import autoprefixer from 'autoprefixer'; // css自动添加兼容性前缀
 import path from 'path';
 import ElementPlus from 'unplugin-element-plus/vite'; // 新增导入
 
-export default defineConfig(({ mode, command }) => {
-    
+export default defineConfig(({mode, command}) => {
   const env = loadEnv(mode, process.cwd());
   return {
     // 部署生产环境和开发环境下的URL。
@@ -21,18 +20,18 @@ export default defineConfig(({ mode, command }) => {
     // https://cn.vitejs.dev/config/#resolve-extensions
     plugins: [
       ...createPlugins(env, command === 'build'), // 保留原有插件
-      ElementPlus({ useSource: true }), // 新增 ElementPlus 自动导入样式
+      ElementPlus({useSource: true}) // 新增 ElementPlus 自动导入样式
     ],
     server: {
       host: '0.0.0.0',
       port: Number(env.VITE_APP_PORT),
       open: true,
       proxy: {
-        [env.VITE_APP_BASE_API]: {
-          target: 'http://localhost:8080',
+        '/dev-api': {
+          target: 'http://192.168.1.237',
           changeOrigin: true,
           ws: true,
-          rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
+          rewrite: (path) => path.replace(/^\/dev-api/, '')
         }
       }
     },
@@ -46,7 +45,6 @@ export default defineConfig(({ mode, command }) => {
       },
       postcss: {
         plugins: [
-      
           // 浏览器兼容性
           autoprefixer(),
           {
@@ -56,8 +54,7 @@ export default defineConfig(({ mode, command }) => {
                 atRule.remove();
               }
             }
-          },
-          
+          }
         ]
       }
     },