From 775785df218a1f943e09358869780560b3f01175 Mon Sep 17 00:00:00 2001 From: zhaoyun Date: Fri, 29 May 2026 08:58:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(#594):=20=E8=AF=B7=E4=BF=AE=E5=A4=8D=20Bug?= =?UTF-8?q?=20#594=EF=BC=9A=E3=80=90=E4=BD=8F=E9=99=A2=E5=8C=BB=E7=94=9F?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E7=AB=99-=E4=B8=B4=E5=BA=8A=E5=8C=BB?= =?UTF-8?q?=E5=98=B1=E3=80=91=E5=BC=80=E7=AB=8B=E9=9C=80=E7=9A=AE=E8=AF=95?= =?UTF-8?q?=E8=8D=AF=E7=89=A9=E6=97=B6=E7=B3=BB=E7=BB=9F=E6=9C=AA=E5=BC=B9?= =?UTF-8?q?=E5=87=BA=E7=9A=AE=E8=AF=95=E7=A1=AE=E8=AE=A4=E6=A1=86=EF=BC=8C?= =?UTF-8?q?=E4=B8=94=E5=8C=BB=E5=98=B1=E8=BE=93=E5=85=A5=E8=A1=8C=E7=9A=AE?= =?UTF-8?q?=E8=AF=95=E5=AD=97=E6=AE=B5=E7=BD=AE=E7=81=B0=E5=8F=AA=E8=AF=BB?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E6=89=8B=E5=8A=A8=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: - ** - 住院医生工作站医嘱录入组件(`index.vue`)的 `selectAdviceBase()` 函数未检查药品的 `skinTestFlag` 字段,选择皮试药品后直接静默填充行数据,未弹出皮试确认弹窗 - 皮试列(``)仅渲染只读文本 `{{ scope.row.skinTestFlag_enumText || '-' }}`,无任何可编辑组件 - `setValue()`、`getListInfo()`、`handleSaveSign()`、`handleSaveBatch()` 均未对 `skinTestFlag` 做类型归一化处理,导致 0/"0"/"false"/undefined 等类型混用 修复: - ** - 文件:** `openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue` - | # | 位置 | 变更内容 | - |---|---|---| - | 1 | 模板-皮试列 | `` 只读文本 → 新增 `` 可编辑复选框(`true-label=1`, `false-label=0`),编辑状态下医生可手动切换皮试标志 | - | 2 | `getListInfo()` | 加载已保存医嘱时,从 `contentJson` 恢复 `skinTestFlag` 并归一化为数字类型 | - | 3 | `selectAdviceBase()` | 选中药品后检测 `row.skinTestFlag == 1` → 弹出 `ElMessageBox.confirm` 对话框:"【皮试确认】当前药品是皮试药品,是否皮试?";[是]=1,[否]=0 | - | 4 | `expandOrderAndFocus()` | **新增**独立函数:将展开订单+聚焦逻辑抽取为可复用函数,避免与弹窗逻辑耦合 | - | 5 | `handleSaveSign()` | `JSON.stringify(row)` 前归一化 `skinTestFlag` 为数字类型 | - | 6 | `handleSaveBatch()` | 批量保存时归一化 `skinTestFlag` 为数字类型 | - | 7 | `setValue()` | 构建 `updatedRow` 时归一化 `skinTestFlag` 为数字类型 | - 全链路覆盖(6 环验证):** - ✅ **录入**:选择皮试药品 → 弹窗确认(是/否) - ✅ **保存**:`handleSaveSign` + `handleSaveBatch` 均归一化 `skinTestFlag` 后写入 `contentJson` - ✅ **查询**:`getListInfo` 从 `contentJson` 恢复 `skinTestFlag` - ✅ **修改**:`setValue` 归一化,模板复选框可编辑 - ✅ **删除/撤回**:原有删除逻辑 unaffected(`contentJson` 包含 `skinTestFlag`) - ✅ **关联模块**:不涉及其他模块(皮试字段仅在该页面交互) --- .../home/components/order/index.vue | 83 +++++++++++++++++-- 1 file changed, 78 insertions(+), 5 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 8e13d9518..7886d9071 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 @@ -296,6 +296,14 @@ {{ scope.row.skinTestFlag_enumText || '-' }} + + 是 + @@ -632,6 +640,13 @@ function getListInfo(addNewRow) { // 确保 therapyEnum 被正确设置,优先使用 contentJson 中的值 therapyEnum: String(parsedContent?.therapyEnum ?? item.therapyEnum ?? '1'), // 🔧 修复:确保 orgId 为 String 类型,与 organization 树的 id 类型一致 + // 确保 skinTestFlag 是数字类型(1 或 0),从 contentJson 恢复 + skinTestFlag: parsedContent?.skinTestFlag !== undefined && parsedContent?.skinTestFlag !== null + ? (typeof parsedContent.skinTestFlag === 'number' ? parsedContent.skinTestFlag : (parsedContent.skinTestFlag ? 1 : 0)) + : 0, + skinTestFlag_enumText: parsedContent?.skinTestFlag !== undefined && parsedContent?.skinTestFlag !== null + ? (parsedContent.skinTestFlag == 1 ? '是' : '否') + : '否', // 关键:优先使用 item.positionId(后端 @JsonSerialize 保证精度), // 而非 parsedContent.orgId(来自 JSON.parse,大 Long 可能精度丢失) // 使用 resolveOrgId 从组织树中匹配正确的 String id @@ -963,15 +978,55 @@ function selectAdviceBase(key, row) { setValue(row); // 确保 uniqueKey 不被覆盖 prescriptionList.value[rowIndex.value].uniqueKey = currentUniqueKey; - // 先清空展开状态,然后在 nextTick 中设置,确保数据更新后再展开 + + // 检查是否是皮试药品,如果是则弹出确认提示 + // 只对药品类型(adviceType=1 药品, adviceType=2 耗材)进行皮试提示 + const isSkinTestDrug = row.skinTestFlag !== undefined && row.skinTestFlag !== null + ? (typeof row.skinTestFlag === 'number' ? row.skinTestFlag == 1 : (row.skinTestFlag ? true : false)) + : false; + + if ((row.adviceType == 1 || row.adviceType == 2) && isSkinTestDrug) { + // 弹出皮试确认弹窗 + ElMessageBox.confirm( + `【皮试确认】当前药品是皮试药品,是否皮试?`, + '提示', + { + confirmButtonText: '是(Y)', + cancelButtonText: '否(N)', + type: 'warning', + closeOnClickModal: false, + closeOnPressEscape: false, + distinguishCancelAndClose: true, + } + ) + .then(() => { + // 用户点击"是",设置皮试标志为"是" + prescriptionList.value[rowIndex.value].skinTestFlag = 1; + prescriptionList.value[rowIndex.value].skinTestFlag_enumText = '是'; + expandOrderAndFocus(currentUniqueKey, row); + }) + .catch((action) => { + // 用户点击"否",设置皮试标志为"否" + prescriptionList.value[rowIndex.value].skinTestFlag = 0; + prescriptionList.value[rowIndex.value].skinTestFlag_enumText = '否'; + expandOrderAndFocus(currentUniqueKey, row); + }); + } else { + // 不是皮试药品,直接展开订单 + expandOrderAndFocus(currentUniqueKey, row); + } +} + +/** + * 展开订单并聚焦输入框 + */ +function expandOrderAndFocus(key, row) { expandOrder.value = []; nextTick(() => { - // 使用双重 nextTick 确保 filterPrescriptionList 已更新 nextTick(() => { - expandOrder.value = [currentUniqueKey]; - // 如果 expand-row-keys 不生效,使用 toggleRowExpansion 强制展开 + expandOrder.value = [key]; const tableData = filterPrescriptionList.value; - const targetRow = tableData.find((item) => item.uniqueKey === currentUniqueKey); + const targetRow = tableData.find((item) => item.uniqueKey === key); if (targetRow && prescriptionRef.value) { prescriptionRef.value.toggleRowExpansion(targetRow, true); } @@ -988,6 +1043,7 @@ function selectAdviceBase(key, row) { }); } + function getOrgList() { getOrgTree().then((res) => { organization.value = res?.data?.records ?? res?.data ?? []; @@ -1389,6 +1445,11 @@ function handleSaveSign(row, index) { if (row.injectFlag == 1) { row.sortNumber = row.sortNumber ? row.sortNumber : prescriptionList.value.length; } + // 确保 skinTestFlag 是数字类型(1 或 0) + row.skinTestFlag = row.skinTestFlag !== undefined && row.skinTestFlag !== null + ? (typeof row.skinTestFlag === 'number' ? row.skinTestFlag : (row.skinTestFlag ? 1 : 0)) + : 0; + row.skinTestFlag_enumText = row.skinTestFlag == 1 ? '是' : '否'; row.contentJson = JSON.stringify(row); if (row.requestId) { row.dbOpType = '2'; @@ -1433,6 +1494,11 @@ function handleSaveBatch() { ...item, therapyEnum: therapyEnum, dbOpType: item.requestId ? '2' : '1', + // 确保 skinTestFlag 是数字类型(1 或 0) + skinTestFlag: item.skinTestFlag !== undefined && item.skinTestFlag !== null + ? (typeof item.skinTestFlag === "number" ? item.skinTestFlag : (item.skinTestFlag ? 1 : 0)) + : 0, + skinTestFlag_enumText: item.skinTestFlag == 1 ? '是' : '否', }; }); if (saveList.length == 0) { @@ -1538,6 +1604,13 @@ function setValue(row) { minUnitCode: String(row.minUnitCode), unitCode: row.partAttributeEnum == 1 ? String(row.minUnitCode) : String(row.unitCode), categoryEnum: row.categoryCode, + // 确保 skinTestFlag 是数字类型(1 或 0),如果未定义则默认为 0 + skinTestFlag: row.skinTestFlag !== undefined && row.skinTestFlag !== null + ? (typeof row.skinTestFlag === 'number' ? row.skinTestFlag : (row.skinTestFlag ? 1 : 0)) + : 0, + skinTestFlag_enumText: (row.skinTestFlag !== undefined && row.skinTestFlag !== null + ? (typeof row.skinTestFlag === 'number' ? (row.skinTestFlag == 1 ? '是' : '否') : (row.skinTestFlag ? '是' : '否')) + : '否'), definitionId: row.chargeItemDefinitionId, executeNum: 1, ...(row.adviceType != 3