Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -42,7 +42,6 @@ import {defineEmits, ref, unref} from 'vue';
|
||||
import {deleteRecord, getRecordByEncounterIdList} from '../api';
|
||||
import {ElMessage} from 'element-plus';
|
||||
import {patientInfo} from '../../store/patient.js';
|
||||
import apiRequestManager from '@/utils/apiRequestManager.js';
|
||||
|
||||
const emits = defineEmits(['historyClick']);
|
||||
const props = defineProps({
|
||||
@@ -68,30 +67,15 @@ const queryParams = ref({
|
||||
isPage: 0,
|
||||
});
|
||||
const historyData = ref([]);
|
||||
// 防止重复加载的标志
|
||||
let isLoadingHistory = false;
|
||||
|
||||
const queryList = async () => {
|
||||
// 防止重复加载
|
||||
if (isLoadingHistory) {
|
||||
console.log('History data is already loading, skipping duplicate call');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoadingHistory = true;
|
||||
|
||||
try {
|
||||
if (patientInfo.value.encounterId && unref(definitionId) && unref(definitionId) !== '') {
|
||||
const res = await apiRequestManager.execute(
|
||||
getRecordByEncounterIdList,
|
||||
'/document/record/getRecordByEncounterIdList',
|
||||
{
|
||||
isPage: 0, // 确保参数一致,便于去重
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: patientInfo.value.patientId,
|
||||
definitionId: unref(definitionId),
|
||||
}
|
||||
);
|
||||
const res = await getRecordByEncounterIdList({
|
||||
...queryParams.value,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: patientInfo.value.patientId,
|
||||
definitionId: unref(definitionId),
|
||||
});
|
||||
historyData.value = res.data || [];
|
||||
} else {
|
||||
historyData.value = [];
|
||||
@@ -99,8 +83,6 @@ const queryList = async () => {
|
||||
} catch (error) {
|
||||
// ElMessage.error(' 获取模板树失败 ');
|
||||
historyData.value = [];
|
||||
} finally {
|
||||
isLoadingHistory = false; // 重置加载标志
|
||||
}
|
||||
};
|
||||
const handleNodeClick = (data) => {
|
||||
|
||||
@@ -103,7 +103,6 @@ import dayjs from 'dayjs';
|
||||
// 打印工具
|
||||
import {PRINT_TEMPLATE, simplePrint} from '@/utils/printUtils.js';
|
||||
import {getEncounterDiagnosis} from '../api';
|
||||
import apiRequestManager from '@/utils/apiRequestManager.js';
|
||||
import History from './components/history';
|
||||
import Template from './components/template';
|
||||
import TemplateEdit from './components/templateEdit.vue';
|
||||
@@ -206,7 +205,7 @@ const handleNodeClick = (data, node) => {
|
||||
|
||||
// 选择任何病历模板后,都加载该病历类型的最新历史记录
|
||||
if (node.isLeaf && props.patientInfo && props.patientInfo.patientId) {
|
||||
debouncedLoadLatestMedicalRecord();
|
||||
loadLatestMedicalRecord();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
@@ -280,7 +279,7 @@ const handleSubmitOk = async (data) => {
|
||||
|
||||
// 等待历史记录列表更新后,重新加载最新病历并更新选中状态
|
||||
setTimeout(() => {
|
||||
debouncedLoadLatestMedicalRecord();
|
||||
loadLatestMedicalRecord();
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
ElMessage.error('提交失败');
|
||||
@@ -411,7 +410,7 @@ const selectOutpatientMedicalRecordTemplate = async () => {
|
||||
// 等待模板加载完成,然后获取并回显最新病历数据
|
||||
setTimeout(() => {
|
||||
historyRef.value?.queryList();
|
||||
debouncedLoadLatestMedicalRecord();
|
||||
loadLatestMedicalRecord();
|
||||
}, 500);
|
||||
});
|
||||
} else {
|
||||
@@ -422,36 +421,19 @@ const selectOutpatientMedicalRecordTemplate = async () => {
|
||||
// 当前选中的历史病历ID,用于在History组件中高亮显示
|
||||
const selectedHistoryRecordId = ref('');
|
||||
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
// 防止重复加载的标志
|
||||
let isLoadingLatestRecord = false;
|
||||
|
||||
// 加载最新的病历数据并回显
|
||||
const loadLatestMedicalRecord = async () => {
|
||||
if (!patientInfo.value.encounterId || !currentSelectTemplate.value.id) return;
|
||||
|
||||
// 防止重复加载
|
||||
if (isLoadingLatestRecord) {
|
||||
console.log('Latest medical record is already loading, skipping duplicate call');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoadingLatestRecord = true;
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// 获取患者的历史病历记录
|
||||
const res = await apiRequestManager.execute(
|
||||
getRecordByEncounterIdList,
|
||||
'/document/record/getRecordByEncounterIdList',
|
||||
{
|
||||
isPage: 0,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: patientInfo.value.patientId,
|
||||
definitionId: currentSelectTemplate.value.id,
|
||||
}
|
||||
);
|
||||
const res = await getRecordByEncounterIdList({
|
||||
isPage: 0,
|
||||
encounterId: patientInfo.value.encounterId,
|
||||
patientId: patientInfo.value.patientId,
|
||||
definitionId: currentSelectTemplate.value.id,
|
||||
});
|
||||
|
||||
const historyRecords = res.data || [];
|
||||
if (historyRecords.length > 0) {
|
||||
@@ -537,12 +519,8 @@ const loadLatestMedicalRecord = async () => {
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
isLoadingLatestRecord = false; // 重置加载标志
|
||||
}
|
||||
};
|
||||
|
||||
// 防抖版本的加载最新病历数据函数
|
||||
const debouncedLoadLatestMedicalRecord = debounce(loadLatestMedicalRecord, 300);
|
||||
const templateRef = ref(null);
|
||||
|
||||
const handleTemplateClick = (data) => {
|
||||
@@ -772,7 +750,7 @@ const selectDefaultTemplate = () => {
|
||||
|
||||
// 直接加载最新病历数据,不再使用额外的setTimeout延迟
|
||||
// 因为handleNodeClick中已经有nextTick和setTimeout处理组件渲染
|
||||
debouncedLoadLatestMedicalRecord();
|
||||
loadLatestMedicalRecord();
|
||||
});
|
||||
} else {
|
||||
console.log('未找到门诊病历模板');
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-button type="text" size="small" @click="handlePrint(scope.row)">打印</el-button>
|
||||
<el-button type="text" size="small" style="color: #f56c6c" @click="handleDelete(scope.row)">删除</el-button>
|
||||
<el-button link size="small" @click="handlePrint(scope.row)">打印</el-button>
|
||||
<el-button link size="small" style="color: #f56c6c" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -379,7 +379,7 @@
|
||||
<!-- 标题栏 -->
|
||||
<div class="selected-header" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #eee;">
|
||||
<span style="font-weight: bold; color: #1a2b6d">已选择</span>
|
||||
<el-button type="text" @click="clearAllSelected" style="color: #f56c6c">清空</el-button>
|
||||
<el-button link @click="clearAllSelected" style="color: #f56c6c">清空</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 已选项目列表 -->
|
||||
@@ -393,7 +393,7 @@
|
||||
<span class="item-itemName">{{ item.itemName }}</span>
|
||||
<span class="item-price">¥{{ item.itemPrice }}</span>
|
||||
<el-button
|
||||
type="text"
|
||||
link
|
||||
size="small"
|
||||
style="color: #f56c6c; margin-left: auto"
|
||||
@click="removeInspectionItem(item)"
|
||||
|
||||
@@ -268,14 +268,15 @@ const validatePhraseName = (phraseName, excludeId = null) => {
|
||||
// 所有数据(用于客户端分页处理)
|
||||
const allData = ref([])
|
||||
|
||||
// 获取医生常用语列表数据
|
||||
// 获取医生常用语列表数据
|
||||
const fetchDoctorPhraseList = async () => {
|
||||
try {
|
||||
const response = await getDoctorPhraseList()
|
||||
// 处理后端返回的数据结构:data.data
|
||||
if (response.code === 200 && response.data && response.data.data) {
|
||||
// 【关键修改】去掉 response.data.data,直接取 response.data
|
||||
if (response.code === 200 && response.data) {
|
||||
// 按照sortNo由小到大排序,保证列表顺序正确
|
||||
allData.value = response.data.data.sort((a, b) => a.sortNo - b.sortNo)
|
||||
allData.value = response.data.sort((a, b) => a.sortNo - b.sortNo)
|
||||
total.value = allData.value.length
|
||||
// 执行客户端分页逻辑
|
||||
applyPagination()
|
||||
@@ -285,7 +286,7 @@ const fetchDoctorPhraseList = async () => {
|
||||
total.value = 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error) // 增加控制台日志便于调试
|
||||
console.error('获取列表失败:', error)
|
||||
ElMessage.error('获取数据失败: 网络请求错误')
|
||||
allData.value = []
|
||||
total.value = 0
|
||||
@@ -322,19 +323,18 @@ const handleCurrentChange = (val) => {
|
||||
applyPagination()
|
||||
}
|
||||
|
||||
// 搜索功能核心方法
|
||||
// 搜索功能核心方法
|
||||
const handleSearch = async () => {
|
||||
try {
|
||||
// searchScope可能是null(未选择)、1=个人,2=科室,3=全院
|
||||
const phraseType = searchScope.value === null ? undefined : searchScope.value
|
||||
// 调用搜索接口:phraseName, phraseType
|
||||
const response = await searchDoctorPhraseList(searchKeyword.value, phraseType)
|
||||
if (response.code === 200 && response.data && response.data.data) {
|
||||
// 按照sortNo由小到大排序
|
||||
allData.value = response.data.data.sort((a, b) => a.sortNo - b.sortNo)
|
||||
// 【关键修改】去掉 response.data.data,直接取 response.data
|
||||
if (response.code === 200 && response.data) {
|
||||
allData.value = response.data.sort((a, b) => a.sortNo - b.sortNo)
|
||||
total.value = allData.value.length
|
||||
currentPage.value = 1 // 搜索后重置到第一页
|
||||
applyPagination() // 应用分页
|
||||
currentPage.value = 1
|
||||
applyPagination()
|
||||
} else {
|
||||
ElMessage.error('搜索失败: ' + (response.msg || '未知错误'))
|
||||
allData.value = []
|
||||
@@ -349,20 +349,30 @@ const handleSearch = async () => {
|
||||
}
|
||||
|
||||
// 打开新增模态框方法
|
||||
// index.vue
|
||||
|
||||
const showAddDialog = () => {
|
||||
// 重置表单数据
|
||||
// 1. 算出当前最大的排序号
|
||||
// 如果列表是空的,就从 1 开始;如果不空,取第一条(因为我们排过序了)或遍历找最大值
|
||||
let maxSortNo = 0
|
||||
if (allData.value && allData.value.length > 0) {
|
||||
// 既然 allData 已经按 sortNo 排序了,那最后一个就是最大的?
|
||||
// 或者保险起见,用 Math.max 算一下
|
||||
maxSortNo = Math.max(...allData.value.map(item => item.sortNo || 0))
|
||||
}
|
||||
|
||||
// 2. 重置表单,并将排序号设为 最大值 + 1
|
||||
addForm.value = {
|
||||
phraseName: '',
|
||||
phraseContent: '',
|
||||
sortNo: 1,
|
||||
sortNo: maxSortNo + 1, // <--- 这样每次打开就是 2, 3, 4...
|
||||
phraseType: 1,
|
||||
phraseCategory: ''
|
||||
}
|
||||
// 重置表单验证状态
|
||||
|
||||
if (addFormRef.value) {
|
||||
addFormRef.value.clearValidate()
|
||||
}
|
||||
// 打开模态框
|
||||
addDialogVisible.value = true
|
||||
}
|
||||
|
||||
@@ -434,7 +444,6 @@ const handleDelete = async (row) => {
|
||||
// 用户取消删除时不提示错误
|
||||
if (error !== 'cancel') {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除操作失败: 网络异常或权限不足')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,39 +464,41 @@ const showEditDialog = (row) => {
|
||||
}
|
||||
|
||||
// 编辑表单提交保存方法
|
||||
// 修改 index.vue 中的 handleEditSave 方法
|
||||
const handleEditSave = async () => {
|
||||
try {
|
||||
// 先执行表单验证
|
||||
// 1. 表单校验
|
||||
const validateResult = await editFormRef.value.validate()
|
||||
if (!validateResult) return
|
||||
|
||||
// 名称唯一性校验(排除当前编辑的这条记录ID)
|
||||
// 2. 名称唯一性校验
|
||||
const nameValidation = validatePhraseName(editForm.value.phraseName, editForm.value.id)
|
||||
if (!nameValidation.valid) {
|
||||
ElMessage.error(nameValidation.message)
|
||||
return
|
||||
}
|
||||
|
||||
// 准备更新数据,修复时间格式为ISO字符串,适配后端LocalDateTime
|
||||
// 3. 准备数据
|
||||
const updateData = {
|
||||
...editForm.value,
|
||||
enableFlag: 1,
|
||||
updateTime: new Date().toISOString() // 前端临时赋值,后端最终以自己的为准
|
||||
updateTime: new Date().toISOString()
|
||||
}
|
||||
|
||||
// 调用更新接口
|
||||
// 4. 调用接口
|
||||
const response = await updateDoctorPhrase(updateData)
|
||||
|
||||
// 【核心修改】直接判断 code === 200 即可
|
||||
// 因为后端现在失败会返回 R.fail (code!=200),所以只要是 200 就是成功
|
||||
if (response.code === 200) {
|
||||
ElMessage.success('更新成功')
|
||||
ElMessage.success(response.msg || '更新成功') // 优先显示后端返回的消息
|
||||
editDialogVisible.value = false
|
||||
// 重新拉取数据,保证列表数据最新
|
||||
fetchDoctorPhraseList()
|
||||
} else {
|
||||
ElMessage.error('更新失败: ' + (response.msg || '未知错误'))
|
||||
ElMessage.error(response.msg || '更新失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新失败:', error)
|
||||
ElMessage.error('更新操作失败: 网络请求错误')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
{{ userStore.nickName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="" width="300">
|
||||
<el-radio-group v-model="firstEnum">
|
||||
<el-radio :label="1">初诊</el-radio>
|
||||
<el-radio :label="2">复诊</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button type="primary" plain @click.stop="handleFinish(patientInfo.encounterId)">
|
||||
完诊
|
||||
</el-button>
|
||||
@@ -209,7 +213,6 @@ import useUserStore from '@/store/modules/user';
|
||||
import { nextTick } from 'vue';
|
||||
import { updatePatientInfo } from './components/store/patient.js';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
// // 监听路由离开事件
|
||||
// onBeforeRouteLeave((to, from, next) => {
|
||||
@@ -276,6 +279,7 @@ const loading = ref(false);
|
||||
const { proxy } = getCurrentInstance();
|
||||
const visitType = ref('');
|
||||
const firstVisitDate = ref('');
|
||||
const firstEnum = ref(1); // 初复诊标识:1=初诊,2=复诊
|
||||
const disabled = computed(() => {
|
||||
// 只有在有患者信息但某些条件不满足时才启用覆盖层
|
||||
// 当前逻辑保持不变,但我们将在按钮级别处理禁用状态
|
||||
@@ -488,8 +492,7 @@ function handleOpen() {
|
||||
patientDrawerRef.value.refreshList();
|
||||
}
|
||||
|
||||
// 原始的handleCardClick函数
|
||||
function handleCardClickOriginal(item, index) {
|
||||
function handleCardClick(item, index) {
|
||||
console.log('handleCardClick 被调用');
|
||||
console.log('点击的患者项目:', item);
|
||||
console.log('患者项目中的encounterId:', item.encounterId);
|
||||
@@ -506,6 +509,15 @@ function handleCardClickOriginal(item, index) {
|
||||
console.log('patientInfo.value 设置为:', patientInfo.value);
|
||||
console.log('patientInfo.value.encounterId:', patientInfo.value?.encounterId);
|
||||
|
||||
// 根据患者信息设置初复诊标识
|
||||
const backendValue = item.firstEnum ?? item.first_enum;
|
||||
|
||||
if (backendValue !== undefined && backendValue !== null) {
|
||||
firstEnum.value = Number(backendValue); // 确保是数字类型
|
||||
} else {
|
||||
firstEnum.value = 1;
|
||||
}
|
||||
|
||||
// 确保患者信息包含必要的字段
|
||||
if (!patientInfo.value.encounterId) {
|
||||
console.error('患者信息缺少encounterId字段:', patientInfo.value);
|
||||
@@ -546,9 +558,6 @@ function handleCardClickOriginal(item, index) {
|
||||
});
|
||||
}
|
||||
|
||||
// 使用防抖的handleCardClick函数,防止短时间内多次点击
|
||||
const handleCardClick = debounce(handleCardClickOriginal, 500);
|
||||
|
||||
function handleLeave(encounterId) {
|
||||
leaveEncounter(encounterId).then((res) => {
|
||||
if (res.code == 200) {
|
||||
@@ -566,11 +575,18 @@ function handleFinish(encounterId) {
|
||||
patientInfo.value = {};
|
||||
visitType.value = ''; // 重置初复诊标识
|
||||
visitTypeDisabled.value = false; // 重置禁用状态
|
||||
firstEnum.value = 1; // 重置为初诊
|
||||
getPatientList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 监听初复诊标识变化
|
||||
watch(firstEnum, (newValue) => {
|
||||
// 这里可以添加更新后端的逻辑,如果需要实时同步到后端
|
||||
// 例如:updateEncounterFirstEnum(patientInfo.value.encounterId, newValue)
|
||||
});
|
||||
|
||||
function handleTimeChange(value) {
|
||||
queryParams.value.registerTimeSTime = value + ' 00:00:00';
|
||||
queryParams.value.registerTimeETime = value + ' 23:59:59';
|
||||
@@ -594,7 +610,7 @@ function handleHospitalizationClick() {
|
||||
|
||||
// 接诊回调
|
||||
function handleReceive(row) {
|
||||
handleCardClickOriginal(row);
|
||||
handleCardClick(row);
|
||||
currentEncounterId.value = row.encounterId;
|
||||
drawer.value = false;
|
||||
getPatientList();
|
||||
@@ -781,7 +797,7 @@ const markSeen = async () => {
|
||||
currentCallPatient.value = {};
|
||||
};
|
||||
const callThis = (row) => {
|
||||
handleCardClickOriginal(row);
|
||||
handleCardClick(row);
|
||||
currentCallPatient.value = row;
|
||||
dialogVisible.value = false;
|
||||
// 刷新患者列表和候诊列表
|
||||
|
||||
Reference in New Issue
Block a user