Эх сурвалжийг харах

营养诊断 会诊模板等

HuRongxin 1 сар өмнө
parent
commit
d0eee246a5
22 өөрчлөгдсөн 1828 нэмэгдсэн , 198 устгасан
  1. 63 0
      src/api/parameter/basicPublicTemplate/nutritionEducationTemplate/index.ts
  2. 133 0
      src/api/parameter/basicPublicTemplate/nutritionEducationTemplate/types.ts
  3. 42 2
      src/api/patients/diagnosis/types.ts
  4. 2 0
      src/api/workbench/treatmentUser/types.ts
  5. 114 4
      src/views/parameter/basicPublicTemplate/consultantResultTemplate/addOrEditForm.vue
  6. 2 5
      src/views/parameter/basicPublicTemplate/consultantResultTemplate/index.vue
  7. 199 0
      src/views/parameter/basicPublicTemplate/nutritionEducationTemplate/addOrEditForm.vue
  8. 307 0
      src/views/parameter/basicPublicTemplate/nutritionEducationTemplate/index.vue
  9. 178 0
      src/views/parameter/basicPublicTemplate/nutritionEducationTemplate/templateDetail.vue
  10. 9 29
      src/views/patients/checkLabel/index.vue
  11. 1 1
      src/views/patients/medicalRecord/detailDialog.vue
  12. 1 1
      src/views/patients/medicalRecord/editDialog.vue
  13. 59 36
      src/views/patients/medicalRecord/index.vue
  14. 216 0
      src/views/patients/medicalRecord/levelMenu.vue
  15. 33 68
      src/views/patients/medicalRecord/levelMenu/medicalRecord/index.vue
  16. 105 0
      src/views/patients/medicalRecord/levelMenu/nutriDiagnosis/index.vue
  17. 200 0
      src/views/patients/medicalRecord/levelMenu/visitRecord/index.vue
  18. 2 2
      src/views/patients/nutriDiagnosis/consultantTemplateDialog.vue
  19. 60 0
      src/views/patients/nutriDiagnosis/detailDialog.vue
  20. 96 45
      src/views/patients/nutriDiagnosis/index.vue
  21. 1 0
      src/views/patients/nutritionEducation/index.vue
  22. 5 5
      src/views/workbench/treatmentUser/index.vue

+ 63 - 0
src/api/parameter/basicPublicTemplate/nutritionEducationTemplate/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { EducationTemplateVO, EducationTemplateForm, EducationTemplateQuery } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate/types';
+
+/**
+ * 查询营养宣教模板列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listEducationTemplate = (query?: EducationTemplateQuery): AxiosPromise<EducationTemplateVO[]> => {
+    return request({
+        url: '/basicPublicTemplate/educationTemplate/list',
+        method: 'get',
+        params: query
+    });
+};
+
+/**
+ * 查询营养宣教模板详细
+ * @param id
+ */
+export const getEducationTemplate = (id: string | number): AxiosPromise<EducationTemplateVO> => {
+    return request({
+        url: '/basicPublicTemplate/educationTemplate/' + id,
+        method: 'get'
+    });
+};
+
+/**
+ * 新增营养宣教模板
+ * @param data
+ */
+export const addEducationTemplate = (data: EducationTemplateForm) => {
+    return request({
+        url: '/basicPublicTemplate/educationTemplate',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 修改营养宣教模板
+ * @param data
+ */
+export const updateEducationTemplate = (data: EducationTemplateForm) => {
+    return request({
+        url: '/basicPublicTemplate/educationTemplate',
+        method: 'put',
+        data: data
+    });
+};
+
+/**
+ * 删除营养宣教模板
+ * @param id
+ */
+export const delEducationTemplate = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/basicPublicTemplate/educationTemplate/' + id,
+        method: 'delete'
+    });
+};

+ 133 - 0
src/api/parameter/basicPublicTemplate/nutritionEducationTemplate/types.ts

@@ -0,0 +1,133 @@
+export interface EducationTemplateVO {
+    /**
+     * 
+     */
+    id: string | number;
+
+    /**
+     * 模板名称
+     */
+    templateName: string;
+
+    /**
+     * 适用科室
+     */
+    deptId: string | number;
+
+    deptName: string;
+
+    /**
+     * 疾病标签id
+     */
+    diseaseLabelId: string | number;
+
+    /**
+     * 模板描述
+     */
+    description: string;
+
+    /**
+     * 正文
+     */
+    content: string;
+
+    /**
+     * 最后修改人部门
+     */
+    updateDept: number;
+}
+
+export interface EducationTemplateForm extends BaseEntity {
+    /**
+     * 
+     */
+    id?: string | number;
+
+    /**
+     * 模板名称
+     */
+    templateName?: string;
+
+    /**
+     * 适用科室
+     */
+    deptId?: string | number;
+
+    deptIdList?: any[];
+
+    /**
+     * 疾病标签id
+     */
+    diseaseLabelId?: string | number;
+
+    labelList?: any[];
+
+    /**
+     * 模板描述
+     */
+    description?: string;
+
+    /**
+     * 正文
+     */
+    content?: string;
+
+    contentStr?: string
+
+    /**
+     * 最后修改人部门
+     */
+    updateDept?: number;
+
+    startTime?: string;
+
+    endTime?: string
+
+
+}
+
+export interface EducationTemplateQuery extends PageQuery {
+
+    /**
+     * 模板名称
+     */
+    searchValue?: string;
+
+    /**
+     * 适用科室
+     */
+    deptId?: string | number;
+
+    /**
+     * 疾病标签id
+     */
+    diseaseLabelId?: string | number;
+
+    /**
+     * 模板描述
+     */
+    description?: string;
+
+
+    dateRange?: string[];
+
+    /**
+     * 正文
+     */
+    content?: string;
+
+    /**
+     * 最后修改人部门
+     */
+    updateDept?: number;
+
+    createDept?: number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 42 - 2
src/api/patients/diagnosis/types.ts

@@ -9,6 +9,16 @@ export interface DiagnosisVO {
      */
     treatmentUserId: string | number;
 
+    /**
+ * 看诊类型
+ */
+    type: string;
+
+    /**
+     * 门诊号
+     */
+    outpatientNo: string;
+
     /**
      * 会诊结果模板id
      */
@@ -24,6 +34,8 @@ export interface DiagnosisVO {
      */
     diagnosisBasisId: string | number;
 
+    consultantResult: string;
+
     /**
      * 医嘱
      */
@@ -39,11 +51,26 @@ export interface DiagnosisForm extends BaseEntity {
      */
     id?: string | number;
 
-    dateRange?: string[];
+    dateRange?: any[];
+
+    /**
+ * 看诊类型
+ */
+    type?: string;
+
+    /**
+     * 门诊号
+     */
+    outpatientNo?: string;
+
+    labelList?: any[];
 
     visitType?: string;
 
-    consultationContent?: string;
+    // 会诊结果
+    consultantResult?: string;
+
+    consultantResultStr?: string;
 
     /**
      * 患者id
@@ -65,6 +92,7 @@ export interface DiagnosisForm extends BaseEntity {
      */
     diagnosisBasisId?: string | number;
 
+
     /**
      * 医嘱
      */
@@ -79,6 +107,16 @@ export interface DiagnosisQuery extends PageQuery {
      */
     treatmentUserId?: string | number;
 
+    /**
+  * 看诊类型
+  */
+    type?: string;
+
+    /**
+     * 门诊号
+     */
+    outpatientNo?: string;
+
     dateRange?: string[];
 
     visitType?: string | number;
@@ -101,6 +139,8 @@ export interface DiagnosisQuery extends PageQuery {
      */
     diagnosisBasisId?: string | number;
 
+    consultantResult?: string;
+
     /**
      * 医嘱
      */

+ 2 - 0
src/api/workbench/treatmentUser/types.ts

@@ -94,6 +94,8 @@ export interface TreatmentUserVo {
    */
   admissionDate: string;
 
+  deptName: string;
+
 }
 
 export interface TreatmentUserForm extends BaseEntity {

+ 114 - 4
src/views/parameter/basicPublicTemplate/consultantResultTemplate/addOrEditForm.vue

@@ -29,8 +29,10 @@
                             <el-input v-model="form.description" type="textarea" placeholder="请输入模板描述" />
                         </el-form-item>
                     </el-col>
+                    <el-col :span="5">
+                        <el-button type="primary" plain @click="handleParamDetail">参数说明</el-button>
+                    </el-col>
                 </el-row>
-
                 <el-row :gutter="20">
                     <el-col :span="20">
                         <el-form-item label="正文" prop="content">
@@ -38,14 +40,88 @@
                         </el-form-item>
                     </el-col>
                 </el-row>
-
             </el-form>
+            <el-dialog title="参数说明" v-model="detailDialog.visible" width="30%" :close-on-click-modal="false" append-to-body>
+                <div class="detail-container">
+                    <div class="detail-row">
+                        <div class="detail-label">会诊目的</div>
+                        <div class="detail-content">${purpose}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">身高</div>
+                        <div class="detail-content">${height}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">体重</div>
+                        <div class="detail-content">${weight}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">BMI</div>
+                        <div class="detail-content">${bmi}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">近6个月体重变化</div>
+                        <div class="detail-content">${lossWeight}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">体重下降率</div>
+                        <div class="detail-content">${lossWeightRate}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">24h 摄入情况:能量</div>
+                        <div class="detail-content">${totalFood24retrospectCalories}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">24h 摄入情况:蛋白质</div>
+                        <div class="detail-content">${totalFood24retrospectProtein}</div>
+                    </div>
+                    <div class="detail-row">
+                        <div class="detail-label">白蛋白</div>
+                        <div class="detail-content">${alb}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">前白蛋白</div>
+                        <div class="detail-content">${beforeAlb}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">血红蛋白</div>
+                        <div class="detail-content">${hgb}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">营养风险筛查</div>
+                        <div class="detail-content">${nrs2002Score} ${nrs2002Conclusion}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">营养不良评定</div>
+                        <div class="detail-content">${glimResult}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">途径</div>
+                        <div class="detail-content">${way}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">经口膳食:能量</div>
+                        <div class="detail-content">${totalCalories}</div>
+                    </div>
+                     <div class="detail-row">
+                        <div class="detail-label">经口膳食:蛋白质</div>
+                        <div class="detail-content">${totalProtein}</div>
+                    </div>
+                </div>
+                <template #footer>
+                    <div class="dialog-footer" style="text-align: center">
+                        <el-button size="large" @click="detailDialog.visible = false">关闭</el-button>
+                    </div>
+                </template>
+            </el-dialog>
             <div class="flex justify-center gap-2 mt-4">
                 <el-button :loading="buttonLoading" type="primary" @click="submitForm">保 存</el-button>
             </div>
+
         </el-card>
         <!-- 添加模板类型管理弹窗 -->
         <ResultTemplateTypeDialog ref="resultTemplateTypeDialogRef" @success="getTemplateTypeList" />
+
     </div>
 </template>
 
@@ -58,7 +134,6 @@
         getResultTemplate
     } from '@/api/parameter/basicPublicTemplate/consultantResultTemplate';
     import { ResultTemplateForm } from '@/api/parameter/basicPublicTemplate/consultantResultTemplate/types';
-    import Editor from '@/components/Editor/index.vue';
     import ResultTemplateTypeDialog from '../consultantResultTemplateType/resultTemplateTypeDialog.vue';
     import { listResultTemplateType } from '@/api/parameter/basicPublicTemplate/consultantResultTemplateType';
     import type { ResultTemplateTypeQuery } from '@/api/parameter/basicPublicTemplate/consultantResultTemplateType/types';
@@ -75,6 +150,10 @@
         label: string;
     }
 
+    const detailDialog = reactive < DialogOption > ({
+        visible: false
+    });
+
     const templateTypeList = ref(JSON.parse(route.query.templateTypeList as string || '[]'));
 
     const initFormData: ResultTemplateForm = {
@@ -128,6 +207,10 @@
         resultTemplateTypeDialogRef.value.open();
     };
 
+    const handleParamDetail = () => {
+        detailDialog.visible = true; // 打开弹窗
+    };
+
     // 返回按钮
     const goBack = () => {
         router.back();
@@ -196,4 +279,31 @@
             }
         }
     });
-</script>
+</script>
+<style scoped>
+ .detail-container {
+        background: #fff;
+    }
+
+    .detail-row {
+        display: flex;
+        border-bottom: 1px solid #dcdfe6;
+    }
+     .detail-row:last-child {
+        border-bottom: none;
+    }
+
+    .detail-label {
+        width: 50%;
+        padding: 12px 20px;
+        background: #f5f7fa;
+        border-right: 1px solid #dcdfe6;
+        box-sizing: border-box;
+    }
+
+    .detail-content {
+        width: 50%;
+        padding: 12px 20px;
+        box-sizing: border-box;
+    }
+    </style>

+ 2 - 5
src/views/parameter/basicPublicTemplate/consultantResultTemplate/index.vue

@@ -7,9 +7,6 @@
                         <el-form-item label="开始时间">
                             <el-date-picker v-model="queryParams.startTime" type="datetime" placeholder="选择开始时间" clearable />
                             <el-date-picker v-model="queryParams.endTime" type="datetime" placeholder="选择结束时间" clearable />
-                        </el-form-item>
-                        <el-form-item>
-
                         </el-form-item>
                         <el-form-item label="创建人科室">
                             <el-tree-select v-model="queryParams.createBy" :data="treeData" :props="treeProps" placeholder="请选择" check-strictly node-key="id" @keyup.enter="handleQuery" />
@@ -54,10 +51,10 @@
                     </template>
                 </el-table-column>
                 <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
-                <el-table-column label="创建人姓名" align="center" prop="createBy" />
+                <el-table-column label="创建人姓名" align="center" prop="createByUser" />
                 <el-table-column label="创建人科室" align="center" prop="createDeptName" />
                 <el-table-column label="最后修改时间" align="center" prop="updateTime" width="180" />
-                <el-table-column label="最后修改人姓名" align="center" prop="updateBy" />
+                <el-table-column label="最后修改人姓名" align="center" prop="updateByUser" />
                 <el-table-column label="最后修改人科室" align="center" prop="updateDeptName" />
                 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                     <template #default="scope">

+ 199 - 0
src/views/parameter/basicPublicTemplate/nutritionEducationTemplate/addOrEditForm.vue

@@ -0,0 +1,199 @@
+<template>
+    <div class="p-2">
+        <el-button type="primary" plain size="large" @click="goBack">返回</el-button>
+        <el-card shadow="never">
+            <el-form ref="educationTemplateFormRef" :model="form" :rules="rules" label-width="100px">
+                <el-row :gutter="20">
+                    <el-col :span="10">
+                        <el-form-item label="模板名称" prop="templateName">
+                            <el-input v-model="form.templateName" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="10">
+                        <el-form-item label="适用科室" prop="deptIdList">
+                            <el-tree-select v-model="form.deptIdList" :data="treeData" :props="treeProps"  multiple placeholder="请选择" check-strictly node-key="id" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="10">
+                        <el-form-item label="疾病标签" prop="diseaseLableId">
+                            <el-select v-model="form.labelList" multiple placeholder="请选择" style="width: 100%;" :disabled="true" @click="labelDialogVisible = true" class="custom-label-select" value-key="labelId">
+                                <el-option v-for="item in form.labelList" :key="item.labelId" :label="item.labelName" :value="item">
+                                    <el-tag type="info" size="small">{{ item.labelName }}</el-tag>
+                                </el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="10">
+                        <el-form-item label="模板描述" prop="description">
+                            <el-input v-model="form.description" type="textarea" :rows="5"  placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="20">
+                        <el-form-item label="正文" prop="content">
+                            <Editor v-model="form.content" :min-height="200" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+            </el-form>
+            <div class="flex justify-center gap-2 mt-4">
+                <el-button :loading="buttonLoading" type="primary" @click="submitForm">保 存</el-button>
+            </div>
+        </el-card>
+        <DiseaseLabel v-model="labelDialogVisible" :initial-selected-labels="form.labelList || []" @confirm="onLabelConfirm" />
+    </div>
+</template>
+
+<script setup lang="ts">
+    import { getCurrentInstance, ref, reactive, onMounted } from 'vue';
+    import { useRouter, useRoute } from 'vue-router';
+    import { addEducationTemplate, updateEducationTemplate, getEducationTemplate } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate';
+    import { EducationTemplateForm } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate/types';
+    import { listDept } from '@/api/system/dept';
+    import DiseaseLabel from '@/views/warehouse/nutriProduct/labelDialog.vue';
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+    const router = useRouter();
+    const route = useRoute();
+    const educationTemplateFormRef = ref();
+    const buttonLoading = ref(false);
+    const loading = ref(false);
+    const treeData = ref([]);
+    const labelDialogVisible = ref(false); // 疾病标签
+
+    const treeProps = ref({
+        value: 'deptId',
+        label: 'deptName',
+        children: 'children'
+    });
+
+    const initFormData: EducationTemplateForm = {
+        id: undefined,
+        templateName: undefined,
+        deptId: undefined,
+        deptIdList: [],
+        labelList: [],
+        diseaseLabelId: undefined,
+        description: undefined,
+        content: undefined,
+        contentStr: undefined,
+        updateDept: undefined
+    };
+
+    const form = ref < EducationTemplateForm > ({ ...initFormData });
+
+    const rules = {
+        templateName: [
+            { required: true, message: "模板名称不能为空", trigger: "blur" }
+        ],
+        deptId: [
+            { required: true, message: "适用科室不能为空", trigger: "change" }
+        ],
+        deiseaseLableId: [
+            { required: true, message: "疾病标签不能为空", trigger: "change" }
+        ],
+        description: [
+            { required: true, message: "模板描述不能为空", trigger: "blur" }
+        ],
+        content: [
+            { required: true, message: "正文不能为空", trigger: "blur" }
+        ]
+    };
+
+    /** 获取部门列表 */
+    const getDeptList = async () => {
+        loading.value = true;
+        try {
+            const res = await listDept({
+                pageNum: 1,
+                pageSize: 100
+            });
+            if (!res.data) {
+                console.warn("部门数据为空");
+                treeData.value = [];
+                return;
+            }
+
+            const processedData = proxy ?.handleTree(res.data, 'deptId');
+            if (!processedData) {
+                console.warn("树形数据处理失败");
+                treeData.value = [];
+                return;
+            }
+
+            treeData.value = processedData;
+        } catch (error) {
+            console.error('获取部门列表失败:', error);
+            treeData.value = [];
+        } finally {
+            loading.value = false;
+        }
+    };
+
+    // 标签确认回调
+    function onLabelConfirm(selectedLabels: Array < { labelId: string | number;labelName: string } > ) {        
+        form.value.labelList = selectedLabels;
+    }
+
+    // 返回按钮
+    const goBack = () => {
+        router.back();
+    };
+
+    /** 表单重置 */
+    const reset = () => {
+        form.value = { ...initFormData };
+        educationTemplateFormRef.value ?.resetFields();
+    };
+
+    /** 提交按钮 */
+    const submitForm = () => {
+        educationTemplateFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                try {
+                    if (form.value.id) {
+                        form.value.contentStr = window.btoa(encodeURIComponent(form.value.content))
+                        await updateEducationTemplate(form.value);
+                    } else {
+                        form.value.contentStr = window.btoa(encodeURIComponent(form.value.content))
+                        console.log('form.value', JSON.stringify(form.value));
+                        
+                        await addEducationTemplate(form.value);
+                    }
+                    proxy ?.$modal.msgSuccess("操作成功");
+                    router.back();
+                } catch (error) {
+                    console.error('提交失败', error);
+                } finally {
+                    buttonLoading.value = false;
+                }
+            }
+        });
+    };
+
+    /** 获取详情 */
+    const getDetail = async (id: string | number) => {
+        try {
+            const res = await getEducationTemplate(id);
+            Object.assign(form.value, res.data);
+        } catch (error) {
+            console.error('获取详情失败', error);
+            proxy ?.$modal.msgError("获取详情失败");
+        }
+    };
+
+    onMounted(async () => {
+        await getDeptList();
+        const id = route.query.id;
+        if (id) {
+            await getDetail(id as string);
+        }
+    });
+</script>

+ 307 - 0
src/views/parameter/basicPublicTemplate/nutritionEducationTemplate/index.vue

@@ -0,0 +1,307 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div v-show="showSearch" class="mb-[10px]">
+                <el-card shadow="hover">
+                    <el-form ref="queryFormRef" :model="queryParams" :inline="true" 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-tree-select v-model="queryParams.createDept" :data="treeData" :props="treeProps" placeholder="请选择" check-strictly node-key="id" @keyup.enter="handleQuery" />
+                        </el-form-item>
+                        <el-form-item label="适用科室">
+                            <el-tree-select v-model="queryParams.deptId" :data="treeData" :props="treeProps" placeholder="请选择" check-strictly node-key="id" @keyup.enter="handleQuery" />
+                        </el-form-item>
+                        <el-form-item prop="searchValue">
+                            <el-input v-model="queryParams.searchValue" placeholder="模板名称/模板描述/创建人/最后编辑人" clearable style="width:300px" @keyup.enter="handleQuery" />
+                        </el-form-item>
+                        <el-form-item>
+                            <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
+                            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                        </el-form-item>
+                    </el-form>
+                </el-card>
+            </div>
+        </transition>
+
+        <el-card shadow="never">
+            <template #header>
+                <el-row :gutter="10" class="mb8">
+                    <el-col :span="1.5">
+                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['basicPublicTemplate:educationTemplate:add']">新增模板</el-button>
+                    </el-col>
+                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+                </el-row>
+            </template>
+            <el-table v-loading="loading" border :data="educationTemplateList" @selection-change="handleSelectionChange">
+                <el-table-column type="selection" width="55" align="center" />
+                <el-table-column label="模板名称" align="center" prop="templateName" />
+                <el-table-column label="模板描述" align="center" prop="description">
+                    <template #default="scope">
+                        <div class="description-cell" @mouseenter="showTooltip($event, scope.row.description)" @mouseleave="hideTooltip">
+                            {{ scope.row.description }}
+                        </div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="适用科室" align="center" prop="deptName" />
+                <el-table-column label="创建时间" align="center" prop="createTime" />
+                <el-table-column label="创建人姓名" align="center" prop="createByUser" />
+                <el-table-column label="创建人科室" align="center" prop="createDeptName" />
+                <el-table-column label="最后编辑时间" align="center" prop="updateTime" />
+                <el-table-column label="最后编辑人姓名" align="center" prop="updateByUser" />
+                <el-table-column label="最后编辑人科室" align="center" prop="updateDeptName" />
+                <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="['basicPublicTemplate:educationTemplate:edit']">编辑</el-button>
+                        </el-tooltip>
+                        <el-tooltip content="详情" placement="top">
+                            <el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
+                        </el-tooltip>
+                    </template>
+                </el-table-column>
+            </el-table>
+
+            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+    </div>
+    <Teleport to="body">
+        <Transition name="fade">
+            <div v-if="tooltipVisible" class="custom-tooltip" :style="tooltipStyle">
+                {{ tooltipContent }}
+            </div>
+        </Transition>
+    </Teleport>
+</template>
+
+<script setup name="EducationTemplate" lang="ts">
+    import { listEducationTemplate, getEducationTemplate, delEducationTemplate } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate';
+    import { EducationTemplateVO, EducationTemplateQuery } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate/types';
+    import { listDept } from '@/api/system/dept';
+    import { useRouter } from 'vue-router';
+    import type { DeptQuery } from '@/api/system/dept/types';
+
+    const router = useRouter();
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+    const educationTemplateList = ref < EducationTemplateVO[] > ([]);
+    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 treeData = ref([]);
+    const treeProps = ref({
+        value: 'deptId',
+        label: 'deptName',
+        children: 'children'
+    });
+
+    const queryFormRef = ref < ElFormInstance > ();
+
+    const data = reactive({
+        queryParams: {
+            pageNum: 1,
+            pageSize: 10,
+            searchValue: undefined,
+            deptId: undefined,
+            dateRange: undefined,
+            createDept: undefined,
+            params: {}
+        } as EducationTemplateQuery
+    });
+
+    const initQueryParams = () => {
+        queryParams.value = {
+            pageNum: 1,
+            pageSize: 10,
+            searchValue: undefined,
+            deptId: undefined,
+            dateRange: undefined,
+            createDept: undefined,
+            params: {}
+        };
+    };
+
+    const { queryParams } = toRefs(data);
+
+    // 添加tooltip相关的状态和方法
+    const tooltipVisible = ref(false);
+    const tooltipContent = ref('');
+    const tooltipStyle = ref({
+        left: '0px',
+        top: '0px'
+    });
+
+    const showTooltip = (event: MouseEvent, content: string) => {
+        const target = event.target as HTMLElement;
+        const rect = target.getBoundingClientRect();
+
+        tooltipContent.value = content;
+        tooltipStyle.value = {
+            left: `${rect.left + window.scrollX}px`,
+            top: `${rect.bottom + window.scrollY + 5}px`
+        };
+        tooltipVisible.value = true;
+    };
+
+    const hideTooltip = () => {
+        tooltipVisible.value = false;
+    };
+
+    /** 查询营养宣教模板列表 */
+    const getList = async () => {
+        loading.value = true;
+        const res = await listEducationTemplate(queryParams.value);
+        educationTemplateList.value = res.rows;
+
+        // 获取部门数据
+        const deptMap = new Map();
+        treeData.value.forEach(dept => {
+            deptMap.set(dept.deptId, dept.deptName);
+            if (dept.children) {
+                dept.children.forEach(child => {
+                    deptMap.set(child.deptId, child.deptName);
+                });
+            }
+        });
+        total.value = res.total;
+        loading.value = false;
+    }
+
+    const getDeptList = async () => {
+        loading.value = true;
+        try {
+            const res = await listDept({
+                    pageNum: 1,
+                    pageSize: 100
+                }as DeptQuery);
+            if (!res.data) {
+                console.warn("部门数据为空");
+                treeData.value = [];
+                return;
+            }
+
+            const processedData = proxy ?.handleTree(res.data, 'deptId');
+            if (!processedData) {
+                console.warn("树形数据处理失败");
+                treeData.value = [];
+                return;
+            }
+
+            treeData.value = processedData;
+        } catch (error) {
+            console.error('获取部门列表失败:', error);
+            treeData.value = [];
+        } finally {
+            loading.value = false;
+        }
+    };
+
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        queryParams.value.pageNum = 1;
+        getList();
+    }
+
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        queryFormRef.value ?.resetFields();
+        initQueryParams();
+        handleQuery();
+    }
+
+    /** 多选框选中数据 */
+    const handleSelectionChange = (selection: EducationTemplateVO[]) => {
+        ids.value = selection.map(item => item.id);
+        single.value = selection.length != 1;
+        multiple.value = !selection.length;
+    }
+
+    /** 新增按钮操作 */
+    const handleAdd = () => {
+        router.push('/argManage/nutritionEducationTemplateAdd');
+    }
+
+        /** 查看详情按钮操作 */
+    const handleDetail = (row: EducationTemplateVO) => {
+        router.push({
+            path: '/argManage/nutritionEducationTemplateDetail',
+            query: { id: row.id }
+        });
+    };
+
+    /** 修改按钮操作 */
+    const handleUpdate = (row ? : EducationTemplateVO) => {
+        const id = row ?.id || ids.value[0];
+        router.push({
+            path: '/argManage/nutritionEducationTemplateAdd',
+            query: { id }
+        });
+    }
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row ? : EducationTemplateVO) => {
+        const _ids = row ?.id || ids.value;
+        await proxy ?.$modal.confirm('是否确认删除营养宣教模板编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+        await delEducationTemplate(_ids);
+        proxy ?.$modal.msgSuccess("删除成功");
+        await getList();
+    }
+
+    /** 导出按钮操作 */
+    const handleExport = () => {
+        proxy ?.download('system/educationTemplate/export', {
+            ...queryParams.value
+        }, `educationTemplate_${new Date().getTime()}.xlsx`)
+    }
+
+    onMounted(() => {
+        getList();
+        getDeptList();
+    });
+</script>
+
+<style scoped>
+    .description-cell {
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        -webkit-line-clamp: 2;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        word-break: break-all;
+        line-height: 1.5;
+        max-height: 3em;
+        text-align: left;
+        padding: 0 8px;
+        cursor: pointer;
+    }
+
+    .custom-tooltip {
+        position: fixed;
+        z-index: 9999;
+        background: white;
+        border: 1px solid #e4e7ed;
+        border-radius: 4px;
+        padding: 12px;
+        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+        max-width: 400px;
+        line-height: 1.5;
+        font-size: 14px;
+        word-break: break-all;
+        text-align: left;
+    }
+
+    .fade-enter-active,
+    .fade-leave-active {
+        transition: opacity 0.2s ease;
+    }
+
+    .fade-enter-from,
+    .fade-leave-to {
+        opacity: 0;
+    }
+</style>

+ 178 - 0
src/views/parameter/basicPublicTemplate/nutritionEducationTemplate/templateDetail.vue

@@ -0,0 +1,178 @@
+<template>
+    <div class="p-2">
+        <el-button type="primary" plain size="large" @click="goBack">返回</el-button>
+        <el-card shadow="never" class="mt-4">
+            <el-form label-width="100px" class="mb-4">
+                <el-row :gutter="20">
+                    <el-col :span="16">
+                        <el-form-item label="模板名称:">
+                            <div class="form-text">{{ templateDetail.templateName }}</div>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="16">
+                        <el-form-item label="适用科室:">
+                            <div class="form-text">{{ templateDetail.deptName }}</div>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="16">
+                        <el-form-item label="疾病标签:">
+                            <div class="form-text">{{ templateDetail.diseaseLabelId }}</div>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="16">
+                        <el-form-item label="模板描述:">
+                            <div class="form-text">{{ templateDetail.description }}</div>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+            </el-form>
+
+            <div class="content-section">
+                <div class="section-title">正文:</div>
+                <div class="template-content" v-html="templateDetail.content"></div>
+            </div>
+            <!-- 
+            <div class="content-section">
+                <div class="section-title">变量说明</div>
+                <el-table :data="variableList" border stripe>
+                    <el-table-column prop="name" label="变量名" min-width="200"/>
+                    <el-table-column prop="description" label="说明" min-width="150"/>
+                    <el-table-column prop="example" label="示例值" min-width="150"/>
+                </el-table>
+            </div> -->
+        </el-card>
+    </div>
+</template>
+
+<script setup lang="ts">
+    import { ref, onMounted } from 'vue';
+    import { useRouter, useRoute } from 'vue-router';
+    import { getEducationTemplate } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate';
+    import { EducationTemplateVO } from '@/api/parameter/basicPublicTemplate/nutritionEducationTemplate/types';
+
+
+    const router = useRouter();
+    const route = useRoute();
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+    const templateDetail = ref < EducationTemplateVO > ({
+        id: undefined,
+        templateName: '',
+        deptId: undefined,
+        deptName: '',
+        diseaseLabelId: undefined,
+        description: '',
+        content: '',
+        updateDept: undefined
+    });
+
+
+    // 变量说明列表
+    const variableList = ref([
+        { name: '${purpose}', description: '会诊目的', example: '营养评估' },
+        { name: '${height}', description: '身高', example: '170' },
+        { name: '${weight}', description: '体重', example: '65' },
+        { name: '${bmi}', description: 'BMI指数', example: '22.5' },
+        { name: '${lossWeight}', description: '近6个月体重变化', example: '-2' },
+        { name: '${lossWeightRate}', description: '体重下降率', example: '3' },
+        { name: '${totalFood24retrospectCalories}', description: '24h膳食回顾能量', example: '2000' },
+        { name: '${totalFood24retrospectProtein}', description: '24h膳食回顾蛋白质', example: '60' },
+        { name: '${alb}', description: '白蛋白', example: '35' },
+        { name: '${beforeAlb}', description: '前白蛋白', example: '180' },
+        { name: '${hgb}', description: '血红蛋白', example: '120' },
+        { name: '${nrs2002Score}', description: 'NRS2002评分', example: '3' },
+        { name: '${nrs2002Conclusion}', description: 'NRS2002结论', example: '存在营养风险' },
+        { name: '${glimResult}', description: 'GLIM营养不良评估', example: '重度营养不良' },
+        { name: '${way}', description: '营养治疗途径', example: '经口肠内营养+补充性肠外营养' },
+        { name: '${totalCalories}', description: '总能量', example: '2000' },
+        { name: '${totalProtein}', description: '总蛋白质', example: '80' }
+    ]);
+
+
+
+    /** 获取模板详情 */
+    const getDetail = async (id: string | number) => {
+        try {
+            const res = await getEducationTemplate(id);
+            templateDetail.value = res.data;
+        } catch (error) {
+            console.error('获取详情失败', error);
+            proxy ?.$modal.msgError("获取详情失败");
+        }
+    };
+
+    // 返回按钮
+    const goBack = () => {
+        router.back();
+    };
+
+    onMounted(async () => {
+        const id = route.query.id;
+        if (id) {
+            await Promise.all([
+                getDetail(id as string)
+            ]);
+        } else {
+            proxy ?.$modal.msgError("未找到模板ID");
+            router.back();
+        }
+    });
+</script>
+
+<style scoped>
+    .form-text {
+        line-height: 32px;
+        color: #606266;
+    }
+
+    .content-section {
+        margin-top: 20px;
+    }
+
+    .section-title {
+        font-size: 16px;
+        font-weight: bold;
+        margin-bottom: 16px;
+        color: #303133;
+        position: relative;
+        padding-left: 10px;
+    }
+
+    .section-title::before {
+        content: '';
+        position: absolute;
+        left: 0;
+        top: 50%;
+        transform: translateY(-50%);
+        width: 4px;
+        height: 16px;
+        background-color: #409EFF;
+        border-radius: 2px;
+    }
+
+    .template-content {
+        padding: 16px;
+        border: 1px solid #e4e7ed;
+        border-radius: 4px;
+        min-height: 500px;
+        width: 60%;
+        line-height: 50px;
+        background-color: #fff;
+        margin-bottom: 20px;
+    }
+
+    .template-content :deep(p) {
+        margin: 8px 0;
+        line-height: 1.6;
+    }
+
+    :deep(.el-form-item__label) {
+        font-weight: bold;
+    }
+</style>

+ 9 - 29
src/views/patients/checkLabel/index.vue

@@ -2,39 +2,18 @@
     <div>
 
         <!-- 筛选区 -->
-         <div>
+        <div>
             <el-date-picker v-model="dateRange" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
-             <span style="margin-left: 30px">检验类型</span><el-select v-model="visitType" placeholder="请选择" style="width: 140px; margin-left: 10px">
-                <el-option label="门诊" value="0" />
-                <el-option label="住院" value="1" />
+            <span style="margin-left: 30px">检验类型</span>
+            <el-select v-model="visitType" placeholder="请选择" style="width: 140px; margin-left: 10px">
+                <el-option label="检查" value="0" />
+                <el-option label="化验" value="1" />
             </el-select>
-           <el-input v-model="searchDoctor" placeholder="医生姓名/门诊号/住院号" style="width: 240px; " clearable />
-            <el-button type="primary" class="filter-btn" style="margin-right: 8px;" @click="handleSearch">查询</el-button>
+            <el-input v-model="searchDoctor" placeholder="医生姓名/门诊号/住院号" style="width: 240px;margin-left: 8px; " clearable />
+            <el-button type="primary" class="filter-btn" style="margin-left: 8px;" @click="handleSearch">查询</el-button>
             <el-button class="filter-btn" @click="handleReset">重置</el-button>
         </div>
-        <!-- <div>
-            <el-row >
-                <el-col :span="10">
-                </el-col>
-                <el-col :span="4" >
-                    <el-select v-model="checkType" placeholder="检查类型"  style="width: 260px">
-                        <el-option label="检查" value="1" />
-                        <el-option label="化验" value="2" />
-                    </el-select>
-                </el-col>
-                <el-col :span="4">
-                    <el-input v-model="searchDoctor" placeholder="申请医生/检查项目" />
-                </el-col>
-                <el-col :span="6">
-                    <el-button type="primary" class="search-btn">查询</el-button>
-                    <el-button class="reset-btn">重置</el-button>
-                </el-col>
-            </el-row>
-
-
-
-
-        </div> -->
+       
         <!-- 表格区 -->
         <el-table :data="tableData" border class="check-table" style="width: 100%">
             <el-table-column prop="item" label="检查项目" />
@@ -61,6 +40,7 @@
 <script setup lang="ts">
     import { ref } from 'vue';
     const dateRange = ref([]);
+    const visitType = ref('1');
     const checkType = ref('2');
     const searchDoctor = ref('');
     const showSearch = ref(true);

+ 1 - 1
src/views/patients/medicalRecord/detailDialog.vue

@@ -17,7 +17,7 @@
                 </el-col>
                 <el-col :span="12">
                     <div class="detail-row"><span class="label">门诊号:</span><span class="value">{{ detailData.outpatientNo || '--' }}</span></div>
-                    <div class="detail-row"><span class="label required">性别:</span><span class="value">{{ detailData.sex === '1' ? '男' : detailData.sex === '2' ? '女' : '--' }}</span></div>
+                    <div class="detail-row"><span class="label required">性别:</span><span class="value">{{ detailData.sex === '0' ? '男' : detailData.sex === '1' ? '女' : '--' }}</span></div>
                     <div class="detail-row"><span class="label">出生日期:</span><span class="value">{{ detailData.birthday || '--' }}</span></div>
                     <div class="detail-row"><span class="label">联系电话:</span><span class="value">{{ detailData.phoneNum || '--' }}</span></div>
                     <div class="detail-row"><span class="label">体重:</span><span class="value">{{ detailData.weight ? detailData.weight + 'kg' : '--' }}</span></div>

+ 1 - 1
src/views/patients/medicalRecord/editDialog.vue

@@ -34,7 +34,7 @@
                             <span>{{ form.outpatientNo || '--' }}</span>
                         </el-form-item>
                         <el-form-item label="性别:" prop="sex" required>
-                            <span>{{ form.sex === '1' ? '男' : form.sex === '2' ? '女' : '--' }}</span>
+                            <span>{{ form.sex === '0' ? '男' : form.sex === '1' ? '女' : '--' }}</span>
                         </el-form-item>
                         <el-form-item label="出生日期" prop="birthday">
                             <span>{{ form.birthday || '--' }}</span>

+ 59 - 36
src/views/patients/medicalRecord/index.vue

@@ -37,7 +37,7 @@
                     <span>营养监测</span>
                 </el-menu-item>
                 <el-menu-item index="nutritionEducation">
-                    <span>营养教</span>
+                    <span>营养教</span>
                 </el-menu-item>
             </el-menu>
             <div class="search-bar">
@@ -52,7 +52,7 @@
                 </el-tabs>
             </div>
             <div class="patient-table">
-                <el-table :data="patientList" border size="small" height="50%" :show-header="true" class="table-patients" :row-class-name="tableRowClassName" @row-click="handleRowClick">
+                <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" />
@@ -66,34 +66,30 @@
         <div class="main-content">
             <el-row>
                 <div class="patient-left-info">
-                    <el-row>
-                        <span style="font-size: 22px;">{{ patientInfo.name }}</span>
-                        <span style="margin-left: 30px;">{{ patientInfo.age }}</span>
+                    <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>
+                    <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>门诊号:</span>
-                        <span>科室:{{ patientInfo.deptName }}</span>
-                        <span>营养诊断:</span>
+                        <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"
-            />
+            <component :is="currentComponent" v-if="currentComponent" :patient-info="patientInfo" />
         </div>
 
         <!-- 患者详情弹窗 -->
@@ -110,16 +106,18 @@
     import { listTreatmentUser, getTreatmentUser } from '@/api/workbench/treatmentUser';
     import DetailDialog from './detailDialog.vue';
     import EditDialog from './editDialog.vue';
-    
+
     // 动态导入组件
-    const MedicalRecord = defineAsyncComponent(() => import('./medicalRecord.vue'));
+    const MedicalRecord = defineAsyncComponent(() => import('./levelMenu.vue'));
     const NutriDiagnosis = defineAsyncComponent(() => import('@/views/patients/nutriDiagnosis/index.vue'));
     const CheckLabel = defineAsyncComponent(() => import('@/views/patients/checkLabel/index.vue'));
+    const NutritionEducation = defineAsyncComponent(() => import('@/views/patients/nutritionEducation/index.vue'));
 
     const componentMap = {
         medicalRecord: MedicalRecord, // “营养病例”对应MedicalRecord.vue
         checkLabel: CheckLabel, // “检查标签”对应CheckLabel.vue
         nutritionDiagnosis: NutriDiagnosis,
+        nutritionEducation: NutritionEducation,
         // ... 其它映射
     };
     const currentComponent = ref(componentMap['medicalRecord']); // 默认显示
@@ -133,10 +131,12 @@
         id: '',
         name: '',
         age: '',
-         gender: '',
+        type: '',
+        gender: '',
         deptName: '',
-       
-    } as any);
+        outpatientNo: '',
+
+    });
 
     // 弹窗控制
     const showDetailDialog = ref(false);
@@ -167,6 +167,8 @@
     };
 
     const handleRowClick = (row, column, event) => {
+        activeMenu.value = 'medicalRecord';
+        currentComponent.value = componentMap['medicalRecord'];
         const idx = patientList.value.findIndex(item => item === row);
         patientInfo.value = row;
         if (idx !== -1) {
@@ -175,6 +177,7 @@
     };
 
     const handlePrev = () => {
+        activeMenu.value = 'medicalRecord';
         currentComponent.value = componentMap['medicalRecord']
         if (currentPatientIndex.value > 0) {
             patientInfo.value = patientList.value[currentPatientIndex.value - 1];
@@ -183,6 +186,7 @@
     };
 
     const handleNext = () => {
+        activeMenu.value = 'medicalRecord';
         currentComponent.value = componentMap['medicalRecord']
         patientInfo.value = patientList.value[currentPatientIndex.value + 1];
         if (currentPatientIndex.value < patientList.value.length - 1) {
@@ -221,7 +225,7 @@
             proxy ?.$modal.msgError('请先选择患者');
             return;
         }
-        
+
         try {
             // 获取患者详细信息
             const res = await getTreatmentUser(patientInfo.value.id);
@@ -268,10 +272,15 @@
                 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,
-                gender: item.sex === '1' ? '男' : item.sex === '2' ? '女' : '',
+                type: item.type, // 0: 门诊,1: 住院
+                deptName: item.deptName,
+                outpatientNo: item.outpatientNo,
+                gender: item.sex === '0' ? '男' : item.sex === '1' ? '女' : '',
                 age: item.age
             }));
             waitingCount.value = patientList.value.length;
@@ -332,8 +341,11 @@
         border-right: 1px solid #e6e6e6;
         display: flex;
         flex-direction: column;
-        padding-bottom: 12px;
+        padding-bottom: 60px;
+        /* 增加底部padding,为按钮留出空间 */
         position: relative;
+        overflow: hidden;
+        /* 防止内容溢出 */
     }
 
     .back-button {
@@ -386,25 +398,25 @@
     }
 
     .patient-table {
-        padding: 0 12px;
-        margin-top: 4px;
+        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;
+            color: #409eff;
             font-weight: bold;
             font-size: 13px;
             padding: 4px 0;
         }
-
         .el-table__row {
             cursor: pointer;
         }
-
         .el-table__row.current-row {
             background: #eaf4ff !important;
         }
@@ -420,6 +432,9 @@
         bottom: 12px;
         padding: 0 12px;
         background: #fff;
+        z-index: 1;
+        width: calc(100% - 24px);
+        margin: 0 auto;
     }
 
     .main-content {
@@ -431,7 +446,7 @@
     .patient-left-info {
         background-color: #fff;
         height: 100px;
-        padding: 20px;
+        padding: 10px;
         border-radius: 4px;
         margin-bottom: 20px;
         width: 11%;
@@ -449,20 +464,28 @@
 
     }
 
-
-
-
-
+    .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: 30%;
+        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;
     }

+ 216 - 0
src/views/patients/medicalRecord/levelMenu.vue

@@ -0,0 +1,216 @@
+<template>
+    <div class="patient-info">
+        <span>营养病例</span>
+    </div>
+    <div class="custom-tab-bar">
+        <el-menu :default-active="activeMenu" class="medical-menu" @select="handleSelect" mode="horizontal">
+            <el-menu-item index="medicalRecord">
+                <span>病史记录</span>
+            </el-menu-item>
+            <el-menu-item index="visitRecord">
+                <span>检查指标</span>
+            </el-menu-item>
+            <el-menu-item index="checkLabel">
+                <span>营养筛查</span>
+            </el-menu-item>
+            <el-menu-item index="nutritionEvaluation">
+                <span>营养评估</span>
+            </el-menu-item>
+            <el-menu-item index="nutritionDiagnosis">
+                <span>营养诊断</span>
+            </el-menu-item>
+            <el-menu-item index="nutritionPlan">
+                <span>营养干预</span>
+            </el-menu-item>
+            <el-menu-item index="nutritionMonitor"> 
+                <span>营养膳食</span>
+            </el-menu-item>
+            <el-menu-item index="checkRoom" v-show="props.patientInfo.type=='1'"> 
+                <span>查房记录</span>
+            </el-menu-item>
+        </el-menu>
+    </div>
+
+    <div>
+        <!-- <keep-alive>
+        </keep-alive> -->
+                    <component :is="currentComponent" v-if="currentComponent" :patient-info="props.patientInfo"/>
+
+    </div>
+
+
+</template>
+
+<script setup lang="ts">
+    import { ref } from 'vue';
+
+    const MedicalRecord = defineAsyncComponent(() => import('@/views/patients/medicalRecord/levelMenu/medicalRecord/index.vue'));
+    const VisitRecord = defineAsyncComponent(() => import('@/views/patients/medicalRecord/levelMenu/visitRecord/index.vue'));
+
+    const NutriDiagnosis = defineAsyncComponent(() => import('@/views/patients/medicalRecord/levelMenu/nutriDiagnosis/index.vue'));
+
+    const activeMenu = ref('medicalRecord');
+
+    const componentMap = {
+        medicalRecord: MedicalRecord,
+        visitRecord: VisitRecord,
+        nutritionDiagnosis: NutriDiagnosis,
+        // ... 其它映射
+    };
+
+    const currentComponent = ref(componentMap['medicalRecord']); // 默认显示
+
+   // 声明接收的 props
+    const props = defineProps({
+        patientInfo: {
+            type: Object,
+            required: true,
+            default: () => ({
+                id: '',
+                name: '',
+                age: '',
+                gender: ''
+            })
+        }
+    });
+
+    const handleSelect = (key: string) => {
+        activeMenu.value = key;
+        currentComponent.value = componentMap[key] || null;
+    };
+</script>
+
+<style lang="scss" scoped>
+    .custom-tab-bar {
+        display: flex;
+        background: #76b4f4;
+        height: 56px;
+        line-height: 55px;
+        align-items: stretch;
+        border-bottom: 1px solid #e0e0e0;
+        margin-bottom: 24px;
+        overflow-x: auto;
+        white-space: nowrap;
+        padding-bottom: 2px;
+
+        // 让el-menu横向铺满
+        :deep(.el-menu--horizontal) {
+            border-bottom: none;
+            background: transparent;
+        }
+
+        :deep(.el-menu--horizontal > .el-menu-item) {
+            height: 56px;
+            line-height: 56px;
+            font-size: 16px;
+            color: #fff;
+            background: transparent;
+        }
+
+        :deep(.el-menu-item.is-active) {
+            background: #3f6cb5;
+            color: #fff;
+        }
+    }
+
+    .medical-menu {
+        display: inline-flex;
+        min-width: max-content;
+        width: 90% ;
+    }
+
+    .patient-info {
+        background-color: #fff;
+        padding: 20px;
+        border-radius: 4px;
+        margin-bottom: 20px;
+        font-size: 24px;
+
+        :deep(.el-descriptions__label) {
+            width: 80px;
+            justify-content: flex-end;
+        }
+    }
+
+    .content-area {
+        background-color: #fff;
+        margin-top: -20px;
+        padding: 10px;
+        border-radius: 4px;
+        min-height: calc(100vh - 200px);
+    }
+
+    .custom-tab.first.active,
+    .custom-tab.active {
+        background: #4a7ebc;
+    }
+
+    .custom-tab:not(.active):hover {
+        background: #6bb0e6;
+    }
+
+    .custom-tab+.custom-tab {
+        border-left: 1px solid rgba(255, 255, 255, 0.1);
+    }
+
+    .medical-content {
+        background: #fff;
+        border-radius: 4px;
+        padding: 50px 60px 40px 60px;
+        min-height: 80vh;
+        font-size: 15px;
+        color: #222;
+    }
+
+    .row {
+        display: flex;
+        align-items: flex-start;
+        margin-bottom: 16px;
+        flex-wrap: wrap;
+    }
+
+    .label {
+        min-width: 110px;
+        color: #222;
+        font-weight: 500;
+        margin-right: 8px;
+        line-height: 28px;
+        text-align: right;
+    }
+
+    .edit-link {
+        color: #409eff;
+        margin-right: 24px;
+        cursor: pointer;
+        font-size: 14px;
+        line-height: 28px;
+    }
+
+    .content-text {
+        flex: 1;
+        color: #333;
+        line-height: 28px;
+        margin-right: 16px;
+        word-break: break-all;
+    }
+
+    .multi-line {
+        flex-direction: column;
+        align-items: flex-start;
+        margin-bottom: 20px;
+    }
+
+    .add-btn {
+        margin-left: 12px;
+        width: 32px;
+        height: 32px;
+        border-radius: 50%;
+        background: #f5f7fa;
+        border: 1px dashed #dcdfe6;
+        color: #999;
+        font-size: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+    }
+</style>

+ 33 - 68
src/views/patients/medicalRecord/medicalRecord.vue → src/views/patients/medicalRecord/levelMenu/medicalRecord/index.vue

@@ -2,11 +2,6 @@
     <div class="patient-info">
         <span>营养病例</span>
     </div>
-    <div class="custom-tab-bar">
-        <div v-for="(tab, idx) in tabs" :key="tab.value" :class="['custom-tab', { active: activeTab === tab.value, first: idx === 0 }]" @click="activeTab = tab.value">
-            {{ tab.label }}
-        </div>
-    </div>
     <div class="content-area">
         <div class="medical-content">
             <div class="row">
@@ -47,129 +42,99 @@
             </div>
             <div class="row">
                 <span class="label">知情同意书(0/5):</span>
-                <imageUpload  :limit="5" :isShowTip="false" />
+                <imageUpload :limit="5" :isShowTip="false" />
             </div>
         </div>
-
     </div>
-    
     <!-- 主诉编辑对话框 -->
-    <MainSultDialog 
-        v-model:visible="showMainSultDialog" 
-        :main-sult-data="mainSult" 
-        @save="handleMainSultSave" 
-        @close="handleMainSultClose" 
-    />
-    
+    <MainSultDialog v-model:visible="showMainSultDialog" :main-sult-data="mainSult" @save="handleMainSultSave" @close="handleMainSultClose" />
+
     <!-- 现病史编辑对话框 -->
-    <PresentIllnessDialog 
-        v-model:visible="showPresentIllnessDialog" 
-        :present-illness-data="presentIllness" 
-        @save="handlePresentIllnessSave" 
-        @close="handlePresentIllnessClose" 
-    />
-    
+    <PresentIllnessDialog v-model:visible="showPresentIllnessDialog" :present-illness-data="presentIllness" @save="handlePresentIllnessSave" @close="handlePresentIllnessClose" />
+
     <!-- 既往史编辑对话框 -->
-    <PastIllnessDialog 
-        v-model:visible="showPastIllnessDialog" 
-        :past-illness-data="pastIllness" 
-        @save="handlePastIllnessSave" 
-        @close="handlePastIllnessClose" 
-    />
-    
+    <PastIllnessDialog v-model:visible="showPastIllnessDialog" :past-illness-data="pastIllness" @save="handlePastIllnessSave" @close="handlePastIllnessClose" />
+
     <!-- 家族史编辑对话框 -->
-    <FamilyHistoryDialog 
-        v-model:visible="showFamilyHistoryDialog" 
-        :family-history-data="familyHistory" 
-        @save="handleFamilyHistorySave" 
-        @close="handleFamilyHistoryClose" 
-    />
+    <FamilyHistoryDialog v-model:visible="showFamilyHistoryDialog" :family-history-data="familyHistory" @save="handleFamilyHistorySave" @close="handleFamilyHistoryClose" />
 
 </template>
 
 <script setup lang="ts">
     import { ref } from 'vue';
-    import MainSultDialog from './edit/mainSultDialog.vue';
-    import FamilyHistoryDialog from './edit/familyHistoryDialog.vue';
-    import PastIllnessDialog from './edit/pastIllnessDialog.vue';
-    import PresentIllnessDialog from './edit/presentIllnessDialog.vue';
-    
-    const tabs = [
-        { label: '病史记录', value: 'history' },
-        { label: '检查指标', value: 'check' },
-        { label: '营养筛查', value: 'screen' },
-        { label: '营养评估', value: 'evaluate' },
-        { label: '营养诊断', value: 'diagnose' },
-        { label: '营养干预', value: 'intervene' },
-        { label: '营养膳食', value: 'diet' },
-    ];
-    const activeTab = ref('history');
-    
+    import MainSultDialog from '../../edit/mainSultDialog.vue';
+    import FamilyHistoryDialog from '../../edit/familyHistoryDialog.vue';
+    import PastIllnessDialog from '../../edit/pastIllnessDialog.vue';
+    import PresentIllnessDialog from '../../edit/presentIllnessDialog.vue';
+
+
+
     // 主诉相关
     const mainSult = ref('');
     const showMainSultDialog = ref(false);
-    
+
     const handleEditMainSult = () => {
         showMainSultDialog.value = true;
     };
-    
+
+
     const handleMainSultSave = (data: string) => {
         mainSult.value = data;
         // 这里可以调用API保存数据
         console.log('保存主诉:', data);
     };
-    
+
     const handleMainSultClose = () => {
         showMainSultDialog.value = false;
     };
-    
+
     // 现病史相关
     const presentIllness = ref('');
     const showPresentIllnessDialog = ref(false);
-    
+
     const handleEditPresentIllness = () => {
         showPresentIllnessDialog.value = true;
     };
-    
+
     const handlePresentIllnessSave = (data: string) => {
         presentIllness.value = data;
-       
+
     };
-    
+
     const handlePresentIllnessClose = () => {
         showPresentIllnessDialog.value = false;
     };
-    
+
     // 既往史相关
     const pastIllness = ref('');
     const showPastIllnessDialog = ref(false);
-    
+
     const handleEditPastIllness = () => {
         showPastIllnessDialog.value = true;
     };
-    
+
     const handlePastIllnessSave = (data: string) => {
         pastIllness.value = data;
         console.log('保存既往史:', data);
     };
-    
+
     const handlePastIllnessClose = () => {
         showPastIllnessDialog.value = false;
     };
-    
+
     // 家族史相关
     const familyHistory = ref('');
     const showFamilyHistoryDialog = ref(false);
-    
+
     const handleEditFamilyHistory = () => {
         showFamilyHistoryDialog.value = true;
     };
-    
+
     const handleFamilyHistorySave = (data: string) => {
         familyHistory.value = data;
         console.log('保存家族史:', data);
     };
-    
+
     const handleFamilyHistoryClose = () => {
         showFamilyHistoryDialog.value = false;
     };
@@ -265,7 +230,7 @@
         font-size: 14px;
         line-height: 28px;
     }
-    
+
     .content-text {
         flex: 1;
         color: #333;

+ 105 - 0
src/views/patients/medicalRecord/levelMenu/nutriDiagnosis/index.vue

@@ -0,0 +1,105 @@
+<template>
+    <div class="p-2">
+        <el-card shadow="never">
+            <el-table v-loading="loading" border :data="diagnosisList" @selection-change="handleSelectionChange">
+                <el-table-column label="营养诊断时间" align="center" prop="createTime" width="180" />
+                <el-table-column label="营养诊断依据" align="center" prop="diagnosisBasis" width="180">
+                    <template #default="scope">
+                        <span>{{ scope.row.diagnosisBasis ||'--' }}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="营养诊断" align="center" prop="diagnosisLabelStr" />
+                <el-table-column label="诊断医生" align="center" prop="createByUser" width="180" />
+            </el-table>
+            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+    </div>
+</template>
+
+<script setup name="LevelDiagnosis" lang="ts">
+    import { ref, watch, onMounted, onBeforeUnmount, getCurrentInstance, toRefs, reactive } from 'vue';
+    import { listDiagnosis, } from '@/api/patients/diagnosis';
+    import { DiagnosisVO, DiagnosisQuery, DiagnosisForm } from '@/api/patients/diagnosis/types';
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+    const diagnosisList = ref < DiagnosisVO[] > ([]);
+    const loading = ref(true);
+    const ids = ref < Array < string | number >> ([]);
+    const single = ref(true);
+    const multiple = ref(true);
+    const total = ref(0);
+    const isUnmounted = ref(false);
+    onBeforeUnmount(() => {
+        isUnmounted.value = true;
+    });
+
+    // 声明接收的 props
+    const props = defineProps({
+        patientInfo: {
+            type: Object,
+            required: true,
+            default: () => ({
+                id: '',
+                name: '',
+                age: '',
+                gender: ''
+            })
+        }
+    });
+
+    const initFormData: DiagnosisForm = {
+        id: undefined,
+        treatmentUserId: props.patientInfo ?.id,
+        consultantTemplateId: undefined,
+        diagnosisLableId: undefined,
+        diagnosisBasisId: undefined,
+        medicalOrder: undefined,
+        consultantResult: undefined,
+        consultantResultStr: undefined,
+    }
+
+    const data = reactive < PageData < DiagnosisForm,
+        DiagnosisQuery >> ({
+            form: { ...initFormData },
+            queryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                treatmentUserId: props.patientInfo ?.id,
+                params: {}
+            },
+            rules: {
+
+            }
+        });
+
+    const { queryParams, form, rules } = toRefs(data);
+
+    /** 查询营养诊断列表 */
+    const getList = async () => {
+        loading.value = true;
+        const res = await listDiagnosis(queryParams.value);
+        if (isUnmounted.value) return;
+        diagnosisList.value = res.rows;
+
+        total.value = res.total;
+        loading.value = false;
+    }
+    watch(
+        () => props.patientInfo.id,
+        (newId) => {
+            // form.value.treatmentUserId = newId;
+            queryParams.value.treatmentUserId = newId;
+            getList();
+        }, { immediate: true }
+    );
+
+    /** 多选框选中数据 */
+    const handleSelectionChange = (selection: DiagnosisVO[]) => {
+        ids.value = selection.map(item => item.id);
+        single.value = selection.length != 1;
+        multiple.value = !selection.length;
+    }
+    onMounted(() => {
+        getList();
+    });
+</script>

+ 200 - 0
src/views/patients/medicalRecord/levelMenu/visitRecord/index.vue

@@ -0,0 +1,200 @@
+<template>
+    <div>
+
+        <!-- 筛选区 -->
+        <div>
+            <span style="margin-left: 30px">检验类型</span>
+            <el-select v-model="visitType" placeholder="请选择" style="width: 140px; margin-left: 10px">
+                <el-option label="检查" value="0" />
+                <el-option label="化验" value="1" />
+            </el-select>
+            <el-input v-model="searchDoctor" placeholder="审核医生/检查项目" style="width: 240px;margin-left: 8px; " clearable />
+            <el-button type="primary" class="filter-btn" style="margin-left: 8px;" @click="handleSearch">查询</el-button>
+            <el-button class="filter-btn" @click="handleReset">重置</el-button>
+        </div>
+       
+        <!-- 表格区 -->
+        <el-table :data="tableData" border class="check-table" style="width: 100%">
+            <el-table-column prop="item" label="检查项目" />
+            <el-table-column prop="deptName" label="申请科室" />
+            <el-table-column prop="applyDoctor" label="申请医生" />
+            <el-table-column prop="applyTime" label="申请时间" />
+            <el-table-column prop="reviewDoctor" label="审核医生" />
+            <el-table-column prop="diagnosis" label="临床诊断" />
+            <template #empty>
+                <div class="empty-data">暂无数据</div>
+            </template>
+        </el-table>
+        <!-- 分页区 -->
+        <div class="pagination-bar">
+            <span>共0条</span>
+            <span class="pagination-gap">前往</span>
+            <el-input v-model="page" size="small" class="page-input" style="width: 40px;" />
+            <span class="pagination-gap">页</span>
+            <el-pagination background layout="prev, pager, next, sizes" :total="0" :page-size="10" :current-page="page" :page-sizes="[10, 20, 50, 100]" class="pagination" />
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+    import { ref } from 'vue';
+    const visitType = ref('1');
+    const checkType = ref('2');
+    const searchDoctor = ref('');
+    const tableData = ref([]); // 空数据
+    const page = ref(1);
+</script>
+
+<style scoped>
+    .check-indicators-container {
+        background: #f6f9fb;
+        min-height: 100vh;
+        padding: 0;
+    }
+
+    .custom-tab-bar {
+        display: flex;
+        background: #7ec0fa;
+        height: 40px;
+        align-items: stretch;
+        border-bottom: 1px solid #e0e0e0;
+        margin-bottom: 24px;
+    }
+
+    .custom-tab {
+        color: #fff;
+        font-size: 16px;
+        padding: 0 32px;
+        display: flex;
+        align-items: center;
+        cursor: pointer;
+        height: 100%;
+        transition: background 0.2s;
+        background: #7ec0fa;
+        font-weight: 500;
+    }
+
+    .custom-tab.first.active,
+    .custom-tab.active {
+        background: #4a7ebc;
+    }
+
+    .custom-tab:not(.active):hover {
+        background: #6bb0e6;
+    }
+
+    .custom-tab+.custom-tab {
+        border-left: 1px solid rgba(255, 255, 255, 0.1);
+    }
+
+    .filter-bar {
+        display: flex;
+        align-items: center;
+        padding: 24px 0 0 24px;
+        gap: 12px;
+        background: #fff;
+    }
+
+    .date-picker {
+        width: 200px
+    }
+
+    .date-picker.custom-date-picker {
+        width: 200px !important;
+        min-width: 200px !important;
+        max-width: 200px !important;
+    }
+
+    .date-picker.custom-date-picker :deep(.el-input__wrapper) {
+        height: 50px !important;
+        min-height: 50px !important;
+        border-radius: 4px !important;
+        border: 1px solid #dcdfe6 !important;
+        font-size: 14px !important;
+        background: #fff !important;
+        box-shadow: none !important;
+        padding: 0 8px !important;
+    }
+
+    .date-picker.custom-date-picker :deep(.el-input__inner) {
+        height: 32px !important;
+        line-height: 32px !important;
+        font-size: 14px !important;
+        padding: 0 4px !important;
+    }
+
+    .date-picker.custom-date-picker :deep(.el-range-separator) {
+        padding: 0 2px !important;
+        color: #c0c4cc !important;
+        font-size: 14px !important;
+    }
+
+    .date-picker.custom-date-picker :deep(.el-range-input) {
+        font-size: 14px !important;
+        padding: 0 2px !important;
+    }
+
+    .date-picker.custom-date-picker :deep(.el-icon) {
+        font-size: 16px !important;
+        color: #c0c4cc !important;
+    }
+
+    .check-type {
+        width: 160px;
+    }
+
+    .search-doctor {
+        width: 260px;
+    }
+
+    .search-btn {
+        margin-left: 8px;
+    }
+
+    .reset-btn {
+        margin-left: 0;
+    }
+
+    .check-table {
+        margin: 16px 0 0 0;
+        background: #fff;
+    }
+
+    .check-table ::v-deep .el-table__header th {
+        background: #e6f0fa;
+        color: #333;
+        font-weight: 500;
+        font-size: 15px;
+    }
+
+    .empty-data {
+        text-align: center;
+        color: #999;
+        padding: 32px 0;
+        background: #fff;
+        font-size: 16px;
+    }
+
+    .pagination-bar {
+        display: flex;
+        align-items: center;
+        background: #fff;
+        padding: 8px 24px 24px 0;
+        justify-content: flex-end;
+        gap: 8px;
+        font-size: 14px;
+        margin-top: 0;
+    }
+
+    .pagination-gap {
+        margin: 0 4px;
+    }
+
+    .page-input {
+        text-align: center;
+    }
+
+    .pagination {
+        margin-left: 8px;
+    }
+</style>

+ 2 - 2
src/views/patients/nutriDiagnosis/consultantTemplateDialog.vue

@@ -35,8 +35,8 @@
     };
 
     const handleConfirm = () => {
-        // 只传递有 template 字段的节点
-        emit('select', selectedTemplate.value?.template || '');
+        // 只传递有 template 字段的节点 
+        emit('select', selectedTemplate.value || '');
         emit('update:visible', false);
     };
 

+ 60 - 0
src/views/patients/nutriDiagnosis/detailDialog.vue

@@ -0,0 +1,60 @@
+<template>
+  <el-dialog v-model="visible" title="营养诊断详情" width="880px" :close-on-click-modal="false" :destroy-on-close="true" top="20px">
+    <el-form label-width="120px" class="detail-form">
+      <el-form-item label="营养诊断:">
+        <el-input :model-value="detail.diagnosisLabelStr" readonly />
+      </el-form-item>
+      <el-form-item label="营养诊断依据:">
+        <el-input :model-value="detail.diagnosisBasis" readonly />
+      </el-form-item>
+      <el-form-item label="会诊结果:">
+        <el-input :model-value="detail.consultantResult" readonly />
+      </el-form-item>
+      <el-form-item label="营养医嘱:">
+        <el-input :model-value="detail.medicalOrder" readonly />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="visible = false">关闭</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import { ref, defineProps, watch, defineExpose } from 'vue';
+const emit = defineEmits(['update:modelValue']);
+const props = defineProps({
+  modelValue: Boolean,
+  detail: {
+    type: Object,
+    default: () => ({})
+  }
+});
+const visible = ref(props.modelValue);
+watch(
+  () => props.modelValue,
+  (v) => {
+    visible.value = v;
+  }
+);
+watch(visible, (v) => {
+  if (!v) emit('update:modelValue', false);
+});
+defineExpose({ visible });
+</script>
+<script lang="ts">
+export default {};
+</script>
+
+<style scoped>
+.detail-form {
+  padding: 10px 20px 0 20px;
+}
+.el-form-item {
+  margin-bottom: 24px;
+}
+.el-input[readonly] .el-input__inner {
+  background: #f5f7fa;
+  color: #333;
+}
+</style> 

+ 96 - 45
src/views/patients/nutriDiagnosis/index.vue

@@ -9,7 +9,7 @@
                                 <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="form.visitType" class="spec-unit-select">
+                                <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>
@@ -39,20 +39,27 @@
                 </template>
                 <el-table v-loading="loading" border :data="diagnosisList" @selection-change="handleSelectionChange">
                     <el-table-column type="selection" width="55" align="center" />
-                    <el-table-column label="" align="center" prop="id" v-if="true" />
                     <el-table-column label="时间" align="center" prop="createTime" />
-                    <el-table-column label="诊断依据" align="center" prop="diagnosisBasis" />
-                    <el-table-column label="看诊类型" align="center" prop="diagnosisType" />
-                    <el-table-column label="门诊/住院号" align="center" prop="outpatientNumber" />
-                    <el-table-column label="营养诊断" align="center" prop="nutritionalDiagnosis" />
-                    <el-table-column label="诊断医生" align="center" prop="diagnosisDoctor" />
+                    <el-table-column label="诊断依据" align="center" prop="diagnosisBasis">
+                        <template #default="scope">
+                            <span>{{getDictLabel(treatment_user_type ,scope.row.diagnosisBasis )|| '--' }}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="看诊类型" align="center" prop="type">
+                        <template #default="scope">
+                            <span>{{getDictLabel(treatment_user_type ,scope.row.type )|| '--' }}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="门诊/住院号" align="center" prop="outpatientNo" />
+                    <el-table-column label="营养诊断" align="center" prop="diagnosisLabelStr" width="350"/>
+                    <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)"></el-button>
+                            <el-tooltip content="详情" placement="top">
+                                <el-button link type="primary" icon="Edit" @click="handleDetail(scope.row)">详情</el-button>
                             </el-tooltip>
                             <el-tooltip content="删除" placement="top">
-                                <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
+                                <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
                             </el-tooltip>
                         </template>
                     </el-table-column>
@@ -65,8 +72,8 @@
         <div v-show="type === 'addForm'">
             <el-form ref="diagnosisFormRef" :model="form" :rules="rules" label-width="120px">
                 <el-form-item label="营养诊断:" prop="diagnosisLableId">
-                    <el-select v-model="labelList" multiple placeholder="请选择" style="width: 100%;" :disabled="true" @click="labelDialogVisible = true" class="custom-label-select" value-key="labelId">
-                        <el-option v-for="item in labelList" :key="item.labelId" :label="item.labelName" :value="item">
+                    <el-select v-model="form.labelList" multiple placeholder="请选择" style="width: 100%;" :disabled="true" @click="labelDialogVisible = true" class="custom-label-select">
+                        <el-option v-for="item in labelOptions" :key="item.labelId" :label="item.labelName" :value="item.labelId">
                             <el-tag type="info" size="small">{{ item.labelName }}</el-tag>
                         </el-option>
                     </el-select>
@@ -82,20 +89,22 @@
                     </div>
                 </el-form-item>
                 <el-form-item>
-                    <Editor v-model="form.consultationContent" placeholder="请输入内容..." style="min-height: 200px; width: 100%;" />
+                    <Editor v-model="form.consultantResult" placeholder="请输入内容..." style="min-height: 200px; width: 100%;" />
                 </el-form-item>
                 <el-form-item label="营养医嘱:" prop="medicalOrder">
                     <el-input v-model="form.medicalOrder" placeholder="请输入" clearable />
                 </el-form-item>
 
             </el-form>
-            <LabelDialog v-model="labelDialogVisible" :initial-selected-labels="labelList || []" @confirm="onLabelConfirm" />
+            <LabelDialog v-model="labelDialogVisible" :initial-selected-labels="labelOptions || []" @confirm="onLabelConfirm" />
             <ConsultantTemplateDialog v-model:visible="showTemplateDialog" @select="onTemplateSelect" />
             <div class="dialog-footer" style="text-align: center; margin-top: 100px">
                 <el-button @click="handleCancel">取 消</el-button>
                 <el-button :loading="buttonLoading" type="primary" @click="submitForm">提 交</el-button>
             </div>
         </div>
+        <!-- 详情弹窗始终挂载在最外层div内 -->
+        <detail-dialog v-model="showDetailDialog" :detail="currentDetail" />
     </div>
 </template>
 
@@ -104,6 +113,10 @@
     import { DiagnosisVO, DiagnosisQuery, DiagnosisForm } from '@/api/patients/diagnosis/types';
     import { getTreatmentUser as fetchTreatmentUser } from '@/api/workbench/treatmentUser';
     import LabelDialog from '@/views/warehouse/nutriProduct/labelDialog.vue';
+    import { getDiseaseLabel } from '@/api/system/diseaseLabel'; // 新增: 导入获取标签详情API
+    import { log } from 'console';
+    import DetailDialog from './detailDialog.vue';
+    import { watch } from 'vue';
     const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
     const ConsultantTemplateDialog = defineAsyncComponent(() => import('./consultantTemplateDialog.vue'));
@@ -119,9 +132,10 @@
     const multiple = ref(true);
     const total = ref(0);
     const type = ref('list');
-    const labelList = ref([]);
-    const detailData = ref({});
     const labelDialogVisible = ref(false);
+    const labelOptions = ref < any[] > ([]); // 新增: 用于存储可选标签对象
+    const showDetailDialog = ref(false);
+    const currentDetail = ref({});
 
     const queryFormRef = ref < ElFormInstance > ();
     const diagnosisFormRef = ref < ElFormInstance > ();
@@ -131,6 +145,7 @@
         visible: false,
         title: ''
     });
+
     // 声明接收的 props
     const props = defineProps({
         patientInfo: {
@@ -147,12 +162,14 @@
 
     const initFormData: DiagnosisForm = {
         id: undefined,
-        treatmentUserId: props.patientInfo ?.id, // Initialize with patient ID
+        labelList: [],
+        treatmentUserId: props.patientInfo ?.id,
         consultantTemplateId: undefined,
         diagnosisLableId: undefined,
         diagnosisBasisId: undefined,
         medicalOrder: undefined,
-        consultationContent: undefined,
+        consultantResult: undefined,
+        consultantResultStr: undefined,
     }
 
     const data = reactive < PageData < DiagnosisForm,
@@ -162,6 +179,7 @@
                 pageNum: 1,
                 pageSize: 10,
                 visitType: undefined,
+                treatmentUserId: props.patientInfo ?.id,
                 dateRange: undefined,
                 searchValue: undefined,
                 params: {}
@@ -178,26 +196,25 @@
 
     const { queryParams, form, rules } = toRefs(data);
 
+    // 监听患者ID变化,自动同步到表单和查询参数
+    watch(
+      () => props.patientInfo.id,
+      (newId) => {
+        form.value.treatmentUserId = newId;
+        queryParams.value.treatmentUserId = newId;
+      },
+      { immediate: true }
+    );
+
     /** 查询营养诊断列表 */
     const getList = async () => {
         loading.value = true;
         const res = await listDiagnosis(queryParams.value);
         diagnosisList.value = res.rows;
-        console.log("diagnosisList", JSON.stringify(diagnosisList.value));
 
         total.value = res.total;
         loading.value = false;
     }
-    // 详情按钮处理
-    const getTreatmentUser = async () => {
-        try {
-            // 获取患者详细信息
-            const res = await fetchTreatmentUser(props.patientInfo ?.id);
-            detailData.value = res.data;
-        } catch (error) {
-
-        }
-    };
 
     /** 取消按钮 */
     const cancel = () => {
@@ -206,24 +223,27 @@
     }
     // 标签确认回调
     function onLabelConfirm(selectedLabels: Array < { labelId: string | number;labelName: string } > ) {
-        labelList.value = selectedLabels;
+        form.value.labelList = selectedLabels.map(l => l.labelId); // 只存labelId
+        labelOptions.value = selectedLabels; // 用于el-option展示labelName
     }
-    const onTemplateSelect = async (templateContent) => {
+    const onTemplateSelect = async (data) => {
+        form.value.consultantTemplateId = data.id;
+        let templateContent = data.template;
+        console.log(JSON.stringify(data));
+
         if (!templateContent) return;
 
         try {
             // 获取患者详细信息
             const res = await fetchTreatmentUser(props.patientInfo ?.id);
             const patientDetail = res.data || {};
-
-            console.log('Template content:', templateContent);
-            console.log('Patient details:', patientDetail);
-
+            form.value.consultantTemplateId = data.id;
             // 替换模板中的占位符
             let processedContent = templateContent;
 
             // 定义替换规则(根据实际字段进行调整)
             const replacements = {
+                'purpose': patientDetail.type == 1 ? '住院' : '门诊' || '',
                 'height': patientDetail.height || '',
                 'weight': patientDetail.weight || '',
                 'bmi': patientDetail.bmi || '',
@@ -234,7 +254,6 @@
                 'beforeAlb': patientDetail.beforeAlb || '',
                 'way': patientDetail.way || '',
                 'glimResult': patientDetail.glimResult || '',
-                'purpose': patientDetail.purpose || '',
                 'lossWeight': patientDetail.lossWeight || '',
                 'totalCalories': patientDetail.totalCalories || '',
                 'totalProtein': patientDetail.totalProtein || '',
@@ -246,8 +265,6 @@
                 // 可以根据需要添加更多替换规则
             };
 
-            console.log('Replacements:', replacements);
-
             // 执行替换
             for (const [key, value] of Object.entries(replacements)) {
                 const placeholder = '${' + key + '}';
@@ -255,21 +272,22 @@
                 processedContent = processedContent.split(placeholder).join(value);
             }
 
-            console.log('Processed content:', processedContent);
-
             // 将处理后的内容赋值给表单
-            form.value.consultationContent = processedContent;
+            form.value.consultantResult = processedContent;
         } catch (error) {
             console.error('获取患者详情失败:', error);
             proxy ?.$modal.msgError('获取患者详情失败');
             // 如果获取详情失败,仍然使用原始模板
-            form.value.consultationContent = templateContent;
+            form.value.consultantResult = templateContent;
         }
     };
 
     /** 表单重置 */
     const reset = () => {
-        form.value = { ...initFormData };
+        form.value = { 
+            ...initFormData,
+            treatmentUserId: props.patientInfo ?.id // 用最新id
+         };
         diagnosisFormRef.value ?.resetFields();
     }
 
@@ -282,8 +300,19 @@
     /** 重置按钮操作 */
     const resetQuery = () => {
         queryFormRef.value ?.resetFields();
+        queryParams.value.dateRange = undefined;
+        queryParams.value.type = undefined;
+        queryParams.value.searchValue = undefined;
+        queryParams.value.pageNum = 1;
+        queryParams.value.pageSize = 10;
         handleQuery();
     }
+    // 字典label工具
+    function getDictLabel(dictList: any[], value: string) {
+        if (!dictList || !Array.isArray(dictList)) return value || '--';
+        const found = dictList.find(item => item.value === value);
+        return found ? found.label : value || '--';
+    }
 
     /** 多选框选中数据 */
     const handleSelectionChange = (selection: DiagnosisVO[]) => {
@@ -302,7 +331,7 @@
         type.value = 'list';
     };
     const clearContent = () => {
-        form.value.consultationContent = '';
+        form.value.consultantResult = '';
     }
 
     /** 修改按钮操作 */
@@ -311,6 +340,15 @@
         const _id = row ?.id || ids.value[0]
         const res = await getDiagnosis(_id);
         Object.assign(form.value, res.data);
+        // 适配labelList为labelId数组时,需获取完整标签对象
+        if (Array.isArray(form.value.labelList) && form.value.labelList.length > 0 && typeof form.value.labelList[0] !== 'object') {
+            // 批量获取标签详情
+            const labelIds = form.value.labelList;
+            const labelDetailPromises = labelIds.map(id => getDiseaseLabel(id).then(r => r.data));
+            labelOptions.value = await Promise.all(labelDetailPromises);
+        } else {
+            labelOptions.value = form.value.labelList || [];
+        }
         dialog.visible = true;
         dialog.title = "修改营养诊断";
     }
@@ -321,8 +359,12 @@
             if (valid) {
                 buttonLoading.value = true;
                 if (form.value.id) {
+                    form.value.consultantResultStr = window.btoa(encodeURIComponent(form.value.consultantResult))
                     await updateDiagnosis(form.value).finally(() => buttonLoading.value = false);
                 } else {
+                    console.log('addForm', JSON.stringify(form.value));
+
+                    form.value.consultantResultStr = window.btoa(encodeURIComponent(form.value.consultantResult))
                     await addDiagnosis(form.value).finally(() => buttonLoading.value = false);
                 }
                 proxy ?.$modal.msgSuccess("操作成功");
@@ -330,7 +372,6 @@
                 await getList();
                 type.value = 'list';
             }
-
         });
     }
 
@@ -343,7 +384,17 @@
         await getList();
     }
 
+    const handleDetail = (row: any) => {
+        currentDetail.value = row;
+        currentDetail.value.consultantResult= stripHtml(currentDetail.value.consultantResult);
+        showDetailDialog.value = true;
+    };
 
+    function stripHtml(html) {
+        const div = document.createElement('div');
+        div.innerHTML = html;
+        return div.textContent || div.innerText || '';
+    }
 
     onMounted(() => {
         getList();

+ 1 - 0
src/views/patients/nutritionEducation/index.vue

@@ -0,0 +1 @@
+<template>营养宣教</template>

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

@@ -67,8 +67,8 @@
                                         <span class="patient-name">{{ patient.treatName }}</span>
                                         <span class="patient-age">{{ patient.age }}</span>
                                     </div>
-                                    <span class="gender-icon" :class="patient.sex === '1' ? 'male' : 'female'">
-                                        {{ patient.sex === '1' ? '♂' : '♀' }}
+                                    <span class="gender-icon" :class="patient.sex === '0' ? 'male' : 'female'">
+                                        {{ patient.sex === '0' ? '♂' : '♀' }}
                                     </span>
                                 </div>
                                 <div class="patient-detail">
@@ -166,7 +166,7 @@
                     <el-col :span="12">
                         <el-form-item label="性别" prop="sex">
                             <el-select v-model="form.sex" placeholder="请选择" clearable>
-                                <el-option v-for="dict in user_sex" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value" />
                             </el-select>
                         </el-form-item>
                         <el-form-item label="出生日期" prop="birthday">
@@ -219,7 +219,7 @@
 
     const router = useRouter();
     const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-    const { treatment_user_type, treatment_user_status, evaluation_status, physical_activity, user_sex } = toRefs < any > (proxy ?.useDict('treatment_user_type', 'treatment_user_status', 'evaluation_status', 'physical_activity', 'user_sex'));
+    const { treatment_user_type, treatment_user_status, evaluation_status, physical_activity, sys_user_sex } = toRefs < any > (proxy ?.useDict('treatment_user_type', 'treatment_user_status', 'evaluation_status', 'physical_activity', 'sys_user_sex'));
     const userList = ref < TreatmentUserVo[] > ([]);
     const buttonLoading = ref(false);
     const loading = ref(true);
@@ -449,7 +449,7 @@
 
             // 根据身份证倒数第二位判断性别(奇数为男,偶数为女)
             const genderNum = parseInt(idCard.length === 18 ? idCard.charAt(16) : idCard.charAt(14));
-            form.value.sex = (genderNum % 2 === 1 ? '1' : '2').toString();
+            form.value.sex = (genderNum % 2 === 1 ? '0' : '1').toString();
         }
     }