Files
his/openhis-ui-vue3/src/views/doctorstation/components/hospitalizationDialog.vue
chenqi 257ea42db7 fix(hospitalization): 优化住院登记表单的默认值设置逻辑 bug#178
- 引入watch监听诊断类别字典变化,动态设置默认值
- 移除硬编码的medTypeCode初始值'21',改为从字典动态获取
- 修复科室选择逻辑,支持当前医生科室不在住院科室列表时的显示
- 为诊断类别添加验证逻辑,确保主诊断的medTypeCode在字典选项中
- 解决已选科室不在过滤列表中时无法正确显示的问题
- 添加科室树形结构递归查找功能,支持临时添加医生科室到选项列表
2026-03-17 19:22:07 +08:00

530 lines
17 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>
<el-dialog
title="住院登记"
v-model="props.open"
width="1000px"
append-to-body
destroy-on-close
@close="close"
@open="openDialog"
>
<div class="operate">
<div>患者信息</div>
</div>
<el-row>
<el-col :span="2" class="descriptions-item-label">
<el-text truncated>患者姓名</el-text>
</el-col>
<el-col :span="3" class="patInfo-value">
<el-text truncated>{{ patientInfo.patientName }}</el-text>
</el-col>
<el-col :span="2" class="descriptions-item-label">
<el-text truncated>年龄</el-text>
</el-col>
<el-col :span="3" class="patInfo-value">
<el-text truncated>{{ patientInfo.age }}</el-text>
</el-col>
<el-col :span="2" class="descriptions-item-label">
<el-text truncated>性别</el-text>
</el-col>
<el-col :span="3" class="patInfo-value">
<el-text truncated>{{ patientInfo.genderEnum_enumText }}</el-text>
</el-col>
<el-col :span="2" class="descriptions-item-label">
<el-text truncated>费用性质</el-text>
</el-col>
<el-col :span="3" class="patInfo-value">
<el-text truncated>{{ patientInfo.contractName }}</el-text>
</el-col>
</el-row>
<div class="operate">
<div>住院信息</div>
</div>
<el-form
class="register-from"
:model="submitForm"
style="padding-left: 8px"
ref="registerRef"
label-width="80px"
:rules="rules"
>
<el-row :gutter="8">
<el-col :span="6">
<el-form-item label="入院科室" prop="inHospitalOrgId">
<el-tree-select
clearable
style="width: 100%"
v-model="submitForm.inHospitalOrgId"
filterable
:data="organization"
:props="{
value: 'id',
label: 'name',
children: 'children',
}"
value-key="id"
check-strictly
:check-strictly-except-leaf="false"
:default-expand-all="true"
placeholder="请选择入院科室"
@change="handleChange"
@node-click="handleNodeClick"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="入院病区" prop="wardLocationId">
<el-select v-model="submitForm.wardLocationId">
<el-option
v-for="item in wardListOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
<template #empty>
<div>请先选择入院科室</div>
</template>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="患者病情">
<el-select v-model="submitForm.priorityEnum">
<el-option
v-for="item in priorityLevelOptionOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<!-- <el-col :span="6">
<el-form-item label="入院类型" prop="admitSourceCode">
<el-select v-model="submitForm.admitSourceCode">
<el-option
v-for="item in admit_source_code"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="入院方式" prop="inWayCode">
<el-select v-model="submitForm.inWayCode">
<el-option
v-for="item in in_way_code"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
-->
</el-row>
<el-row :gutter="8">
<el-col :span="6">
<el-form-item label="诊断类别" prop="medTypeCode">
<el-select
v-model="submitForm.medTypeCode"
placeholder="诊断"
clearable
filterable
@change="
(value) => {
submitForm.ybClassEnum = value;
}
"
>
<el-option
v-for="item in med_type"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入院诊断" prop="diagnosisDefinitionId">
<!-- <el-select
v-model="submitForm.diagnosisDefinitionId"
placeholder="诊断"
clearable
filterable
remote
:remote-method="getDiagnosisInfo"
style="width: 400px"
>
<el-option
v-for="item in diagnosisDefinitionList"
:key="item.id"
:label="item.name"
:value="item.id"
@click="handleDiagnosisChange(item)"
/>
</el-select> -->
<el-input v-model="props.mainDiagnosis.name" disabled style="width: 400px" />
<!-- 隐藏存储ID的字段 -->
<input type="hidden" v-model="submitForm.diagnosisDefinitionId" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submit"> </el-button>
<el-button @click="close"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import {watch} from 'vue';
import {getDiagnosisDefinitionList, getInit, getOrgList, handleHospitalization, wardList,} from './api.js';
const submitForm = reactive({
medTypeCode: '', // 从字典动态获取默认值
});
const props = defineProps({
open: {
type: Boolean,
default: false,
},
patientInfo: {
type: Object,
default: () => ({}),
},
encounterId: {
type: String,
default: '',
},
mainDiagnosis: { type: Object, default: null },
});
const emit = defineEmits(['close']);
const priorityLevelOptionOptions = ref(undefined);
const organization = ref([]);
const wardListOptions = ref([]);
const diagnosisDefinitionList = ref([]);
let diagnosisDefinitionId = '';
let diagnosisYbNo = '';
const { proxy } = getCurrentInstance();
const { med_type } = proxy.useDict('med_type');
// 监听诊断类别字典加载,默认选择第一项(仅当没有主诊断时)
watch(
med_type,
(newVal) => {
if (newVal && newVal.length > 0 && !submitForm.medTypeCode && !props.mainDiagnosis) {
submitForm.medTypeCode = newVal[0].value;
}
},
{ immediate: true }
);
const rules = reactive({
diagnosisDefinitionId: [
{
required: true,
message: '入院诊断未填写',
trigger: ['blur', 'change'],
},
],
medTypeCode: [
{
required: true,
message: '诊断类别未选择',
trigger: ['blur', 'change'],
},
],
inHospitalOrgId: [
{
required: true,
message: '入院科室未填写',
trigger: ['blur', 'change'],
},
],
});
function openDialog() {
console.log('hospitalizationDialog openDialog 被调用');
console.log('props.patientInfo:', props.patientInfo);
console.log('props.encounterId:', props.encounterId);
console.log('props.patientInfo.encounterId:', props.patientInfo?.encounterId);
console.log('orgId==========>', props.patientInfo.orgId);
getOrgList().then((res) => {
console.log('获取组织机构数据:', res);
// 确保数据结构正确
if (res && res.code === 200 && res.data && res.data.records && Array.isArray(res.data.records)) {
// 递归遍历树形结构,获取所有符合条件的节点
const flattenTree = (nodes) => {
let result = [];
nodes.forEach(node => {
// 检查当前节点是否符合条件 - 扩展筛选条件
if (node &&
node.typeEnum === 2 && // 科室类型
checkClassEnumValue(node.classEnum, 2) && // 住院类别(支持多选)
node.activeFlag !== 0) { // 活跃状态(非停用)
result.push(node);
}
// 递归处理子节点
if (node.children && Array.isArray(node.children)) {
result = result.concat(flattenTree(node.children));
}
});
return result;
};
// 从树形结构中提取所有符合条件的组织
organization.value = flattenTree(res.data.records);
console.log('筛选后的组织机构数据:', organization.value);
// 默认选中当前医生所在科室(即使不在住院科室列表中)
if (props.patientInfo?.orgId) {
const doctorOrgId = props.patientInfo.orgId;
const exists = organization.value.some((item) => item?.id === doctorOrgId);
if (exists) {
// 如果医生科室在列表中,直接选中
submitForm.inHospitalOrgId = doctorOrgId;
} else {
// 如果医生科室不在列表中(如门诊科室),临时添加到列表并选中
// 从原始数据中找到医生科室信息
const findOrgInTree = (nodes, orgId) => {
for (const node of nodes) {
if (node.id === orgId) return node;
if (node.children) {
const found = findOrgInTree(node.children, orgId);
if (found) return found;
}
}
return null;
};
const doctorOrg = findOrgInTree(res.data.records, doctorOrgId);
if (doctorOrg) {
organization.value.unshift(doctorOrg);
submitForm.inHospitalOrgId = doctorOrgId;
}
}
// 触发科室选择事件,加载对应病区
if (submitForm.inHospitalOrgId) {
handleNodeClick({ id: submitForm.inHospitalOrgId });
}
}
} else {
organization.value = [];
console.warn('获取组织机构数据为空或格式不正确:', res);
}
console.log('organization==========>', organization.value);
}).catch(error => {
console.error('获取组织机构数据失败:', error);
organization.value = [];
// 显示详细的错误信息
const errorMessage = error.message || error.msg || '获取组织机构数据失败,请稍后重试';
proxy.$modal.msgError(errorMessage);
});
// 获取初始化数据
getInit().then((response) => {
console.log(response, 'response');
if (response.data && response.data.priorityLevelOptionOptions) {
priorityLevelOptionOptions.value = response.data.priorityLevelOptionOptions; // 优先级
}
});
console.log(props.patientInfo, 'patientInfo');
getDiagnosisInfo(undefined);
console.log(props.mainDiagnosis, 'mainDiagnosis');
if (props.mainDiagnosis) {
submitForm.diagnosisDefinitionId = props.mainDiagnosis.definitionId;
diagnosisDefinitionId = props.mainDiagnosis.definitionId;
diagnosisYbNo = props.mainDiagnosis.ybNo || '';
submitForm.diagnosisDesc = props.mainDiagnosis.name || ''; // 设置诊断描述
diagnosisDefinitionList.value = [props.mainDiagnosis];
// 诊断类别优先使用主诊断的medTypeCode但要验证是否在字典选项中
const diagnosisMedTypeCode = props.mainDiagnosis.medTypeCode;
const medTypeExists = med_type.value && med_type.value.some(item => item.value === diagnosisMedTypeCode);
if (medTypeExists) {
submitForm.medTypeCode = diagnosisMedTypeCode;
} else if (med_type.value && med_type.value.length > 0) {
// 如果主诊断的medTypeCode不在字典中默认选择字典第一项
submitForm.medTypeCode = med_type.value[0].value;
}
} else if (med_type.value && med_type.value.length > 0) {
// 无主诊断时,默认选择字典第一项
submitForm.medTypeCode = med_type.value[0].value;
}
}
function getDiagnosisInfo(value) {
getDiagnosisDefinitionList({ pageSize: 500, pageNo: 1, searchKey: value }).then((res) => {
diagnosisDefinitionList.value = res.data.records;
});
}
function handleDiagnosisChange(item) {
diagnosisYbNo = item.ybNo;
diagnosisDefinitionId = item.id;
}
function handleNodeClick(orgInfo) {
// 确保传入正确的科室ID
if (orgInfo && orgInfo.id) {
wardList({ orgId: orgInfo.id }).then((res) => {
if (res && res.data) {
wardListOptions.value = res.data;
// 清空之前选择的病区
submitForm.wardLocationId = undefined;
} else {
wardListOptions.value = [];
submitForm.wardLocationId = undefined;
}
}).catch(error => {
console.error('获取病区列表失败:', error);
wardListOptions.value = [];
submitForm.wardLocationId = undefined;
// 显示详细的错误信息
const errorMessage = error.message || error.msg || '获取病区列表失败,请稍后重试';
proxy.$modal.msgError(errorMessage);
});
} else {
wardListOptions.value = [];
submitForm.wardLocationId = undefined;
}
}
function handleChange(value) {
if (!value) {
wardListOptions.value = [];
submitForm.wardLocationId = undefined;
} else {
// 当选择新科室时,清空病区选择
submitForm.wardLocationId = undefined;
}
}
function submit() {
console.log('hospitalizationDialog submit 被调用');
console.log('props.patientInfo:', props.patientInfo);
console.log('props.encounterId:', props.encounterId);
console.log('props.patientInfo.encounterId:', props.patientInfo?.encounterId);
proxy.$refs['registerRef'].validate((valid) => {
if (valid) {
// 验证必要字段
if (!props.patientInfo.patientId) {
console.log('患者信息不完整,缺少 patientId');
proxy.$modal.msgError('患者信息不完整,无法办理住院');
return;
}
if (!props.encounterId && !props.patientInfo.encounterId) {
console.log('就诊信息不完整,缺少 encounterId');
proxy.$modal.msgError('就诊信息不完整,无法办理住院');
return;
}
let saveData = {
...submitForm,
diagnosisYbNo: diagnosisYbNo,
diagnosisDefinitionId: diagnosisDefinitionId,
// 优先使用props.encounterId确保就诊ID正确传递
ambEncounterId: props.encounterId || props.patientInfo.encounterId,
patientId: props.patientInfo.patientId,
};
console.log('提交住院数据:', saveData);
// 显示加载状态
const loading = proxy.$modal.loading('正在办理住院...');
handleHospitalization(saveData).then((res) => {
console.log('住院办理API响应:', res);
if (res.code == 200) {
proxy.$modal.msgSuccess('办理成功');
close();
} else {
console.error('办理失败:', res.msg);
proxy.$modal.msgError(res.msg || '办理失败,请检查数据后重试');
}
}).catch(error => {
console.error('提交出错:', error);
// 构建详细的错误信息
let errorMsg = '办理住院过程中发生错误';
if (error.response) {
// 如果后端返回了具体错误信息,优先使用
if (error.response.data && error.response.data.message) {
errorMsg = error.response.data.message;
} else if (error.response.data) {
// 如果响应体中有其他可读信息
errorMsg = typeof error.response.data === 'string' ? error.response.data : `${errorMsg} (${error.response.status})`;
} else {
errorMsg = `${errorMsg} (${error.response.status}): ${error.response.statusText}`;
}
} else if (error.request) {
errorMsg = '网络请求失败,请检查网络连接';
} else {
errorMsg = error.message || errorMsg;
}
proxy.$modal.msgError(errorMsg);
}).finally(() => {
// 关闭加载状态
proxy.$modal.closeLoading();
});
} else {
console.log('表单验证失败');
}
});
}
function close() {
emit('close');
}
// 检查classEnum值是否包含指定值支持多选
function checkClassEnumValue(classEnum, targetValue) {
if (!classEnum) return false;
// 如果是字符串且包含逗号,说明是多选值
if (typeof classEnum === 'string' && classEnum.includes(',')) {
const values = classEnum.split(',').map(v => v.trim());
return values.some(v => v == targetValue);
}
// 单个值的情况
return classEnum == targetValue;
}
</script>
<style lang="scss" scoped>
.operate {
font-size: 16px;
background: rgba(37, 109, 149, 0.05);
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
border-radius: 4px 4px 0px 0px;
padding-left: 16px;
color: var(--hip-color-primary-light);
font-weight: bold;
margin: 10px 0;
}
.patInfo-value {
width: 100px;
}
</style>