fix(core): 修复审计字段缺失和组件状态管理问题
- 在Account、ChargeItem、EncounterParticipant和Encounter服务中添加审计字段验证 - 确保tenantId、createBy和createTime字段在插入数据库前正确设置 - 修复EMR模块中删除模板API的导出问题 - 更新患者信息状态管理,统一使用localPatientInfo替换patientInfo - 在EMR组件中实现防抖机制优化历史记录刷新性能 - 修复病历模板切换时的表单数据重置逻辑 - 在首页统计组件中使用markRaw包装图标组件 - 为住院记录模板添加默认表单数据结构 - 修复SVG患者图标路径错误
This commit is contained in:
@@ -348,7 +348,7 @@ import {
|
||||
} from '../api';
|
||||
import adviceBaseList from '../adviceBaseList';
|
||||
import {calculateQuantityByDays} from '@/utils/his';
|
||||
import {patientInfo} from '../../store/patient.js';
|
||||
import {localPatientInfo as patientInfo} from '../../store/localPatient.js';
|
||||
import OrderGroupDrawer from '@/views/doctorstation/components/prescription/orderGroupDrawer.vue';
|
||||
import PrescriptionHistory from '@/views/doctorstation/components/prescription/prescriptionHistory.vue';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
@@ -72,3 +72,12 @@ export function updateTemplate(data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 删除模板
|
||||
export function deleteTemplate(ids) {
|
||||
return request({
|
||||
url: '/document/template/delete',
|
||||
method: 'delete',
|
||||
data: ids,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import {defineEmits, nextTick, ref, unref} from 'vue';
|
||||
import {deleteRecord, getRecordByEncounterIdList} from '../api';
|
||||
import {ElMessage} from 'element-plus';
|
||||
import {Delete} from '@element-plus/icons-vue';
|
||||
import {patientInfo} from '../../store/patient.js';
|
||||
import {localPatientInfo as patientInfo} from '../../store/localPatient.js';
|
||||
|
||||
const emits = defineEmits(['historyClick']);
|
||||
const props = defineProps({
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {defineEmits, ref, unref} from 'vue';
|
||||
import {getListByDefinitionId} from '../api';
|
||||
import {defineEmits, ref, unref, watch} from 'vue';
|
||||
import {getListByDefinitionId, deleteTemplate} from '../api';
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import {Edit} from '@element-plus/icons-vue';
|
||||
|
||||
@@ -46,16 +46,33 @@ const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
};
|
||||
|
||||
// 缓存已加载的模板数据
|
||||
const templateCache = new Map();
|
||||
const queryParams = ref({
|
||||
searchKey: '',
|
||||
isPage: 0,
|
||||
});
|
||||
const templateData = ref([]);
|
||||
|
||||
// 防抖定时器
|
||||
let debounceTimer = null;
|
||||
|
||||
const queryList = async () => {
|
||||
try {
|
||||
if (unref(definitionId) && unref(definitionId) !== '') {
|
||||
const res = await getListByDefinitionId(unref(definitionId));
|
||||
templateData.value = res.data || [];
|
||||
const id = unref(definitionId);
|
||||
if (id && id !== '') {
|
||||
// 检查缓存中是否存在数据
|
||||
if (templateCache.has(id)) {
|
||||
templateData.value = templateCache.get(id);
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await getListByDefinitionId(id);
|
||||
const data = res.data || [];
|
||||
// 将数据存入缓存
|
||||
templateCache.set(id, data);
|
||||
templateData.value = data;
|
||||
} else {
|
||||
templateData.value = [];
|
||||
}
|
||||
@@ -64,6 +81,23 @@ const queryList = async () => {
|
||||
templateData.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 防抖版本的查询函数
|
||||
const debouncedQueryList = async () => {
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(async () => {
|
||||
await queryList();
|
||||
}, 300); // 300ms 防抖延迟
|
||||
};
|
||||
|
||||
// 监听 definitionId 变化,使用防抖
|
||||
watch(definitionId, () => {
|
||||
debouncedQueryList();
|
||||
}, { immediate: true });
|
||||
|
||||
const handleNodeClick = (data) => {
|
||||
emits('templateClick', data);
|
||||
};
|
||||
@@ -81,6 +115,8 @@ const handleDelete = async (item) => {
|
||||
}).then(async () => {
|
||||
await deleteTemplate(item.id);
|
||||
ElMessage.success('删除成功');
|
||||
// 清除缓存中的数据,强制重新加载
|
||||
templateCache.delete(unref(definitionId));
|
||||
queryList();
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
@@ -115,7 +115,7 @@ import {nextTick, onMounted, reactive, ref, watch} from 'vue';
|
||||
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||
import {getTreeList} from '@/views/basicmanage/caseTemplates/api';
|
||||
import {addTemplate, getRecordByEncounterIdList, saveOrUpdateRecord} from './api';
|
||||
import {patientInfo} from '../store/patient.js';
|
||||
import {localPatientInfo as patientInfo} from '../store/localPatient.js';
|
||||
import NursingStatus from '@/views/inpatientDoctor/home/components/applicationShow/nursingStatus.vue';
|
||||
import dayjs from 'dayjs';
|
||||
// 打印工具
|
||||
@@ -148,9 +148,18 @@ const emrComponentRef = ref(null);
|
||||
const quicklyactiveName = ref('history');
|
||||
const leftShow = ref(true);
|
||||
const rightShow = ref(true);
|
||||
// 使用防抖处理历史记录和模板列表的刷新
|
||||
let listRefreshDebounceTimer = null;
|
||||
watch(patientInfo, () => {
|
||||
historyRef.value?.queryList();
|
||||
templateRef.value?.queryList();
|
||||
if (listRefreshDebounceTimer) {
|
||||
clearTimeout(listRefreshDebounceTimer);
|
||||
}
|
||||
|
||||
listRefreshDebounceTimer = setTimeout(() => {
|
||||
historyRef.value?.queryList();
|
||||
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||
// templateRef.value?.queryList();
|
||||
}, 150); // 稍微延后刷新,避免频繁更新
|
||||
});
|
||||
const templateTree = ref(null);
|
||||
|
||||
@@ -185,8 +194,29 @@ const handleNodeClick = (data, node) => {
|
||||
if (node.isLeaf) {
|
||||
// 存储当前节点数据
|
||||
currentSelectTemplate.value = data.document;
|
||||
currentComponent.value = currentSelectTemplate.value.vueRouter || '';
|
||||
// currentComponent.value = data.document.vueRouter || '';
|
||||
|
||||
// 在切换组件前先重置表单数据,避免显示之前的数据
|
||||
editForm.value = {
|
||||
id: '',
|
||||
definitionId: '',
|
||||
definitionBusNo: '',
|
||||
contentJson: '',
|
||||
statusEnum: 1,
|
||||
organizationId: 0,
|
||||
encounterId: '',
|
||||
patientId: '',
|
||||
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
createBy: '',
|
||||
source: '',
|
||||
};
|
||||
|
||||
// 先清空当前组件,再设置新组件,确保组件完全重新渲染
|
||||
currentComponent.value = '';
|
||||
|
||||
// 使用 nextTick 确保 DOM 更新后再设置新组件
|
||||
nextTick(() => {
|
||||
currentComponent.value = currentSelectTemplate.value.vueRouter || '';
|
||||
});
|
||||
} else {
|
||||
currentSelectTemplate.value = {
|
||||
id: '',
|
||||
@@ -198,7 +228,8 @@ const handleNodeClick = (data, node) => {
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
historyRef.value?.queryList();
|
||||
templateRef.value?.queryList();
|
||||
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||
// templateRef.value?.queryList();
|
||||
|
||||
// 选择任何病历模板后,都加载该病历类型的最新历史记录
|
||||
if (node.isLeaf && patientInfo.value && patientInfo.value.patientId) {
|
||||
@@ -270,7 +301,8 @@ const handleSubmitOk = async (data) => {
|
||||
|
||||
// 刷新历史记录列表
|
||||
historyRef.value?.queryList();
|
||||
templateRef.value?.queryList();
|
||||
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||
// templateRef.value?.queryList();
|
||||
|
||||
// 等待历史记录列表更新后,重新加载最新病历并更新选中状态
|
||||
setTimeout(() => {
|
||||
@@ -429,7 +461,8 @@ const print = async () => {
|
||||
const refresh = () => {
|
||||
queryTemplateTree();
|
||||
historyRef.value?.queryList();
|
||||
templateRef.value?.queryList();
|
||||
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||
// templateRef.value?.queryList();
|
||||
};
|
||||
|
||||
const deleteEmr = async () => {
|
||||
@@ -522,7 +555,7 @@ const selectOutpatientMedicalRecordTemplate = async () => {
|
||||
|
||||
// 加载最新的病历数据并回显
|
||||
const loadLatestMedicalRecord = async () => {
|
||||
if (!patientInfo.value.encounterId || !currentSelectTemplate.value.id) return;
|
||||
if (!patientInfo.value?.encounterId || !currentSelectTemplate.value.id) return;
|
||||
editForm.value.id = '';
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -546,7 +579,17 @@ const loadLatestMedicalRecord = async () => {
|
||||
editForm.value = latestRecord;
|
||||
nextTick(() => {
|
||||
if (emrComponentRef.value && latestRecord.contentJson) {
|
||||
emrComponentRef.value.setFormData(JSON.parse(latestRecord.contentJson));
|
||||
try {
|
||||
const parsedData = JSON.parse(latestRecord.contentJson);
|
||||
emrComponentRef.value.setFormData(parsedData);
|
||||
} catch (parseError) {
|
||||
console.error('解析病历数据失败:', parseError);
|
||||
// 解析失败时仍然尝试设置空数据以清空之前的残留数据
|
||||
emrComponentRef.value.setFormData({});
|
||||
}
|
||||
} else {
|
||||
// 如果没有内容数据,也要清空组件中的数据
|
||||
emrComponentRef.value.setFormData({});
|
||||
}
|
||||
|
||||
// 通知History组件更新选中状态
|
||||
@@ -557,16 +600,52 @@ const loadLatestMedicalRecord = async () => {
|
||||
} else {
|
||||
// 清空选中状态
|
||||
selectedHistoryRecordId.value = '';
|
||||
// 病案首页切换晴空逻辑
|
||||
emrComponentRef.value.setFormData?.({});
|
||||
// 当没有历史记录时,也要清空当前表单数据,避免显示之前患者的数据
|
||||
editForm.value = {
|
||||
id: '',
|
||||
definitionId: '',
|
||||
definitionBusNo: '',
|
||||
contentJson: '',
|
||||
statusEnum: 1,
|
||||
organizationId: 0,
|
||||
encounterId: '',
|
||||
patientId: '',
|
||||
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
createBy: '',
|
||||
source: '',
|
||||
};
|
||||
|
||||
nextTick(() => {
|
||||
if (emrComponentRef.value) {
|
||||
emrComponentRef.value.setFormData({});
|
||||
}
|
||||
});
|
||||
loading.value = false;
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('加载最新病历数据失败=====>', error);
|
||||
// 出错时也清空选中状态
|
||||
selectedHistoryRecordId.value = '';
|
||||
// 病案首页切换晴空逻辑
|
||||
emrComponentRef.value.setFormData?.({});
|
||||
// 出错时也要清空表单数据,避免显示之前患者的数据
|
||||
editForm.value = {
|
||||
id: '',
|
||||
definitionId: '',
|
||||
definitionBusNo: '',
|
||||
contentJson: '',
|
||||
statusEnum: 1,
|
||||
organizationId: 0,
|
||||
encounterId: '',
|
||||
patientId: '',
|
||||
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
createBy: '',
|
||||
source: '',
|
||||
};
|
||||
|
||||
nextTick(() => {
|
||||
if (emrComponentRef.value) {
|
||||
emrComponentRef.value.setFormData({});
|
||||
}
|
||||
});
|
||||
loading.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
@@ -672,6 +751,7 @@ const templateEditSubmitOk = async () => {
|
||||
ElMessage.success('模板新增成功');
|
||||
// 刷新模板列表
|
||||
if (templateRef.value && typeof templateRef.value.queryList === 'function') {
|
||||
// 在模板操作后,需要清除缓存并重新加载
|
||||
templateRef.value.queryList();
|
||||
}
|
||||
// 关闭模板编辑弹窗
|
||||
@@ -703,7 +783,8 @@ const templateEditSubmitOk = async () => {
|
||||
} finally {
|
||||
// 无论成功失败都刷新列表
|
||||
historyRef.value?.queryList();
|
||||
templateRef.value?.queryList();
|
||||
// 模板查询已经在模板组件内部通过防抖和缓存优化,这里不再重复调用
|
||||
// templateRef.value?.queryList();
|
||||
}
|
||||
};
|
||||
// onBeforeMount(() => {});
|
||||
@@ -726,6 +807,29 @@ watch(
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 如果没有患者信息,也要重置组件和表单数据
|
||||
currentComponent.value = '';
|
||||
editForm.value = {
|
||||
id: '',
|
||||
definitionId: '',
|
||||
definitionBusNo: '',
|
||||
contentJson: '',
|
||||
statusEnum: 1,
|
||||
organizationId: 0,
|
||||
encounterId: '',
|
||||
patientId: '',
|
||||
recordTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
||||
createBy: '',
|
||||
source: '',
|
||||
};
|
||||
|
||||
// 如果有动态组件实例,也需要重置其表单数据
|
||||
nextTick(() => {
|
||||
if (emrComponentRef.value && emrComponentRef.value.setFormData) {
|
||||
emrComponentRef.value.setFormData({});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
|
||||
@@ -46,6 +46,7 @@ import {computed, onBeforeMount, onMounted, provide, reactive, ref, watch,} from
|
||||
import Emr from './emr/index.vue';
|
||||
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
|
||||
import PatientList from '@/components/PatientList/patient-list.vue';
|
||||
import {localPatientInfo, updateLocalPatientInfo} from './store/localPatient';
|
||||
import {patientInfo, updatePatientInfo} from './store/patient';
|
||||
import {getPatientList} from './components/api';
|
||||
import {
|
||||
@@ -121,21 +122,40 @@ watch(
|
||||
) {
|
||||
const firstPatient = newData[0];
|
||||
if (firstPatient?.encounterId) {
|
||||
handleItemClick(firstPatient);
|
||||
isFirstLoad.value = false;
|
||||
// 使用防抖处理默认选择
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
handleItemClick(firstPatient);
|
||||
isFirstLoad.value = false;
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 防抖函数,防止快速点击导致状态冲突
|
||||
let debounceTimer = null;
|
||||
const handleItemClick = (node) => {
|
||||
cardId.value = node.encounterId;
|
||||
updatePatientInfo(node);
|
||||
// 清除之前的计时器
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
|
||||
diagnosisRef.value?.getList();
|
||||
adviceRef.value?.getListInfo();
|
||||
adviceRef.value?.getDiagnosisInfo();
|
||||
// 设置新的计时器
|
||||
debounceTimer = setTimeout(() => {
|
||||
cardId.value = node.encounterId;
|
||||
// 同时更新本地和全局状态,确保模块内组件和跨模块组件都能正确响应
|
||||
updatePatientInfo(node);
|
||||
updateLocalPatientInfo(node);
|
||||
|
||||
diagnosisRef.value?.getList();
|
||||
adviceRef.value?.getListInfo();
|
||||
adviceRef.value?.getDiagnosisInfo();
|
||||
}, 100); // 100ms 防抖延迟
|
||||
};
|
||||
|
||||
const handleSearch = (keyword) => {
|
||||
|
||||
Reference in New Issue
Block a user