From 659db997fd6a0c936cddde3e237e36adbf00d354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E7=BE=BD?= <关羽@gentronhealth.com> Date: Sun, 10 May 2026 16:02:42 +0800 Subject: [PATCH 01/24] =?UTF-8?q?Fix=20Bug=20#491:=20=E3=80=90=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=A7=91=E5=AE=A4=E9=85=8D=E7=BD=AE=E3=80=91=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E9=85=8D=E7=BD=AE=E6=97=B6=E7=B3=BB=E7=BB=9F=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端修复:时间冲突校验时 organizationService.getById 可能返回 null,增加空值判断避免 NPE 前端修复:保存前校验是否已选择科室,未选择时给出提示并阻断 Co-Authored-By: Claude Opus 4.7 --- .../impl/OrganizationLocationAppServiceImpl.java | 4 ++-- .../implementDepartment/components/batchAddDialog.vue | 4 ++++ .../src/views/basicmanage/implementDepartment/index.vue | 9 ++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java index 7c76d027..e808beb5 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java @@ -147,8 +147,8 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation for (OrganizationLocation organizationLocation : organizationLocationList) if (DateTimeUtils.isOverlap(organizationLocation.getStartTime(), organizationLocation.getEndTime(), orgLoc.getStartTime(), orgLoc.getEndTime())) { - String organizationName = - organizationService.getById(organizationLocation.getOrganizationId()).getName(); + Organization org = organizationService.getById(organizationLocation.getOrganizationId()); + String organizationName = org != null ? org.getName() : "未知科室"; return R.fail("当前诊疗:" + activityName + CommonConstants.Common.DASH + orgLoc.getStartTime() + CommonConstants.Common.DASH + orgLoc.getEndTime() + "与" + organizationName + "时间冲突"); } diff --git a/openhis-ui-vue3/src/views/basicmanage/implementDepartment/components/batchAddDialog.vue b/openhis-ui-vue3/src/views/basicmanage/implementDepartment/components/batchAddDialog.vue index 2f8ea831..9f6cd007 100755 --- a/openhis-ui-vue3/src/views/basicmanage/implementDepartment/components/batchAddDialog.vue +++ b/openhis-ui-vue3/src/views/basicmanage/implementDepartment/components/batchAddDialog.vue @@ -132,6 +132,10 @@ function onCancel() { // 批量添加 async function onConfirm() { + if (!props.organizationId) { + proxy.$message.error('请先在左侧选择科室'); + return; + } if (!formEl) return; formEl.value.validate(async (valid) => { if (!valid) return; diff --git a/openhis-ui-vue3/src/views/basicmanage/implementDepartment/index.vue b/openhis-ui-vue3/src/views/basicmanage/implementDepartment/index.vue index 04eb2f81..b9943008 100755 --- a/openhis-ui-vue3/src/views/basicmanage/implementDepartment/index.vue +++ b/openhis-ui-vue3/src/views/basicmanage/implementDepartment/index.vue @@ -366,6 +366,10 @@ function handleBlur(row, index) { // 编辑或 保存当前行 function openSaveImplementDepartment(row) { + if (!organizationId.value) { + proxy.$message.error('请先在左侧选择科室'); + return; + } const params = { // 科室id organizationId: organizationId.value, @@ -452,13 +456,12 @@ function handleNodeClick(res, node) { // 实际的节点点击处理逻辑 function continueHandleNodeClick(node) { - // 新增按钮是否 disable - isAddDisable.value = false; // 检查节点是否有子节点 if (node.data.children && node.data.children.length > 0) { - // proxy.$message.warning("不能选择父节点"); return; } + // 新增按钮是否 disable + isAddDisable.value = false; // 选中科室id organizationId.value = node.data.id; // 获取 右侧 table 信息 From c39c8faa5c2ea3263bb68d1f52485a59c2a40a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E7=BE=BD?= <关羽@gentronhealth.com> Date: Sun, 10 May 2026 16:05:09 +0800 Subject: [PATCH 02/24] =?UTF-8?q?Fix=20Bug=20#390:=20=E4=BD=8F=E9=99=A2?= =?UTF-8?q?=E6=8A=A4=E5=A3=AB=E7=AB=99-=E5=8C=BB=E5=98=B1=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=EF=BC=9A=E9=80=9A=E8=BF=87=E4=BD=8F=E9=99=A2=E5=8F=B7?= =?UTF-8?q?=E6=A3=80=E7=B4=A2=E6=97=A0=E6=B3=95=E5=AE=9A=E4=BD=8D/?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E6=82=A3=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原 handleSearch 调用 reloadAllPatients 仅尝试刷新已展开的病区节点, 对懒加载树不可靠。改为递增 treeKey 强制树组件完全重新渲染, 触发 loadNode/loadPatientList 重新从后端拉取数据并传入 searchKey 过滤。 --- .../src/views/inpatientNurse/components/patientList.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openhis-ui-vue3/src/views/inpatientNurse/components/patientList.vue b/openhis-ui-vue3/src/views/inpatientNurse/components/patientList.vue index 0921da1f..7bf4811a 100755 --- a/openhis-ui-vue3/src/views/inpatientNurse/components/patientList.vue +++ b/openhis-ui-vue3/src/views/inpatientNurse/components/patientList.vue @@ -273,8 +273,9 @@ function handleSearch() { // 清除缓存(搜索时需要重新加载) patientDataCache.value.clear(); - // 重新加载所有已展开病区的患者列表 - reloadAllPatients(); + // 通过递增 key 强制重新渲染树组件,触发重新加载所有病区患者列表 + // 此时 searchKey 已有值,loadPatientList 会将 searchKey 传给后端进行过滤 + treeKey.value += 1; } // 暴露方法供外部调用 From ad69578cc35145869f587ae52b0721a1b29f8214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E7=BE=BD?= <关羽@gentronhealth.com> Date: Sun, 10 May 2026 16:02:20 +0800 Subject: [PATCH 03/24] =?UTF-8?q?Fix=20Bug=20#486:=20[=E4=BD=8F=E9=99=A2?= =?UTF-8?q?=E5=8C=BB=E7=94=9F=E5=B7=A5=E4=BD=9C=E7=AB=99-=E4=B8=B4?= =?UTF-8?q?=E5=BA=8A=E5=8C=BB=E5=98=B1]=20=E5=8C=BB=E5=98=B1=E6=A3=80?= =?UTF-8?q?=E7=B4=A2=E6=A1=86=E4=B8=8D=E6=94=AF=E6=8C=81=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E6=A8=A1=E7=B3=8A=E6=90=9C=E7=B4=A2=EF=BC=8C=E6=9C=AA=E9=80=89?= =?UTF-8?q?"=E5=8C=BB=E5=98=B1=E7=B1=BB=E5=9E=8B"=E6=97=B6=E6=A3=80?= =?UTF-8?q?=E7=B4=A2=E7=BB=93=E6=9E=9C=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- .../inpatientDoctor/home/components/order/index.vue | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue b/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue index 35336e07..213a499d 100755 --- a/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue +++ b/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue @@ -879,14 +879,12 @@ function handleDiagnosisChange(item) { function handleFocus(row, index) { rowIndex.value = index; row.showPopover = true; - // el-popover 懒渲染,需要等两帧组件才会挂载 const adviceType = row.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType; // 用 adviceType + categoryCode 组合查找匹配的选项 const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType; const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType); - // 诊疗(3)和手术(6)没有categoryCode,传空字符串给refresh,由子组件转为undefined不发送 - // 药品(1)才有categoryCode(如'1'=中成药,'2'=西药,'4'=中草药) - const categoryCode = selectedItem ? selectedItem.categoryCode : (adviceQueryParams.value.categoryCode || ''); + // 修复Bug #486:当行没有显式选择医嘱类型时,不传categoryCode,让搜索在全药库中进行 + const categoryCode = selectedItem ? selectedItem.categoryCode : (row.adviceType !== undefined ? (adviceQueryParams.value.categoryCode || '') : ''); const searchKey = row.adviceName || ''; nextTick(() => { @@ -923,8 +921,8 @@ function handleChange(value) { // 用 adviceType + categoryCode 组合查找匹配的选项 const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType; const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType); - // 诊疗/手术的categoryCode为空字符串,由子组件转为undefined不发送 - const categoryCode = selectedItem ? selectedItem.categoryCode : (adviceQueryParams.value.categoryCode || ''); + // 修复Bug #486:当行没有显式选择医嘱类型时,不传categoryCode,让搜索在全药库中进行 + const categoryCode = selectedItem ? selectedItem.categoryCode : (row?.adviceType !== undefined ? (adviceQueryParams.value.categoryCode || '') : ''); tableRef.refresh(adviceType, categoryCode, value); } } From fb33353962ac3646475e25bf9978e60fc40c0f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B3=E7=BE=BD?= <关羽@gentronhealth.com> Date: Sun, 10 May 2026 16:05:19 +0800 Subject: [PATCH 04/24] =?UTF-8?q?Fix=20Bug=20#488:=20=E3=80=90=E4=B8=B4?= =?UTF-8?q?=E5=BA=8A=E5=8C=BB=E5=98=B1=E3=80=91=E5=8F=8C=E5=87=BB=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=BE=85=E7=AD=BE=E5=8F=91=E5=8C=BB=E5=98=B1=EF=BC=8C?= =?UTF-8?q?=E5=8C=BB=E5=98=B1=E7=B1=BB=E5=9E=8B=E5=9B=9E=E6=98=BE=E4=B8=BA?= =?UTF-8?q?=E6=95=B0=E5=AD=97=E4=B8=94=E7=82=B9=E5=87=BB=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E6=8A=A5=E6=8E=A5=E5=8F=A3=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 handleSaveSign 中 getBindDevice 调用时 itemNo 可能为 undefined 导致的后端报错 "Required request parameter 'itemNo' for method parameter type String is not present":增加 itemNo 空值检查,为空时 console.warn 跳过调用而非发送无效请求 - 移除模板中两处调试残留:console.log 表达式渲染到页面(类型列和频次/用法列) - 修复签发失败处理中截断的 conso; 语法错误 --- .../home/components/order/index.vue | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue b/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue index 213a499d..6c801c13 100755 --- a/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue +++ b/openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue @@ -122,7 +122,6 @@ 和多余的标签,确保el-table正确渲染 2. 新增selectedRowIds独立维护选中行ID集合,不再依赖el-table内部selection状态,避免执行选中时联动触发全选 3. 更新所有选择事件处理器同步维护selectedRowIds 4. 补充index.vue缺失的ref/nextTick/provide导入 Co-Authored-By: Claude Opus 4.7 --- .../components/prescriptionList.vue | 47 ++++++++++++------- .../medicalOrderExecution/index.vue | 2 +- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/components/prescriptionList.vue b/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/components/prescriptionList.vue index 99b7bbbd..05d74322 100755 --- a/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/components/prescriptionList.vue +++ b/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/components/prescriptionList.vue @@ -68,9 +68,7 @@ - - -
@@ -232,7 +230,7 @@ import {adviceCancel, adviceExecute, adviceNoExecute, getPrescriptionList} from import {patientInfoList} from '../../components/store/patient.js'; import {lotNumberMatch} from '@/api/public'; import {formatDateStr} from '@/utils/index'; -import {getCurrentInstance, nextTick, ref} from 'vue'; +import {getCurrentInstance, nextTick, ref, provide} from 'vue'; const activeNames = ref([]); const prescriptionList = ref([]); @@ -242,6 +240,8 @@ const therapyEnum = ref(undefined); const { proxy } = getCurrentInstance(); const loading = ref(false); const chooseAll = ref(false); +// 独立维护选中行ID集合,避免el-table内部selection状态异常导致联动全选 +const selectedRowIds = ref(new Set()); const props = defineProps({ exeStatus: { type: Number, @@ -442,6 +442,7 @@ function handleGetPrescription() { chooseAll.value = false; } else { prescriptionList.value = []; + selectedRowIds.value.clear(); // proxy.$message.warning('请选择患者'); } } @@ -530,10 +531,14 @@ function handleCancel() { } function getSelectRows() { - // 获取选中的医嘱信息 - let list = []; - prescriptionList.value.forEach((item, index) => { - list = [...list, ...proxy.$refs['tableRef' + index][0].getSelectionRows()]; + // 优先从独立维护的selectedRowIds集合中获取选中行,避免el-table内部selection状态异常 + const list = []; + prescriptionList.value.forEach((item) => { + item.forEach((row) => { + if (selectedRowIds.value.has(row.requestId)) { + list.push(row); + } + }); }); return list; } @@ -609,12 +614,14 @@ function handelSwicthChange(value) { if (value) { // 全选:选中所有行并联动checkbox item.forEach((row) => { + selectedRowIds.value.add(row.requestId); tableRef[0].toggleRowSelection(row, true); selectAllCheckboxesInRow(row); }); } else { // 取消全选:取消选中所有行并联动checkbox item.forEach((row) => { + selectedRowIds.value.delete(row.requestId); tableRef[0].toggleRowSelection(row, false); unselectAllCheckboxesInRow(row); }); @@ -625,11 +632,14 @@ function handelSwicthChange(value) { // 默认选中全部行 function defaultSelectAllRows() { + // 清空并重建选中集合 + selectedRowIds.value.clear(); prescriptionList.value.forEach((item, index) => { const tableRef = proxy.$refs['tableRef' + index]; if (tableRef && tableRef[0]) { // 选中该表格的所有行 item.forEach((row) => { + selectedRowIds.value.add(row.requestId); tableRef[0].toggleRowSelection(row, true); // 同时选中该行内部的所有checkbox selectAllCheckboxesInRow(row); @@ -709,13 +719,14 @@ function checkAndToggleRowSelection(row) { const tableRef = proxy.$refs['tableRef' + tableIndex]; if (tableRef && tableRef[0]) { const isAllSelected = isAllCheckboxesSelected(row); - const selectedRows = tableRef[0].getSelectionRows(); - const isCurrentlySelected = selectedRows.some((r) => r.requestId === row.requestId); + const isCurrentlySelected = selectedRowIds.value.has(row.requestId); // 根据checkbox状态更新表格行选中状态 if (isAllSelected && !isCurrentlySelected) { + selectedRowIds.value.add(row.requestId); tableRef[0].toggleRowSelection(row, true); } else if (!isAllSelected && isCurrentlySelected) { + selectedRowIds.value.delete(row.requestId); tableRef[0].toggleRowSelection(row, false); } } @@ -728,9 +739,11 @@ function handleRowSelect(selection, row, tableIndex) { const isSelected = selection.some((item) => item.requestId === row.requestId); if (isSelected) { + selectedRowIds.value.add(row.requestId); // 选中行时,选中该行内部的所有checkbox selectAllCheckboxesInRow(row); } else { + selectedRowIds.value.delete(row.requestId); // 取消选中行时,取消选中该行内部的所有checkbox unselectAllCheckboxesInRow(row); } @@ -747,11 +760,13 @@ function handleSelectAll(selection, tableIndex) { if (selection.length > 0) { // 全选时,选中所有行内部的所有checkbox tableData.forEach((row) => { + selectedRowIds.value.add(row.requestId); selectAllCheckboxesInRow(row); }); } else { // 取消全选时,取消选中所有行内部的所有checkbox tableData.forEach((row) => { + selectedRowIds.value.delete(row.requestId); unselectAllCheckboxesInRow(row); }); } @@ -763,16 +778,12 @@ function handleSelectAll(selection, tableIndex) { // 更新全选开关状态 function updateChooseAllStatus() { let allSelected = true; - prescriptionList.value.forEach((item, index) => { - const tableRef = proxy.$refs['tableRef' + index]; - if (tableRef && tableRef[0]) { - const selectedRows = tableRef[0].getSelectionRows(); - if (selectedRows.length !== item.length) { + prescriptionList.value.forEach((item) => { + item.forEach((row) => { + if (!selectedRowIds.value.has(row.requestId)) { allSelected = false; } - } else { - allSelected = false; - } + }); }); chooseAll.value = allSelected; } diff --git a/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/index.vue b/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/index.vue index 54c36670..905890e4 100755 --- a/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/index.vue +++ b/openhis-ui-vue3/src/views/inpatientNurse/medicalOrderExecution/index.vue @@ -51,7 +51,7 @@