docs(release-notes): 添加住院护士站划价功能说明和发版记录 - 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程 - 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑 - 添加完整的发版内容记录,涵盖新增菜单功能和各模块优化点 - 记录了住院相关功能的新增和门诊业务流程的修复 ```
305 lines
7.7 KiB
Vue
305 lines
7.7 KiB
Vue
<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 { ref, nextTick, inject, defineExpose } from 'vue';
|
||
|
||
const treeRef = ref(null);
|
||
const searchKey = ref('');
|
||
const treeKey = ref(0); // 用于强制重新渲染树组件
|
||
const wardList = ref([]); // 存储病区列表
|
||
const patientDataCache = ref(new Map()); // 缓存患者数据:key为wardId,value为患者列表
|
||
|
||
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> |