Files
his/openhis-ui-vue3/src/views/inpatientDoctor/home/emr/index.vue
chenqi 6af7720470 feat(diagnosis): 完善诊断模块功能并优化病历数据获取
- 添加isSaving状态控制保存过程
- 监听患者信息变化自动获取病历详情和诊断列表
- 增强getDetail方法添加错误处理和日志输出
- 重构handleAddDiagnosis方法分离验证逻辑到独立函数
- 优化病历详情获取接口同时查询门诊和住院病历数据
- 添加文档定义树形列表按使用范围筛选功能
- 修复历史病历数据加载错误处理机制
2026-03-12 23:21:34 +08:00

1075 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* @Author: sjjh
* @Date: 2025-09-18 15:41:10
* @Description: 病历使用首页
-->
<template>
<div class="emr-use-container">
<div
class="disBtn"
:class="{ disLeftBtnNor: leftShow, disLeftBtnAct: !leftShow }"
@click="disNode"
>
<img src="../../../../assets/icons/svg/foldup.svg" />
</div>
<div
class="disBtn"
:class="{ disRightBtnNor: rightShow, disRightBtnAct: !rightShow }"
@click="disNode_R"
>
<img src="../../../../assets/icons/svg/foldup.svg" />
</div>
<transition name="el-zoom-in-left">
<div class="template-tree-container" v-if="leftShow">
<div class="search-box">
<el-input placeholder="病历名称搜索..." v-model="queryParams.name">
<template #append>
<el-button @click="queryTemplateTree">查询</el-button>
</template>
</el-input>
</div>
<el-scrollbar class="template-tree-scrollbar">
<el-tree
ref="templateTree"
:data="templateData"
:props="defaultProps"
auto-expand-parent
node-key="id"
@node-click="handleNodeClick"
class="template-tree"
></el-tree>
</el-scrollbar>
</div>
</transition>
<div class="operate-container">
<div class="operate-btns">
<el-space>
<!-- <el-button type="primary" @click="newEmr">新建</el-button> -->
<el-button type="primary" @click="saveAsModel">存为模版</el-button>
<el-button @click="refresh">刷新</el-button>
<el-button @click="resetForm">重置</el-button>
<el-button type="primary" @click="save">保存</el-button>
<el-button type="primary" @click="onPrint">打印表单</el-button>
<!-- <el-button type="primary" @click="" disabled>病案上传</el-button>
<el-button type="primary" @click="">结算上传</el-button> -->
<!-- <el-button type="primary" @click="onNursingStatus">护理状态</el-button> -->
<!-- <el-button type="primary" @click="print">打印</el-button> -->
</el-space>
</div>
<div class="operate-main">
<el-scrollbar class="template-tree-scrollbar">
<div v-loading="loading" class="loading-container">
<component
:is="currentComponent"
ref="emrComponentRef"
:patientInfo="patientInfo"
@submitOk="handleSubmitOk"
/>
</div>
</el-scrollbar>
</div>
</div>
<transition name="el-zoom-in-left">
<div class="quickly-container" v-if="rightShow">
<el-tabs v-model="quicklyactiveName" type="card">
<el-tab-pane label="历史" name="history">
<History
@historyClick="handleHistoryClick"
ref="historyRef"
v-model:definitionId="currentSelectTemplate.id"
:selectedRecordId="selectedHistoryRecordId"
/>
</el-tab-pane>
<el-tab-pane label="模版" name="model">
<Template
@templateClick="handleTemplateClick"
ref="templateRef"
v-model:definitionId="currentSelectTemplate.id"
@edit="templateEdit"
/>
</el-tab-pane>
</el-tabs>
</div>
</transition>
<TemplateEdit
ref="templateEditRef"
:formData="editTemplateForm"
v-model:dialogVisible="templateEditVisible"
@submitOk="templateEditSubmitOk"
/>
<el-drawer v-model="openDrawer" size="100%">
<template #default>
<div>
<NursingStatus></NursingStatus>
</div>
</template>
</el-drawer>
</div>
</template>
<script setup>
import {nextTick, onMounted, reactive, ref, watch} from 'vue';
import {ElMessage, ElMessageBox} from 'element-plus';
import {getTreeList} from '@/views/basicmanage/caseTemplates/api';
import {addTemplate, getRecordByEncounterIdList, saveOrUpdateRecord} from './api';
import {localPatientInfo as patientInfo} from '../store/localPatient.js';
import NursingStatus from '@/views/inpatientDoctor/home/components/applicationShow/nursingStatus.vue';
import dayjs from 'dayjs';
// 打印工具
import {PRINT_TEMPLATE, simplePrint} from '@/utils/printUtils.js';
import useUserStore from '@/store/modules/user';
import History from './components/history';
import Template from './components/template';
import TemplateEdit from './components/templateEdit.vue';
const userStore = useUserStore();
// 移除未使用的变量
// const { proxy } = getCurrentInstance();
const emits = defineEmits([]);
const props = defineProps({});
const state = reactive({});
// 定义响应式变量
const templateData = ref([]);
const queryParams = ref({
name: '',
useRanges: [1, 2], // 0 暂不使用 1 全院 2 科室 3 个人
organizationId: userStore.orgId,
});
const loading = ref(false); // 数据加载状态
const currentSelectTemplate = ref({
id: '',
});
const openDrawer = ref(false);
const currentComponent = ref('');
const emrComponentRef = ref(null);
const quicklyactiveName = ref('history');
const leftShow = ref(true);
const rightShow = ref(true);
// 使用防抖处理历史记录和模板列表的刷新
let listRefreshDebounceTimer = null;
watch(patientInfo, () => {
if (listRefreshDebounceTimer) {
clearTimeout(listRefreshDebounceTimer);
}
listRefreshDebounceTimer = setTimeout(() => {
historyRef.value?.queryList();
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
// templateRef.value?.queryList();
}, 150); // 稍微延后刷新,避免频繁更新
});
const templateTree = ref(null);
// 当前选中的历史病历ID用于在History组件中高亮显示
const selectedHistoryRecordId = ref('');
// 树配置(模板树)
const defaultProps = {
children: 'children',
label: 'name',
value: 'id',
};
/** 初始化病历模板树(按科室筛选) */
const queryTemplateTree = async () => {
try {
const res = await getTreeList(queryParams.value);
templateData.value = res.data || [];
// 组件挂载后,如果有患者信息,默认选中门诊病历模板
if (patientInfo.value && patientInfo.value.patientId && templateData.value.length > 0) {
selectOutpatientMedicalRecordTemplate();
}
} catch (error) {
ElMessage.error('获取模板树失败');
templateData.value = [];
}
};
// 处理节点点击,根据后台返回的路径加载组件
const handleNodeClick = (data, node) => {
if (node.isLeaf) {
// 存储当前节点数据
currentSelectTemplate.value = data.document;
// 在切换组件前先重置表单数据,避免显示之前的数据
editForm.value = {
id: '',
definitionId: '',
definitionBusNo: '',
contentJson: '',
statusEnum: 1,
organizationId: 0,
encounterId: '',
patientId: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
createBy: '',
source: '',
};
// 先清空当前组件,再设置新组件,确保组件完全重新渲染
currentComponent.value = undefined;
// 使用 nextTick 确保 DOM 更新后再设置新组件
nextTick(() => {
currentComponent.value = currentSelectTemplate.value.vueRouter;
});
} else {
currentSelectTemplate.value = {
id: '',
};
// currentComponent.value = null;
}
// 确保组件状态更新后再查询历史记录
nextTick(() => {
setTimeout(() => {
historyRef.value?.queryList();
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
// templateRef.value?.queryList();
// 选择任何病历模板后,都加载该病历类型的最新历史记录
if (node.isLeaf && patientInfo.value && patientInfo.value.patientId) {
loadLatestMedicalRecord();
}
}, 100);
});
};
const newEmr = () => {
if (currentSelectTemplate.value) {
currentComponent.value = currentSelectTemplate.value.vueRouter;
return;
}
ElMessage.error('请选择模版!');
};
const saveAsModel = async () => {
try {
currentOperate.value = 'addTemplate';
await emrComponentRef.value?.submit();
} catch (error) {
ElMessage.error('存为模版失败');
}
};
const editForm = ref({
id: '',
definitionId: '',
definitionBusNo: '',
contentJson: '',
statusEnum: 1, // 0草稿/暂存 1提交 2归档 3修改
organizationId: 0,
encounterId: '',
patientId: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
createBy: '',
source: '',
});
const editTemplateForm = ref({
id: '',
name: '',
displayOrder: 0,
contextJson: '',
definitionId: '',
useRange: 2,
organizationId: userStore.orgId,
userId: '',
useRanges: [1], // 默认全院使用
remark: '',
});
const currentOperate = ref('add');
const handleSubmitOk = async (data) => {
if (currentOperate.value === 'add') {
//
try {
if (!patientInfo.value?.encounterId || !patientInfo.value?.patientId) {
ElMessage.error('请先选择患者!');
return;
}
editForm.value.definitionId = currentSelectTemplate.value.id;
editForm.value.definitionBusNo = currentSelectTemplate.value.busNo;
editForm.value.contentJson = JSON.stringify(data);
editForm.value.encounterId = patientInfo.value.encounterId;
editForm.value.patientId = patientInfo.value.patientId;
editForm.value.recordTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
await saveOrUpdateRecord(editForm.value);
// ElMessage.success('保存成功');
// 刷新历史记录列表
historyRef.value?.queryList();
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
// templateRef.value?.queryList();
// 等待历史记录列表更新后,重新加载最新病历并更新选中状态
setTimeout(() => {
loadLatestMedicalRecord();
}, 100);
ElMessage.success('保存成功');
} catch (error) {
ElMessage.error('提交失败');
console.log(error);
}
} else if (currentOperate.value === 'addTemplate') {
// 新增或者编辑模板
// editTemplateForm.value.id=
editTemplateForm.value.name =
currentSelectTemplate.value.name + dayjs().format('YYYY/MM/DD HH:mm');
editTemplateForm.value.contextJson = JSON.stringify(data);
editTemplateForm.value.definitionId = currentSelectTemplate.value.id;
editTemplateForm.value.organizationId = userStore.orgId;
editTemplateForm.value.useRanges = [1]; // 默认全院使用
templateEditVisible.value = true;
}
};
// 定义病历模板类型与打印模板的映射关系
const templateToPrintTemplateMap = {
// 手术记录相关模板
手术记录: PRINT_TEMPLATE.OPERATIVE_RECORD,
'手术记录(1.0.0)': PRINT_TEMPLATE.OPERATIVE_RECORD,
tySurgicalRecord: PRINT_TEMPLATE.OPERATIVE_RECORD,
// 门诊病历相关模板
门诊病历: PRINT_TEMPLATE.HQOUTPATIENT_MEDICAL_RECORD,
'门诊病历(1.0.0)': PRINT_TEMPLATE.HQOUTPATIENT_MEDICAL_RECORD,
测试新增: PRINT_TEMPLATE.HQOUTPATIENT_MEDICAL_RECORD,
};
// 根据模板名称获取对应的打印模板
const getPrintTemplateByTemplateName = (templateName) => {
// 默认使用红旗门诊病历模板
let printTemplate = PRINT_TEMPLATE.HQOUTPATIENT_MEDICAL_RECORD;
if (templateName) {
for (const [key, value] of Object.entries(templateToPrintTemplateMap)) {
if (templateName.includes(key)) {
printTemplate = value;
break;
}
}
}
return printTemplate;
};
// 辅助函数:将嵌套对象扁平化为单层结构
const flattenObject = (obj, prefix = '') => {
const flattened = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const newKey = prefix ? `${prefix}_${key}` : key;
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
// 递归处理嵌套对象
Object.assign(flattened, flattenObject(obj[key], newKey));
} else if (Array.isArray(obj[key])) {
// 数组转换为字符串
flattened[newKey] = JSON.stringify(obj[key]);
} else {
// 基本类型直接赋值
flattened[newKey] = obj[key];
}
}
}
return flattened;
};
// 打印
const print = async () => {
try {
if (!currentSelectTemplate.value || !currentSelectTemplate.value.id) {
ElMessage.warning('请先选择病历模板');
return;
}
console.log('打印模板:', currentSelectTemplate.value.name);
console.log('打印病历ID:', editForm.value.id);
// 检查是否已保存
if (!editForm.value.id || editForm.value.id === '') {
ElMessage.warning('请先保存病历后再进行打印');
return;
}
// 获取当前病历组件的表单数据
const formData = emrComponentRef.value?.formData || {};
// 获取当前模板名称
const templateName = currentSelectTemplate.value.name || '';
// 根据模板名称获取对应的打印模板
const selectedPrintTemplate = getPrintTemplateByTemplateName(templateName);
// 打印数据
const printData = {
// 模板信息
templateName: currentSelectTemplate.value.name || '住院病历',
templateId: currentSelectTemplate.value.id || '',
// 医生信息
doctorName: userStore.nickName,
// 患者信息
patientName: patientInfo.value.patientName || '',
patientId: patientInfo.value.patientId || '',
medicalRecordNo: patientInfo.value.medicalRecordNo || '',
gender: patientInfo.value.gender || '',
age: patientInfo.value.age || '',
genderEnum_enumText: patientInfo.value.genderEnum_enumText || '',
idCard: patientInfo.value.idCard || '',
phone: patientInfo.value.phone || '',
registerTime: patientInfo.value.registerTime || '',
// 就诊信息
encounterId: patientInfo.value.encounterId || '',
department: patientInfo.value.department || '',
attendingDoctor: patientInfo.value.attendingDoctor || '',
// 病历信息
documentName: currentSelectTemplate.value.name || '住院病历',
documentId: currentSelectTemplate.value.id || '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
printTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
//病历号
busNo: patientInfo.value.busNo || '',
//费用类型
contractName: patientInfo.value.contractName || '',
// 表单数据 - 需要将嵌套结构展开
...flattenObject(formData),
};
console.log('打印数据:', printData);
// 执行打印,使用根据模板类型选择的打印模板
await simplePrint(selectedPrintTemplate, printData);
// 刷新历史记录列表
historyRef.value?.queryList();
ElMessage.success('打印成功');
} catch (error) {
console.error('打印失败:', error);
ElMessage.error('打印失败: ' + (error.message || '未知错误'));
}
};
const refresh = () => {
queryTemplateTree();
historyRef.value?.queryList();
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
// templateRef.value?.queryList();
};
const deleteEmr = async () => {
try {
// 这里应该添加实际的删除逻辑
ElMessage.success('删除成功!');
} catch (error) {
ElMessage.error('删除失败');
}
};
// 重置表单数据
const resetForm = async () => {
ElMessageBox.confirm('确定要重置吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
try {
// 重置editForm为初始值
editForm.value = {
id: '',
definitionId: '',
definitionBusNo: '',
contentJson: '',
statusEnum: 1,
organizationId: 0,
encounterId: '',
patientId: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
createBy: '',
source: '',
printCount: 0,
};
// 清空选中的历史记录ID
selectedHistoryRecordId.value = '';
// 先将组件设置为空,强制卸载
const currentComponentName = currentComponent.value;
if (currentComponentName) {
currentComponent.value = undefined;
// 等待DOM更新
await nextTick();
// 重新加载组件
currentComponent.value = currentComponentName;
// 再次等待DOM更新后设置空数据
await nextTick();
console.log('组件已重新加载,正在清空数据');
}
// 重置动态组件表单数据
if (emrComponentRef.value && emrComponentRef.value.setFormData) {
console.log('重置表单数据', emrComponentRef.value);
emrComponentRef.value.setFormData({});
}
ElMessage.success('表单已重置');
} catch (error) {
console.error('重置表单失败:', error);
ElMessage.error('重置表单失败');
}
});
};
// 打开护理状态页面
const onNursingStatus = () => {
openDrawer.value = true;
};
const save = async () => {
try {
currentOperate.value = 'add';
await emrComponentRef.value?.submit();
} catch (error) {
console.log('error=============>', error);
ElMessage.error('保存失败');
}
};
// 默认选中门诊病历模板
// 这个函数现在已被selectDefaultTemplate替代保留用于兼容性
const selectOutpatientMedicalRecordTemplate = async () => {
// 直接调用新的selectDefaultTemplate函数
selectDefaultTemplate();
};
// 加载最新的病历数据并回显
const loadLatestMedicalRecord = async () => {
if (!patientInfo.value?.encounterId || !currentSelectTemplate.value.id) return;
editForm.value.id = '';
loading.value = true;
try {
// 获取患者的历史病历记录
const res = await getRecordByEncounterIdList({
isPage: 0,
encounterId: patientInfo.value.encounterId,
patientId: patientInfo.value.patientId,
definitionId: currentSelectTemplate.value.id,
});
const historyRecords = res.data || [];
if (historyRecords.length > 0) {
// 按时间排序,获取最新的病历记录
historyRecords.sort((a, b) => new Date(b.recordTime) - new Date(a.recordTime));
const latestRecord = historyRecords[0];
// 保存最新病历ID用于在History组件中高亮显示
selectedHistoryRecordId.value = latestRecord.id;
// 自动回显最新病历数据到模板
editForm.value = latestRecord;
nextTick(() => {
if (emrComponentRef.value && latestRecord.contentJson) {
try {
const parsedData = JSON.parse(latestRecord.contentJson);
emrComponentRef.value.setFormData(parsedData);
} catch (parseError) {
console.error('解析病历数据失败:', parseError);
// 解析失败时仍然尝试设置空数据以清空之前的残留数据
emrComponentRef.value.setFormData({});
}
} else {
// 如果没有内容数据,也要清空组件中的数据
emrComponentRef.value.setFormData({});
}
// 通知History组件更新选中状态
if (historyRef.value && typeof historyRef.value.updateSelectedRecord === 'function') {
historyRef.value.updateSelectedRecord(latestRecord.id);
}
});
} else {
// 清空选中状态
selectedHistoryRecordId.value = '';
// 当没有历史记录时,也要清空当前表单数据,避免显示之前患者的数据
editForm.value = {
id: '',
definitionId: '',
definitionBusNo: '',
contentJson: '',
statusEnum: 1,
organizationId: 0,
encounterId: '',
patientId: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
createBy: '',
source: '',
};
nextTick(() => {
if (emrComponentRef.value) {
emrComponentRef.value.setFormData({});
}
});
loading.value = false;
}
} catch (error) {
console.error('加载最新病历数据失败:', error);
ElMessage.error('加载最新病历数据失败');
// 出错时也清空选中状态
selectedHistoryRecordId.value = '';
// 出错时也要清空表单数据,避免显示之前患者的数据
editForm.value = {
id: '',
definitionId: '',
definitionBusNo: '',
contentJson: '',
statusEnum: 1,
organizationId: 0,
encounterId: '',
patientId: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
createBy: '',
source: '',
};
nextTick(() => {
if (emrComponentRef.value) {
emrComponentRef.value.setFormData({});
}
});
loading.value = false;
} finally {
loading.value = false;
}
};
// 选择默认模板 - 获取住院病历分类下的第一个模板
const selectDefaultTemplate = () => {
nextTick(() => {
if (!templateData.value || templateData.value.length === 0) {
console.log('模板数据为空,无法选择默认模板');
return;
}
// 查找住院病历分类节点,然后获取其下的第一个模板
const findInpatientRecordCategoryAndFirstTemplate = (nodes) => {
for (const node of nodes) {
// 检查是否是住院病历分类节点
if (!node.document && node.name && node.name.includes('住院病历')) {
// 这是一个分类节点,检查是否有子节点
if (node.children && node.children.length > 0) {
// 返回第一个有document属性的子节点即第一个模板
for (const child of node.children) {
if (child.document) {
return child;
}
}
}
}
// 递归查找子节点
if (node.children && node.children.length > 0) {
const found = findInpatientRecordCategoryAndFirstTemplate(node.children);
if (found) {
return found;
}
}
}
return null;
};
const defaultTemplate = findInpatientRecordCategoryAndFirstTemplate(templateData.value);
if (defaultTemplate) {
nextTick(() => {
templateTree.value?.setCurrentKey(defaultTemplate.id);
// 模拟点击节点
const mockNode = {
isLeaf: true,
};
handleNodeClick(defaultTemplate, mockNode);
// 直接加载最新病历数据不再使用额外的setTimeout延迟
// 因为handleNodeClick中已经有nextTick和setTimeout处理组件渲染
loadLatestMedicalRecord();
});
} else {
console.log('未找到住院病历模板');
}
});
};
const historyRef = ref(null);
const handleHistoryClick = async (data) => {
try {
newEmr();
editForm.value = data;
nextTick(() => {
emrComponentRef.value?.setFormData(JSON.parse(editForm.value.contentJson));
});
// 更新选中的历史记录ID
selectedHistoryRecordId.value = data.id;
} catch (error) {
ElMessage.error('设置历史数据失败');
console.error('设置历史数据失败:', error);
}
};
const templateRef = ref(null);
const handleTemplateClick = async (data) => {
try {
newEmr();
editForm.value = data;
nextTick(() => {
emrComponentRef.value?.setFormData(JSON.parse(editForm.value.contextJson));
});
} catch (error) {
ElMessage.error('设置模板数据失败');
console.error('设置模板数据失败:', error);
}
};
const templateEdit = (data) => {
editTemplateForm.value = data;
templateEditVisible.value = true;
};
// ====dialog
const templateEditVisible = ref(false);
const templateEditSubmitOk = async () => {
try {
// 根据是否存在ID来决定是新增还是编辑
if (!editTemplateForm.value.id) {
// 新增模板
const addResult = await addTemplate(editTemplateForm.value);
if (addResult && addResult.code === 200) {
ElMessage.success('模板新增成功');
// 刷新模板列表
if (templateRef.value && typeof templateRef.value.queryList === 'function') {
// 在模板操作后,需要清除缓存并重新加载
templateRef.value.queryList();
}
// 关闭模板编辑弹窗
templateEditVisible.value = false;
// 清空模板编辑表单
Object.assign(editTemplateForm.value, {
id: '',
name: '',
displayOrder: 0,
contextJson: '',
definitionId: '',
useRange: 2,
organizationId: userStore.orgId,
userId: '',
useRanges: [1],
remark: '',
});
} else {
ElMessage.error('模板新增失败');
console.error('模板新增失败:', addResult);
}
} else {
// 编辑模板 - 暂不实现编辑功能,只支持新增
ElMessage.warning('暂不支持编辑模板');
}
} catch (error) {
console.error('处理模板编辑提交失败:', error);
ElMessage.error('处理模板编辑提交失败: ' + (error.message || '未知错误'));
} finally {
// 无论成功失败都刷新列表
historyRef.value?.queryList();
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
// templateRef.value?.queryList();
}
};
// onBeforeMount(() => {});
// 监听患者信息变化,实现联动显示
watch(
() => patientInfo.value,
(newPatientInfo) => {
// 当患者信息变化时,默认选中住院病历模板并加载最新病历数据
if (newPatientInfo && newPatientInfo.patientId && Object.keys(newPatientInfo).length > 0) {
// 确保模板树已经加载
if (templateData.value && templateData.value.length > 0) {
// 优先尝试使用更精确的selectDefaultTemplate函数
selectDefaultTemplate();
} else {
// 重新加载模板树
queryTemplateTree().then(() => {
// 使用nextTick确保DOM更新移除setTimeout避免多次渲染
nextTick(() => {
selectDefaultTemplate();
});
});
}
} else {
// 如果没有患者信息,也要重置组件和表单数据
currentComponent.value = undefined;
editForm.value = {
id: '',
definitionId: '',
definitionBusNo: '',
contentJson: '',
statusEnum: 1,
organizationId: 0,
encounterId: '',
patientId: '',
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
createBy: '',
source: '',
};
// 如果有动态组件实例,也需要重置其表单数据
nextTick(() => {
if (emrComponentRef.value && emrComponentRef.value.setFormData) {
emrComponentRef.value.setFormData({});
}
});
}
},
{ deep: true, immediate: true }
);
onMounted(async () => {
// 移除日志
await queryTemplateTree();
// 组件挂载完成后,如果已有患者信息,默认选中住院病历模板
if (
patientInfo.value &&
patientInfo.value.patientId &&
Object.keys(patientInfo.value).length > 0
) {
// 使用nextTick确保模板树数据已更新
nextTick(() => {
selectDefaultTemplate();
});
}
});
// 打印
const onPrint = () => {
if (emrComponentRef?.value.printFun) {
emrComponentRef?.value.printFun();
}
};
// 添加一个方法供父组件调用,处理患者切换
const handlePatientChange = (patient) => {
// 更新患者信息
// 注意这里我们不直接修改patientInfo.value因为它是由父组件通过watch管理的
// 我们只需要确保当前组件响应patientInfo的变化
// 重置当前组件,确保在切换患者时重新加载
// 但我们需要确保在组件重新加载后能正确设置患者信息
const selectedTemplateId = currentSelectTemplate.value?.id;
if (selectedTemplateId) {
// 先清空当前组件
currentComponent.value = undefined;
// 使用nextTick确保DOM更新后再重新加载组件和数据
nextTick(() => {
// 重新设置组件
const template = templateData.value?.find(t => t.document && t.document.id === selectedTemplateId);
if (template && template.document?.vueRouter) {
currentComponent.value = template.document.vueRouter;
// 再次使用nextTick确保组件已加载后再加载数据
nextTick(() => {
loadLatestMedicalRecord();
});
} else {
// 如果找不到对应模板,尝试选择默认模板
selectDefaultTemplate();
}
});
} else {
// 如果没有选中模板,尝试选择默认模板
selectDefaultTemplate();
}
};
defineExpose({ state, handlePatientChange });
const disNode = () => {
leftShow.value = !leftShow.value;
};
const disNode_R = () => {
rightShow.value = !rightShow.value;
};
</script>
<style lang="scss" scoped>
.emr-use-container {
position: relative;
display: flex;
height: 100%;
img {
width: 200%;
height: 200%;
}
.disBtn {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
overflow: hidden;
}
.disLeftBtnNor {
cursor: pointer;
position: absolute;
top: 40%;
left: 18%;
width: 20px;
height: 60px;
z-index: 1111;
img {
transform: rotate(-90deg);
}
}
.disLeftBtnAct {
cursor: pointer;
position: absolute;
top: 40%;
left: 0;
width: 20px;
height: 60px;
z-index: 1111;
img {
transform: rotate(90deg);
}
}
.disRightBtnNor {
cursor: pointer;
position: absolute;
top: 40%;
right: 18.5%;
width: 20px;
height: 60px;
z-index: 1111;
img {
transform: rotate(90deg);
}
}
.disRightBtnAct {
cursor: pointer;
position: absolute;
top: 40%;
right: 0;
width: 20px;
height: 60px;
z-index: 1111;
img {
transform: rotate(-90deg);
}
}
.template-tree-container {
border-right: 1px solid #ebeef5;
width: 300px;
flex: none;
height: 100%;
padding: 0 8px 8px 0;
display: flex;
flex-direction: column;
.search-box {
height: 40px;
display: flex;
align-items: center;
flex: none;
border-bottom: 1px solid #ebeef5;
}
.template-tree-scrollbar {
height: calc(100% - 48px);
flex: auto;
}
// 加载容器样式
.loading-container {
min-height: 400px;
width: 100%;
position: relative;
}
}
.operate-container {
width: 100%;
//width: 300px;
//flex: auto;
display: flex;
flex-direction: column;
padding: 0 8px 8px 8px;
.operate-btns {
height: 40px;
flex: none;
display: flex;
align-items: center;
border-bottom: 1px solid #ebeef5;
}
.operate-main {
height: calc(100% - 40px);
flex: auto;
display: flex;
flex-direction: column;
min-height: 0;
.template-tree-scrollbar {
height: 100%;
flex: 1 1 auto;
min-height: 0;
}
.loading-container {
height: 100%;
min-height: 0;
width: 100%;
display: flex;
flex-direction: column;
}
:deep(.loading-container > *) {
flex: 1 1 auto;
min-height: 0;
}
:deep(.template-tree-scrollbar .el-scrollbar__wrap) {
height: 100%;
}
:deep(.template-tree-scrollbar .el-scrollbar__view) {
height: 100%;
display: flex;
flex-direction: column;
min-height: 0;
}
}
}
.quickly-container {
border-left: 1px solid #ebeef5;
width: 300px;
padding: 0 8px 8px 8px;
flex: none;
.el-tabs {
height: 100%;
}
}
}
@layer utilities {
.transition-width {
transition-property: width;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 300ms;
}
}
</style>