Files
his/openhis-ui-vue3/src/views/inpatientNurse/components/patientList.vue

305 lines
7.7 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>
<div>
<el-input placeholder="住院号/姓名" v-model="searchKey" @keyup.enter="handleSearch">
<template #append>
<el-button icon="Search" @click="handleSearch" />
</template>
</el-input>
</div>
<el-tree
ref="treeRef"
:key="treeKey"
:load="loadNode"
lazy
show-checkbox
node-key="id"
default-expand-all
:props="{ label: 'name', children: 'children' }"
@node-click="handleNodeClick"
@check="handleCheckChange"
>
<template #default="{ node, data }">
<div class="custom-tree-node" v-if="node.level === 2">
<span>{{ data.bedName + ' / ' + node.label }}</span>
<span class="tree-node-actions">
{{ data.genderEnum_enumText + ' / ' + data.age }}
</span>
</div>
</template>
</el-tree>
</div>
</template>
<script setup>
import {getPatientList, getWardList} from './api';
import {updatePatientInfoList} from './store/patient';
import {defineExpose, inject, nextTick, ref} from 'vue';
const treeRef = ref(null);
const searchKey = ref('');
const treeKey = ref(0); // 用于强制重新渲染树组件
const wardList = ref([]); // 存储病区列表
const patientDataCache = ref(new Map()); // 缓存患者数据key为wardIdvalue为患者列表
const handleGetPrescription = inject('handleGetPrescription');
/**
* 加载树节点数据
* @param {Object} node - 树节点对象
* @param {Function} resolve - 解析函数,用于返回子节点数据
*/
function loadNode(node, resolve) {
// 根节点:加载所有病区
if (node.level === 0) {
loadWardList(resolve);
}
// 病区节点:加载该病区下的患者列表
else if (node.level === 1) {
const wardId = node.data.id;
loadPatientList(wardId, resolve);
}
// 其他层级返回空数组
else {
resolve([]);
}
}
/**
* 加载病区列表
* @param {Function} resolve - 解析函数
*/
function loadWardList(resolve) {
getWardList()
.then((res) => {
// 格式化病区数据
const wards = Array.isArray(res) ? res : res.data || [];
wardList.value = wards;
// 将病区数据转换为树节点格式
const wardNodes = wards.map((ward) => ({
id: ward.id,
name: ward.name || ward.wardName || '',
leaf: false, // 病区节点不是叶子节点
...ward,
}));
resolve(wardNodes);
})
.catch((error) => {
console.error('加载病区列表失败:', error);
resolve([]);
});
}
/**
* 加载指定病区的患者列表
* @param {String|Number} wardId - 病区ID
* @param {Function} resolve - 解析函数
*/
function loadPatientList(wardId, resolve) {
// 构建缓存键(包含搜索条件)
const cacheKey = `${wardId}_${searchKey.value || ''}`;
// 如果缓存中存在且搜索条件为空,直接使用缓存(搜索时需要重新加载)
if (!searchKey.value && patientDataCache.value.has(cacheKey)) {
const cachedPatients = patientDataCache.value.get(cacheKey);
resolve(cachedPatients);
return;
}
// 调用接口获取患者列表
getPatientList({
wardId: wardId,
searchKey: searchKey.value || '',
})
.then((res) => {
// 处理返回的患者数据
const records = res?.data?.records || [];
// 格式化患者数据
const patients = records.map((item) => ({
id: item.id || item.encounterId,
name: item.patientName || '',
leaf: true, // 患者节点是叶子节点
...item,
}));
// 缓存患者数据(仅在没有搜索条件时缓存)
if (!searchKey.value) {
patientDataCache.value.set(cacheKey, patients);
}
resolve(patients);
})
.catch((error) => {
console.error('加载患者列表失败:', error);
resolve([]);
});
}
/**
* 重新加载所有病区的患者列表
*/
function reloadAllPatients() {
if (!treeRef.value) return;
// 清除患者数据缓存
patientDataCache.value.clear();
nextTick(() => {
const rootNode = treeRef.value?.store?.root;
if (!rootNode?.childNodes) return;
// 遍历所有已展开的病区节点,重新加载患者列表
rootNode.childNodes.forEach((wardNode) => {
if (wardNode && wardNode.level === 1 && wardNode.key) {
reloadWardNodePatients(wardNode);
}
});
});
}
/**
* 重新加载指定病区节点的患者列表
* @param {Object} wardNode - 病区节点对象
*/
function reloadWardNodePatients(wardNode) {
if (!wardNode?.key || !treeRef.value) return;
const wardId = wardNode.data.id;
const cacheKey = `${wardId}_${searchKey.value || ''}`;
// 清除该病区的缓存
patientDataCache.value.delete(cacheKey);
// 清除旧的子节点
treeRef.value.updateKeyChildren(wardNode.key, []);
// 重置节点状态
wardNode.loaded = false;
wardNode.childNodes = [];
// 重新加载患者列表
loadPatientList(wardId, (children) => {
treeRef.value.updateKeyChildren(wardNode.key, children);
});
}
/**
* 重新加载指定病区的患者列表
* @param {String|Number} wardId - 病区ID
*/
function reloadWardPatients(wardId) {
if (!treeRef.value) return;
nextTick(() => {
const rootNode = treeRef.value?.store?.root;
if (!rootNode?.childNodes) return;
// 查找对应的病区节点
const wardNode = rootNode.childNodes.find((node) => node.data.id === wardId);
if (wardNode) {
reloadWardNodePatients(wardNode);
}
});
}
/**
* 手动触发加载节点
* @param {Object} node - 节点对象如果为null则重新加载整个树
*/
function manualLoadNode(node = null) {
if (!node) {
// 重新加载整个树
treeKey.value += 1;
patientDataCache.value.clear();
} else if (node.key && treeRef.value) {
// 重新加载指定节点
if (node.level === 1) {
// 病区节点:重新加载患者列表
reloadWardNodePatients(node);
} else if (node.level === 0) {
// 根节点:重新加载病区列表
loadWardList((wards) => {
treeRef.value.updateKeyChildren(node.key, wards);
});
}
}
}
/**
* 获取所有选中的叶子节点(患者节点)
* @returns {Array} 患者节点数组
*/
function getCheckedLeafNodes() {
if (!treeRef.value) return [];
// 获取所有选中的节点数据
const checkedNodes = treeRef.value.getCheckedNodes() || [];
// 只返回叶子节点(患者节点)
return checkedNodes.filter((node) => node.leaf === true);
}
/**
* 处理节点选中状态变化
* @param {Object} data - 节点数据
* @param {Object} checked - 选中状态对象
*/
function handleCheckChange(data, checked) {
const checkedPatients = getCheckedLeafNodes();
updatePatientInfoList(checkedPatients);
// 调用父组件的方法获取处方列表
if (handleGetPrescription && typeof handleGetPrescription === 'function') {
handleGetPrescription();
}
}
/**
* 处理节点点击事件
* @param {Object} data - 节点数据
* @param {Object} node - 节点对象
*/
function handleNodeClick(data, node) {
// 节点点击处理逻辑(可根据需要添加)
}
/**
* 处理搜索
*/
function handleSearch() {
// 清除缓存(搜索时需要重新加载)
patientDataCache.value.clear();
// 重新加载所有已展开病区的患者列表
reloadAllPatients();
}
// 暴露方法供外部调用
defineExpose({
manualLoadNode,
reloadAllPatients,
reloadWardPatients,
handleSearch,
});
</script>
<style scoped lang="scss">
.custom-tree-node {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.tree-node-actions {
display: flex;
align-items: center;
}
:deep(.el-tree-node__content) {
height: 35px;
}
</style>