Files
his/openhis-ui-vue3/src/views/doctorstation/components/emr/emr.vue
2025-11-05 16:15:23 +08:00

361 lines
10 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.

<template>
<div style="margin-bottom: 15px">
<el-button type="primary" @click="addEmr()">保存</el-button>
<el-button type="primary" plain @click="handleEmrTemplate()" style="margin-left: 20px">
模板
</el-button>
<el-button type="primary" plain @click="handleSaveTemplate()" style="margin-left: 20px">
另存模板
</el-button>
<el-button type="primary" plain @click="handleEmrHistory()" style="margin-left: 20px">
历史病历
</el-button>
<!-- 可选添加打印按钮 -->
<!-- <el-button type="primary" plain @click="printEmr" style="margin-left: 20px">
打印病历
</el-button> -->
</div>
<div
ref="printArea"
style="max-height: 650px; overflow-y: auto; overflow-x: hidden; font-family: 'SimSun', '宋体', sans-serif;"
>
<!-- 标题 -->
<div style="text-align: center; font-size: 18px; font-weight: bold; margin-bottom: 10px;">
{{ visitType === 'FIRST' ? '门诊初诊病历' : '门诊复诊病历' }}
</div>
<!-- 患者基本信息 -->
<div style="display: flex; flex-wrap: wrap; gap: 10px; padding: 10px 0; border-bottom: 1px solid #ebeef5;">
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>就诊卡号:</strong> {{ patientInfo.patientId || '' }}
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>姓名:</strong> {{ patientInfo.patientName || '' }}
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>性别:</strong> {{ patientInfo.genderEnum_enumText || '' }}
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>年龄:</strong> {{ patientInfo.age || '' }}
</div>
</div>
<!-- 就诊信息 -->
<div style="display: flex; flex-wrap: wrap; gap: 10px; padding: 10px 0; border-bottom: 1px solid #ebeef5;">
<div style="flex: 1; min-width: 200px; font-size: 14px; line-height: 24px;">
<strong>就诊日期:</strong> {{ currentVisitDate }}
</div>
<div style="flex: 1; min-width: 200px; font-size: 14px; line-height: 24px;">
<strong>就诊科室:</strong> {{ patientInfo.organizationName || '' }}
</div>
</div>
<!-- 生命体征 -->
<div style="display: flex; flex-wrap: wrap; gap: 10px; padding: 10px 0; border-bottom: 1px solid #ebeef5;">
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>身高:</strong>
<el-input
v-model="form.height"
style="width: 80px; margin-left: 5px;"
/> cm
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>体重:</strong>
<el-input
v-model="form.weight"
style="width: 80px; margin-left: 5px;"
/> kg
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>体温:</strong>
<el-input
v-model="form.temperature"
style="width: 80px; margin-left: 5px;"
:step="0.1"
/>
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>脉搏:</strong>
<el-input
v-model="form.pulse"
style="width: 80px; margin-left: 5px;"
/> /
</div>
</div>
<!-- 主诉 + 发病日期 -->
<div style="display: flex; flex-wrap: wrap; gap: 10px; padding: 10px 0; border-bottom: 1px solid #ebeef5;">
<div style="flex: 1; min-width: 300px; font-size: 14px; line-height: 24px;">
<strong>主诉:</strong>
<el-input
v-model="form.chiefComplaint"
style="width: calc(100% - 50px); margin-left: 5px;"
/>
</div>
<div style="flex: 1; min-width: 120px; font-size: 14px; line-height: 24px;">
<strong>发病日期:</strong>
<el-date-picker
v-model="form.onsetDate"
type="date"
style="width: calc(100% - 80px); margin-left: 5px;"
value-format="YYYY-MM-DD"
/>
</div>
</div>
<!-- 多行文本字段 -->
<div v-for="field in textFieldList" :key="field.key" style="padding: 10px 0;">
<div style="font-size: 14px; margin-bottom: 5px;">
<strong>{{ field.label }}:</strong>
</div>
<el-input
v-model="form[field.key]"
type="textarea"
:rows="4"
style="width: 100%; font-size: 14px; line-height: 1.5;"
/>
</div>
<!-- 弹窗 -->
<el-dialog
:title="emrTitle"
v-model="openEmrTemplate"
:width="showDialog === 'emrHistory' ? '800px' : '600px'"
append-to-body
destroy-on-close
>
<emrTemplate v-if="showDialog === 'emrTemplate'" @selectRow="templateSelect" />
<emrhistory v-if="showDialog === 'emrHistory'" @selectRow="emrHistorySelect" />
<div v-if="showDialog === 'saveTemplate'">
<span>模板名称</span>
<el-input
v-model="templateName"
style="width: 260px; margin-top: 10px; margin-right: 20px"
/>
<el-radio-group v-model="radio">
<el-radio-button :label="1">个人</el-radio-button>
<el-radio-button :label="2">科室</el-radio-button>
<el-radio-button :label="3">全院</el-radio-button>
</el-radio-group>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submit"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { saveEmr, getEmrDetail, saveEmrTemplate } from '../api';
import emrTemplate from '../emr/emrtemplate.vue';
import emrhistory from '../emr/emrhistory.vue';
import { ref, computed, watch, getCurrentInstance } from 'vue';
import { formatDate as formatDateUtil } from '@/utils/index';
// Props
const props = defineProps({
patientInfo: {
type: Object,
required: true,
},
visitType: {
type: String,
default: '',
},
firstVisitDate: {
type: String,
default: '',
},
});
// Computed: 当前就诊日期
const currentVisitDate = computed(() => {
if (props.visitType === 'FOLLOW_UP' && props.firstVisitDate) {
return props.firstVisitDate;
}
return formatDateUtil(props.patientInfo?.registerTime || new Date());
});
// 表单数据
const form = ref({
height: '',
weight: '',
temperature: '',
pulse: '',
chiefComplaint: '',
onsetDate: '',
currentIllnessHistory: '',
pastMedicalHistory: '',
menstrualHistory: '',
allergyHistory: '',
physicalExamination: '',
treatment: '',
auxiliaryExamination: '',
});
// 文本字段配置(用于循环渲染)
const textFieldList = [
{ key: 'currentIllnessHistory', label: '现病史' },
{ key: 'pastMedicalHistory', label: '既往史' },
{ key: 'menstrualHistory', label: '个人史' },
{ key: 'allergyHistory', label: '过敏史' },
{ key: 'physicalExamination', label: '查体' },
{ key: 'treatment', label: '处理' },
{ key: 'auxiliaryExamination', label: '辅助检查' },
];
// 弹窗控制
const emrTitle = ref('');
const radio = ref(1);
const showDialog = ref('');
const openEmrTemplate = ref(false);
const templateName = ref('');
// 事件
const emits = defineEmits(['save']);
const { proxy } = getCurrentInstance();
// 监听表单变化
watch(
() => form.value,
() => {
emits('save', false);
},
{ deep: true }
);
// 格式化日期(用于 onsetDate
function formatDate(date) {
if (!date) return '';
return formatDateUtil(date);
}
// 保存病历
function addEmr() {
// 简单校验主诉
if (!form.value.chiefComplaint) {
proxy.$message.warning('请输入主诉');
return;
}
saveEmr({
patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.encounterId,
contextJson: form.value,
}).then((res) => {
if (res.code === 200) {
proxy.$modal.msgSuccess('病历已保存');
emits('save', true);
}
});
}
// 打开模板
function handleEmrTemplate() {
emrTitle.value = '病历模板';
showDialog.value = 'emrTemplate';
openEmrTemplate.value = true;
}
// 打开历史
function handleEmrHistory() {
emrTitle.value = '历史病历';
showDialog.value = 'emrHistory';
openEmrTemplate.value = true;
sessionStorage.setItem('patientId', props.patientInfo.patientId);
}
// 保存为模板
function handleSaveTemplate() {
emrTitle.value = '保存模板';
showDialog.value = 'saveTemplate';
openEmrTemplate.value = true;
}
// 选择模板/历史
function templateSelect(row) {
form.value = { ...row };
openEmrTemplate.value = false;
}
function emrHistorySelect(row) {
form.value = { ...row };
openEmrTemplate.value = false;
}
// 弹窗确认
function submit() {
if (showDialog.value === 'saveTemplate') {
if (!templateName.value.trim()) {
proxy.$message.warning('请输入模板名称');
return;
}
saveEmrTemplate({
templateName: templateName.value,
useScopeCode: radio.value,
contextJson: form.value,
}).then((res) => {
if (res.code === 200) {
openEmrTemplate.value = false;
proxy.$modal.msgSuccess('保存成功');
}
});
} else {
openEmrTemplate.value = false;
}
}
function cancel() {
openEmrTemplate.value = false;
}
// 可选:打印功能
// function printEmr() {
// const printContent = proxy.$refs.printArea.innerHTML;
// const originalContent = document.body.innerHTML;
// document.body.innerHTML = printContent;
// window.print();
// document.body.innerHTML = originalContent;
// window.location.reload(); // 恢复组件状态
// }
// 暴露方法给父组件
defineExpose({
getDetail(encounterId) {
getEmrDetail(encounterId).then((res) => {
if (res.data) {
try {
form.value = JSON.parse(res.data.contextJson) || {};
} catch (e) {
form.value = {};
}
emits('save', true);
} else {
form.value = {};
}
});
},
addEmr
});
</script>
<style scoped>
/* 可选:增强打印样式 */
@media print {
body * {
visibility: hidden;
}
#printArea, #printArea * {
visibility: visible;
}
#printArea {
position: absolute;
left: 0;
top: 0;
width: 100%;
}
}
</style>