Files
his/openhis-ui-vue3/src/views/doctorstation/index.vue

689 lines
19 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="display: flex; justify-content: space-between; height: 90vh">
<div style="width: 15%; height: 100%; border: 1px solid #eee; border-right: 0">
<div style="padding: 10px; border: 1px solid #eee; height: 50px; border-right: 0">
<span>现诊患者</span>
<el-badge
:value="waitCount > 0 ? waitCount : ''"
:max="10"
style="float: right; color: #409eff; cursor: pointer; margin-right: 10px"
>
<span @click="openDrawer"> 患者队列 </span>
</el-badge>
</div>
<div style="width: 100%; padding: 10px">
<el-input
v-model="queryParams.searchKey"
placeholder="请输入患者名"
clearable
style="width: 100%; margin-bottom: 10px"
@keyup.enter="getPatientList"
>
<template #append>
<el-button icon="Search" @click="getPatientList" />
</template>
</el-input>
<el-date-picker
v-model="registerTime"
@change="handleTimeChange"
type="daterange"
style="width: 100%; margin-bottom: 10px"
:clearable="false"
placeholder="挂号时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
<el-scrollbar height="700px">
<div
v-for="(item, index) in patientList"
:class="item.active ? 'patient-card actived' : 'patient-card'"
:key="item.id"
@click="handleCardClick(item, index)"
>
<div class="main-info-container">
<!-- <el-avatar
:size="30"
src="\src\assets\images\man.png"
fit="scale-down"
/> -->
<div class="name-container">
<!-- 患者姓名 -->
<div class="name" style="max-width: 90px">
<el-text tclass="name" width="auto">{{ item.patientName || '未知' }}</el-text>
</div>
</div>
<div class="name-container">
<!-- 患者性别/年龄 -->
<div class="age">
<el-text tclass="name" width="auto">
{{ item.genderEnum_enumText }}/{{ item.age }}/{{ item.typeCode_dictText }}
</el-text>
</div>
</div>
</div>
<div class="doctor-parent-line" />
<div class="personal-info-container">
<div class="name-container">
<div class="name">
<el-text tclass="name" width="auto">挂号时间</el-text>
<el-text tclass="name" width="auto">
{{ item.registerTime ? formatDate(item.registerTime) : '-' }}
</el-text>
</div>
</div>
</div>
</div>
</el-scrollbar>
</div>
</div>
<div class="disabled-wrapper" style="width: 85%; border: 1px solid #eee; position: relative">
<div style="padding: 10px; border: 1px solid #eee; height: 50px; border-left: 0">
<el-descriptions :column="4">
<el-descriptions-item label="患者信息:" width="150">
{{
Object.keys(patientInfo).length !== 0
? patientInfo.patientName +
' / ' +
patientInfo.age +
' / ' +
patientInfo.genderEnum_enumText +
' / ' +
patientInfo.contractName
: '-'
}}
</el-descriptions-item>
<el-descriptions-item label="挂号时间:" width="150">
{{ Object.keys(patientInfo).length !== 0 ? formatDate(patientInfo.registerTime) : '-' }}
</el-descriptions-item>
<el-descriptions-item label="医生:" width="150">{{
userStore.name
}}</el-descriptions-item>
<el-descriptions-item label="" width="350">
<!-- 初诊 / 复诊 按钮 -->
<el-radio v-model="visitType" label="FIRST" :disabled="visitTypeDisabled">初诊</el-radio>
<el-radio v-model="visitType" label="FOLLOW_UP" :disabled="visitTypeDisabled">复诊</el-radio>
<!-- 原有按钮 -->
<el-button type="primary" plain @click.stop="handleFinish(patientInfo.encounterId)">
完诊
</el-button>
<el-button type="primary" plain @click.stop="handleLeave(patientInfo.encounterId)">
暂离
</el-button>
<el-button type="primary" plain @click.stop="handleRefund(patientInfo.encounterId)">
退费
</el-button>
<el-button
type="primary"
plain
@click.stop="getEnPrescription(patientInfo.encounterId)"
>
处方单
</el-button>
<el-button
type="primary"
plain
@click.stop="openDialog = true"
>
办理住院
</el-button>
<el-button
type="primary"
plain
@click.stop="handleCancelEncounter"
>
取消接诊
</el-button>
</el-descriptions-item>
</el-descriptions>
</div>
<div style="padding: 10px">
<el-tabs
type="card"
style="width: 100%; height: 100%"
v-loading="loading"
v-model="activeTab"
@tab-change="handleClick(activeTab)"
>
<el-tab-pane label="病历" name="emr">
<Emr
:patientInfo="patientInfo"
ref="emrRef"
@save="
(value) => {
saveStatus = value;
}
"
:visitType="visitType"
:firstVisitDate="firstVisitDate"
/>
</el-tab-pane>
<el-tab-pane label="诊断" name="diagnosis">
<Diagnosis
:patientInfo="patientInfo"
ref="diagnosisRef"
@diagnosisSave="
(value) => {
saveStatus = value;
}
"
/>
</el-tab-pane>
<el-tab-pane label="医嘱" name="prescription">
<prescriptionlist
:patientInfo="patientInfo"
ref="prescriptionRef"
:activeTab="activeTab"
/>
</el-tab-pane>
<el-tab-pane label="中医" name="tcm">
<tcmAdvice :patientInfo="patientInfo" ref="tcmRef" />
</el-tab-pane>
<el-tab-pane label="电子处方" name="eprescription">
<eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" />
</el-tab-pane>
</el-tabs>
<div class="overlay" v-if="disabled"></div>
</div>
</div>
<el-drawer v-model="drawer" title="患者队列" direction="ltr" @open="handleOpen">
<PatientList ref="patientDrawerRef" @toCurrent="handleReceive" />
</el-drawer>
<RefundListDialog
:open="openRefundListDialog"
:encounterId="currentEncounterId"
@close="openRefundListDialog = false"
/>
<HospitalizationDialog
:open="openDialog"
:patientInfo="patientInfo"
:encounterId="currentEncounterId"
@close="openDialog = false"
/>
<PrescriptionInfo
:open="openPrescriptionDialog"
:precriptionInfo="prescriptionInfo"
@close="openPrescriptionDialog = false"
/>
</div>
</template>
<script setup>
import Emr from './components/emr/emr.vue';
import {
getList,
leaveEncounter,
completeEncounter,
getEnPrescriptionInfo,
cancelEncounter,
getEmrHistoryList
} from './components/api.js';
import prescriptionlist from './components/prescription/prescriptionlist.vue';
import RefundListDialog from './components/prescription/refundListDialog.vue';
import PatientList from './components/patientList.vue';
import Diagnosis from './components/diagnosis/diagnosis.vue';
import PrescriptionInfo from './components/prescription/prescriptionInfo.vue';
import eprescriptionlist from './components/eprescriptionlist.vue';
import HospitalizationDialog from './components/hospitalizationDialog.vue';
import tcmAdvice from './components/tcm/tcmAdvice.vue';
import { formatDate, formatDateStr } from '@/utils/index';
import useUserStore from '@/store/modules/user';
import { nextTick } from 'vue';
import { onBeforeRouteLeave } from 'vue-router';
// // 监听路由离开事件
// onBeforeRouteLeave((to, from, next) => {
// // 弹出确认框
// const confirmLeave = window.confirm('确定要离开吗?未保存的数据可能丢失!');
// if (confirmLeave) {
// next(); // 允许离开
// } else {
// next(false); // 取消离开
// }
// });
defineOptions({
name: 'PatientParentCard',
});
const userStore = useUserStore();
const bedfont = 'bed-font';
const queryParams = ref({
pageNo: 1,
pageSize: 300,
registerTimeSTime: formatDateStr(new Date(), 'YYYY-MM-DD') + ' 00:00:00',
registerTimeETime: formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59',
});
const drawer = ref(false);
const openRefundListDialog = ref(false);
const openDialog = ref(false);
const openPrescriptionDialog = ref(false);
const saveStatus = ref(false);
const currentEncounterId = ref('');
const emits = defineEmits(['click']);
const activeTab = ref('emr');
const patientList = ref([]);
const patientInfo = ref({});
const visitTypeDisabled = ref(false);
const prescriptionInfo = ref([]);
const registerTime = ref([formatDate(new Date()), formatDate(new Date())]);
const patientDrawerRef = ref();
const prescriptionRef = ref();
const tcmRef = ref();
const emrRef = ref();
const diagnosisRef = ref();
const waitCount = ref(0);
const loading = ref(false);
const { proxy } = getCurrentInstance();
const visitType = ref('');
const firstVisitDate = ref('');
const disabled = computed(() => {
return Object.keys(patientInfo.value).length === 0;
});
const eprescriptionRef = ref();
onMounted(() => {
getWaitPatient();
});
getPatientList();
// 获取现诊患者列表
function getPatientList() {
queryParams.value.statusEnum = 2;
getList(queryParams.value).then((res) => {
patientList.value = res.data.records.map((item) => {
return {
...item,
active: currentEncounterId.value ? item.encounterId == currentEncounterId.value : false,
};
});
});
}
function setVisitType(type) {
visitType.value = type;
}
function checkPatientHistory(patient) {
// 重置状态
visitTypeDisabled.value = false;
firstVisitDate.value = '';
// 如果患者没有身份证号,无法判断是否为初诊
if (!patient.idCard) {
// 默认设置为初诊
visitType.value = 'FIRST';
return;
}
// 查询患者历史就诊记录
const params = {
patientId: patient.patientId,
idCard: patient.idCard
};
getEmrHistoryList(params).then(res => {
if (res.code === 200) {
const records = res.data?.records || [];
// 过滤掉当前正在进行的就诊记录排除相同encounterId的记录
const historyRecords = records.filter(record => record.encounterId !== patient.encounterId);
// 如果有历史记录(排除当前就诊),则为复诊
if (historyRecords.length > 0) {
visitType.value = 'FOLLOW_UP';
// 计算最早一次病历创建时间作为初诊日期
const earliest = historyRecords.reduce((min, cur) => {
const ct = new Date(cur.createTime).getTime();
return ct < min ? ct : min;
}, new Date(historyRecords[0].createTime).getTime());
// 使用统一格式化
firstVisitDate.value = formatDate(earliest);
} else {
// 如果没有历史记录,则为初诊
visitType.value = 'FIRST';
firstVisitDate.value = '';
}
} else {
// 请求失败,默认设置为初诊
visitType.value = 'FIRST';
firstVisitDate.value = '';
}
}).catch(() => {
// 异常情况,默认设置为初诊
visitType.value = 'FIRST';
firstVisitDate.value = '';
});
}
function getWaitPatient() {
queryParams.value.registerTimeSTime = formatDateStr(new Date(), 'YYYY-MM-DD') + ' 00:00:00';
queryParams.value.registerTimeETime = formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59';
queryParams.value.statusEnum = 1;
getList(queryParams.value).then((res) => {
waitCount.value = res.data.total;
});
}
function handleClick(tab) {
switch (tab) {
case 'emr':
break;
case 'diagnosis':
diagnosisRef.value.getDetail(patientInfo.value.encounterId);
break;
case 'prescription':
prescriptionRef.value.getDiagnosisInfo();
break;
case 'tcm':
tcmRef.value.getDiagnosisInfo();
break;
case 'eprescription':
eprescriptionRef.value.getList();
break;
}
// if (tab != 'emr') {
// if (!saveStatus.value) {
// emrRef.value.addEmr();
// }
// }
// if (tab != 'diagnosis') {
// if (!saveStatus.value) {
// let valid= diagnosisRef.value.handleSaveDiagnosis();
// console.log(valid);
// }
// }
}
// 查看本次就诊处方单
function getEnPrescription(encounterId) {
getEnPrescriptionInfo({ encounterId: encounterId }).then((res) => {
prescriptionInfo.value = res.data;
openPrescriptionDialog.value = true;
});
}
function handleRefund(encounterId) {
currentEncounterId.value = encounterId;
openRefundListDialog.value = true;
}
function handleOpen() {
patientDrawerRef.value.refreshList();
}
function handleCardClick(item, index) {
currentEncounterId.value = '';
loading.value = true;
patientList.value.forEach((patient) => {
patient.active = patient.encounterId === item.encounterId;
});
patientInfo.value = item;
// 优先使用数据库中保存的初复诊值
if (item.visitType) {
visitType.value = item.visitType;
// 已完诊的记录禁用修改
visitTypeDisabled.value = item.statusEnum !== 2;
// 如果有初诊日期也从数据库获取
// if (item.firstVisitDate) {
// firstVisitDate.value = item.firstVisitDate;
// }
} else {
// 对于没有初复诊记录的患者,才使用原有的判断逻辑
checkPatientHistory(item);
}
activeTab.value = 'emr';
nextTick(() => {
prescriptionRef.value.getListInfo();
tcmRef.value.getListInfo();
diagnosisRef.value.getList();
eprescriptionRef.value.getList();
emrRef.value.getDetail(item.encounterId);
setTimeout(() => {
loading.value = false;
}, 200);
});
}
function handleLeave(encounterId) {
leaveEncounter(encounterId).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('操作成功');
patientInfo.value = {};
getPatientList();
}
});
}
function handleFinish(encounterId) {
completeEncounter(encounterId).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('操作成功');
patientInfo.value = {};
visitType.value = ''; // 重置初复诊标识
visitTypeDisabled.value = false; // 重置禁用状态
getPatientList();
}
});
}
function handleTimeChange(value) {
queryParams.value.registerTimeSTime = value[0] + ' 00:00:00';
queryParams.value.registerTimeETime = value[1] + ' 23:59:59';
getPatientList();
}
// 接诊回调
function handleReceive(row) {
handleCardClick(row);
currentEncounterId.value = row.encounterId;
drawer.value = false;
getPatientList();
getWaitPatient();
}
function openDrawer() {
drawer.value = true;
}
function handleCancelEncounter(){
proxy.$modal.confirm('您确定要取消病人本次的就诊记录吗?','提示信息',{
confirmButtonText: '是(Y)',
cancelButtonText: '否(N)',
type: 'warning'
}).then(() => {
//调用取消接诊API,添加skipGlobalError配置跳过全局错误提示
cancelEncounter(patientInfo.value.encounterId, { skipErrorMsg: true }).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('取消接诊成功');
patientInfo.value = {};
getPatientList();
}
}).catch((error) => {
proxy.$modal.confirm('该病人本次就诊已经有业务产生,不能取消接诊!','提示信息',{
confirmButtonText: '是(Y)',
type: 'warning'
});
});
}).catch(() => {
// 用户取消操作
});
}
</script>
<style lang="scss" scoped>
.patient-card {
width: 100%;
overflow: hidden;
background-color: #fff;
border: 1px solid;
border-color: #eee;
border-radius: 4px;
box-shadow: 0 2px 2px 0 rgba(57.55, 69.04, 86.28, 20%);
margin-bottom: 10px;
cursor: pointer;
&.actived {
background-color: rgb(7, 155, 140, 5%);
border-color: var(--el-color-primary);
}
.cross-dept {
height: 24px;
padding: 0 16px;
color: #fff;
font-size: 14px;
line-height: 24px;
background-color: #256d95;
}
.main-info-container {
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
margin: 7px 0;
padding: 0 16px;
.bed-container {
display: flex;
flex: 1;
align-items: center;
min-width: 0;
.bed {
flex-grow: 0;
flex-shrink: 1;
min-width: 0;
:deep(.bed-font) {
color: #333;
font-weight: 600;
font-size: 16px;
}
}
.bed_new {
flex-shrink: 0;
width: 10px;
height: 10px;
margin-left: 4px;
background: #29af6f;
border-radius: 50%;
}
}
.indepatient-code-container {
display: flex;
flex-shrink: 0;
align-items: center;
padding-left: 6px;
color: #666;
font-size: 14px;
.sign {
width: 24px;
height: 24px;
color: white;
line-height: 24px;
text-align: center;
border-radius: 50%;
user-select: none;
}
}
}
.doctor-parent-line {
margin: 0 16px;
border-bottom: 1px dashed #ddd;
}
.personal-info-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 8px 0;
padding: 0 16px;
.name-container {
display: flex;
align-items: center;
height: 18px;
.name {
color: #333;
font-size: 14px;
}
.age {
margin-left: 10px;
color: #666;
font-size: 14px;
}
}
.change-department {
width: 58px;
height: 24px;
color: #5585e3;
font-size: 14px;
line-height: 24px;
text-align: center;
background: #e6edfb;
border-radius: 4px;
}
}
.dept {
margin-bottom: 4px;
padding: 0 16px;
display: flex;
justify-content: space-between;
align-items: center;
.doctor {
display: flex;
align-items: center;
height: 32px;
line-height: 32px;
.doctor_name {
display: flex;
align-items: center;
margin-left: 4px;
color: #333;
}
}
.deptNurseName {
display: flex;
align-items: center;
height: 32px;
color: #256d95;
line-height: 32px;
}
}
}
:deep(.el-tabs__header) {
padding: 0;
position: relative;
margin: 0 0 5px !important;
}
:deep(.el-drawer__header) {
margin-bottom: 15px !important;
}
:deep(.el-drawer__body) {
padding: 10px !important;
}
.el-badge {
--el-badge-padding: 6px;
}
.disabled-wrapper .overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999; /* 确保覆盖在内容上方 */
cursor: not-allowed;
}
</style>