From 0c06b05764a4c99622676ab27b9de05e55e3cca6 Mon Sep 17 00:00:00 2001 From: chenqi Date: Wed, 18 Mar 2026 18:17:54 +0800 Subject: [PATCH] =?UTF-8?q?fix(print):=20=E4=BC=98=E5=8C=96=E6=89=93?= =?UTF-8?q?=E5=8D=B0=E5=8A=9F=E8=83=BD=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=92=8C=E4=BF=AE=E5=A4=8D=E4=BD=8D=E7=BD=AEID=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=97=AE=E9=A2=98=20BUG#217?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在printUtils.js中添加详细的打印诊断日志,包含hiprint对象检查、模板数据检查、医院名称处理等步骤 - 修复orderGroupDrawer.vue中的positionId获取逻辑,优先使用item.positionId - 修复prescriptionlist.vue中quantity和totalPrice的计算问题 - 修复服务器端DiagTreatMAppServiceImpl中pricingFlag过滤条件处理问题 - 修复EleInvoiceMapper.xml中orgClassEnum类型的CAST转换问题 - 优化打印错误处理和异常捕获机制 - 添加完整的打印流程日志跟踪功能 --- .../impl/DiagTreatMAppServiceImpl.java | 14 +++ .../dto/DiagnosisTreatmentSelParam.java | 3 + .../mapper/paymentmanage/EleInvoiceMapper.xml | 2 +- openhis-ui-vue3/src/utils/printUtils.js | 110 +++++++++++++++--- .../cliniccharge/components/chargeDialog.vue | 44 +++++-- .../prescription/orderGroupDrawer.vue | 6 +- .../prescription/prescriptionlist.vue | 50 ++++---- 7 files changed, 177 insertions(+), 52 deletions(-) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java index 569d95a8..e3de843e 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java @@ -200,6 +200,13 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService { DiagnosisTreatmentSelParam.setInspectionTypeId(null); // 临时移除,防止HisQueryUtils处理 } + // 临时保存pricingFlag值,手动添加带表别名的条件 + Integer pricingFlagValue = null; + if (DiagnosisTreatmentSelParam != null && DiagnosisTreatmentSelParam.getPricingFlag() != null) { + pricingFlagValue = DiagnosisTreatmentSelParam.getPricingFlag(); + DiagnosisTreatmentSelParam.setPricingFlag(null); // 临时移除,防止HisQueryUtils处理 + } + // 构建查询条件 QueryWrapper queryWrapper = HisQueryUtils.buildQueryWrapper(DiagnosisTreatmentSelParam, searchKey, new HashSet<>(Arrays.asList("T1.bus_no", "T1.name", "T1.py_str", "T1.wb_str")), request); @@ -218,6 +225,13 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService { DiagnosisTreatmentSelParam.setInspectionTypeId(inspectionTypeIdValue); } + // 如果需要按划价标记过滤,添加带表别名的条件 + if (pricingFlagValue != null) { + queryWrapper.eq("T1.pricing_flag", pricingFlagValue); + // 恢复参数对象中的值 + DiagnosisTreatmentSelParam.setPricingFlag(pricingFlagValue); + } + // 分页查询 IPage diseaseTreatmentPage = activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page(pageNo, pageSize), queryWrapper); diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/dto/DiagnosisTreatmentSelParam.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/dto/DiagnosisTreatmentSelParam.java index 55d22d4b..5e987861 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/dto/DiagnosisTreatmentSelParam.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/dto/DiagnosisTreatmentSelParam.java @@ -33,4 +33,7 @@ public class DiagnosisTreatmentSelParam { /** 检验类型ID */ private Long inspectionTypeId; + + /** 划价标记 */ + private Integer pricingFlag; } diff --git a/openhis-server-new/openhis-application/src/main/resources/mapper/paymentmanage/EleInvoiceMapper.xml b/openhis-server-new/openhis-application/src/main/resources/mapper/paymentmanage/EleInvoiceMapper.xml index 89172ce1..1e440c6b 100644 --- a/openhis-server-new/openhis-application/src/main/resources/mapper/paymentmanage/EleInvoiceMapper.xml +++ b/openhis-server-new/openhis-application/src/main/resources/mapper/paymentmanage/EleInvoiceMapper.xml @@ -140,7 +140,7 @@ ON LEFT (T3.bus_no, 6) = T11.bus_no WHERE T2.id = #{encounterId} AND T2.class_enum = #{encClassEnum} - AND T3.class_enum = #{orgClassEnum} + AND T3.class_enum = CAST(#{orgClassEnum} AS VARCHAR) AND T1.delete_flag = '0' LIMIT 1 diff --git a/openhis-ui-vue3/src/utils/printUtils.js b/openhis-ui-vue3/src/utils/printUtils.js index 3f6bba13..d7b6d81c 100644 --- a/openhis-ui-vue3/src/utils/printUtils.js +++ b/openhis-ui-vue3/src/utils/printUtils.js @@ -269,23 +269,63 @@ export function executePrint(data, template, printerName, options = {}, business return new Promise((resolve, reject) => { try { // 调试信息 - console.log('hiprint 对象:', hiprint); - console.log('hiprint.PrintTemplate:', hiprint.PrintTemplate); - console.log('模板数据:', template); + console.log('========== 打印诊断日志开始 =========='); + console.log('[1] hiprint对象检查:'); + console.log(' - hiprint存在:', !!hiprint); + console.log(' - hiprint.PrintTemplate存在:', !!(hiprint && hiprint.PrintTemplate)); + console.log(' - hiprint.hiwebSocket存在:', !!(hiprint && hiprint.hiwebSocket)); + console.log(' - hiprint.hiwebSocket.connected:', hiprint?.hiwebSocket?.connected); + + console.log('[2] 模板数据检查:'); + console.log(' - 模板类型:', typeof template); + console.log(' - 模板存在:', !!template); + console.log(' - 模板panels存在:', !!(template && template.panels)); + console.log(' - panels数量:', template?.panels?.length); + + if (template?.panels?.[0]) { + const panel = template.panels[0]; + console.log(' - panel.name:', panel.name, '(类型:', typeof panel.name, ')'); + console.log(' - panel.index:', panel.index); + console.log(' - panel.printElements数量:', panel.printElements?.length); + + // 检查每个元素的类型 + if (panel.printElements) { + panel.printElements.forEach((el, idx) => { + console.log(` - 元素[${idx}]:`, el.printElementType?.type, '-', el.printElementType?.title); + }); + } + } const userStore = useUserStore(); - const processedTemplate = JSON.parse( - JSON.stringify(template).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName) - ); + console.log('[3] 医院名称:', userStore.hospitalName); + + let processedTemplate; + try { + processedTemplate = JSON.parse( + JSON.stringify(template).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName) + ); + console.log('[4] 模板处理成功'); + } catch (parseError) { + console.error('[4] 模板处理失败:', parseError); + throw new Error('模板处理失败: ' + parseError.message); + } - console.log('打印模板:', processedTemplate.panels?.[0]?.name, '元素数量:', processedTemplate.panels?.[0]?.printElements?.length); + console.log('[5] 打印数据检查:'); + console.log(' - 数据类型:', typeof data); + console.log(' - 数据存在:', !!data); + if (data && typeof data === 'object') { + console.log(' - 数据字段:', Object.keys(data)); + } // 创建打印模板 let hiprintTemplate; try { + console.log('[6] 开始创建PrintTemplate...'); hiprintTemplate = new hiprint.PrintTemplate({ template: processedTemplate }); + console.log('[6] PrintTemplate创建成功:', hiprintTemplate); } catch (templateError) { - console.error('创建打印模板失败:', templateError); + console.error('[6] 创建打印模板失败:', templateError); + console.error('错误堆栈:', templateError.stack); console.error('模板内容:', JSON.stringify(processedTemplate, null, 2)); throw new Error('打印模板创建失败: ' + templateError.message); } @@ -296,47 +336,79 @@ export function executePrint(data, template, printerName, options = {}, business width: 148, ...options, }; + console.log('[7] 打印选项:', printOptions); // 检查客户端是否连接 const isClientConnected = hiprint.hiwebSocket && hiprint.hiwebSocket.connected; + console.log('[8] 客户端连接状态:', isClientConnected); // 如果指定了打印机且客户端已连接,添加到打印选项中 if (printerName && isClientConnected) { printOptions.printer = printerName; // 保存到缓存 savePrinterToCache(printerName, businessName); + console.log('[8] 使用指定打印机:', printerName); } // 打印成功回调 hiprintTemplate.on('printSuccess', function (e) { + console.log('[9] 打印成功:', e); + console.log('========== 打印诊断日志结束 =========='); resolve({ success: true, event: e }); }); // 打印失败回调 hiprintTemplate.on('printError', function (e) { + console.error('[9] 打印失败:', e); + console.log('========== 打印诊断日志结束 =========='); reject({ success: false, event: e, message: '打印失败' }); }); // 根据客户端连接状态选择打印方式 + console.log('[10] 开始执行打印...'); if (isClientConnected && printerName) { // 客户端已连接且指定了打印机,使用静默打印 - hiprintTemplate.print2(data, printOptions); + console.log('[10] 使用print2静默打印'); + try { + hiprintTemplate.print2(data, printOptions); + console.log('[10] print2调用完成'); + } catch (print2Error) { + console.error('[10] print2调用失败:', print2Error); + console.error('[10] print2错误堆栈:', print2Error.stack); + throw new Error('print2打印失败: ' + print2Error.message); + } } else { // 客户端未连接或未指定打印机,使用浏览器打印预览(不需要客户端连接) - console.log('打印客户端未连接,使用浏览器打印预览方式'); - hiprintTemplate.print(data, printOptions, { - styleHandler: () => { - return ''; - }, - callback: () => { - console.log('打印窗口已打开'); - } - }); + console.log('[10] 使用print浏览器打印预览'); + console.log('[10] hiprintTemplate.print方法存在:', typeof hiprintTemplate.print === 'function'); + try { + hiprintTemplate.print(data, printOptions, { + styleHandler: () => { + console.log('[10] styleHandler被调用'); + return ''; + }, + callback: (e) => { + console.log('[10] 打印回调被调用:', e); + } + }); + console.log('[10] print调用完成'); + } catch (printError) { + console.error('[10] print调用失败:', printError); + console.error('[10] print错误堆栈:', printError.stack); + throw new Error('print打印失败: ' + printError.message); + } // 浏览器打印模式下,直接resolve(因为打印窗口已打开) + console.log('[10] 浏览器打印模式,直接返回成功'); + console.log('========== 打印诊断日志结束 =========='); resolve({ success: true, message: '打印窗口已打开' }); } } catch (error) { - reject({ success: false, error: error, message: error.message || '打印过程中发生错误' }); + console.error('[ERROR] 打印过程中发生错误:', error); + console.error('[ERROR] 错误类型:', error?.constructor?.name); + console.error('[ERROR] 错误消息:', error?.message); + console.error('[ERROR] 错误堆栈:', error?.stack); + console.log('========== 打印诊断日志结束 =========='); + reject({ success: false, error: error, message: error?.message || '打印过程中发生错误' }); } }); } diff --git a/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue b/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue index c15dfc6c..3406da98 100644 --- a/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue +++ b/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue @@ -253,10 +253,22 @@ const getUnitLabel = (unitCode) => { async function printReceipt(param) { // 打印收费小票数据 - console.log('打印收费小票数据:', param.chargedItems); - // console.log('!!!!!!!!!选中的收费项目:', param.chargedItems); - console.log('患者信息:', props.patientInfo); - // formData.totalAmount = props.totalAmount; + console.log('========== 打印收费小票 - 开始 =========='); + console.log('[A] 传入参数检查:'); + console.log(' - param对象:', param ? '存在' : '不存在'); + console.log(' - param.chargedItems:', param?.chargedItems ? `存在(${param.chargedItems.length}条)` : '不存在/空'); + console.log(' - param.detail:', param?.detail ? `存在(${param.detail.length}条)` : '不存在/空'); + console.log(' - param.regNo:', param?.regNo); + console.log(' - param.fixmedinsName:', param?.fixmedinsName); + console.log(' - props.patientInfo:', props.patientInfo ? '存在' : '不存在'); + + if (param?.chargedItems) { + console.log('[B] 收费项目数据:'); + param.chargedItems.forEach((item, idx) => { + console.log(` - 项目[${idx}]:`, item.chargeItemName || '未命名', '-', item.quantityWithUnit || item.quantityValue); + }); + } + // 确保第一个支付方式的金额与总金额一致; if (formData.selfPay.length > 0) { formData.selfPay[0].amount = props.totalAmount; @@ -271,6 +283,7 @@ async function printReceipt(param) { try { // 处理param.chargedItems,添加quantityWithUnit字段 + console.log('[C] 开始处理收费项目列表...'); const processedChargeItems = (param.chargedItems || []).map((item) => { // 获取单位标签 const unitLabel = getUnitLabel(item.quantityUnit); @@ -284,8 +297,10 @@ async function printReceipt(param) { quantityWithUnit, // 添加带单位的数量字段供打印使用 }; }); + console.log('[C] 处理完成,项目数:', processedChargeItems.length); // 构造打印数据,整合选中行信息 + console.log('[D] 开始构造打印数据...'); const printData = { data: [ { @@ -566,12 +581,27 @@ async function printReceipt(param) { // 使用printUtils进行打印 // 选择门诊收费打印模板并传递正确的数据格式 - console.log('789797987897', printData.data[0]); + console.log('[E] 最终打印数据检查:'); + console.log(' - printData.data[0]存在:', !!printData.data[0]); + console.log(' - 关键字段:'); + console.log(' * patientName:', printData.data[0]?.patientName); + console.log(' * regNo:', printData.data[0]?.regNo); + console.log(' * chargeItemsList:', printData.data[0]?.chargeItemsList ? `${printData.data[0].chargeItemsList.length}条` : '无'); + console.log(' * totalAmount:', printData.data[0]?.totalAmount); + console.log(' * currentDate:', printData.data[0]?.currentDate); + + console.log('[F] 开始调用printUtils.print...'); + console.log(' - 模板:', 'OUTPATIENT_CHARGE'); + await printUtils.print(PRINT_TEMPLATE.OUTPATIENT_CHARGE, printData.data[0]); - console.log('打印成功'); + console.log('[G] 打印调用成功完成'); + console.log('========== 打印收费小票 - 结束 =========='); } catch (error) { - console.error('打印失败:', error); + console.error('[ERROR] 打印失败:', error); + console.error('[ERROR] 错误详情:', error.message); + console.error('[ERROR] 错误堆栈:', error.stack); + console.log('========== 打印收费小票 - 异常结束 =========='); proxy.$modal.msgError('打印失败: ' + error.message); } } diff --git a/openhis-ui-vue3/src/views/doctorstation/components/prescription/orderGroupDrawer.vue b/openhis-ui-vue3/src/views/doctorstation/components/prescription/orderGroupDrawer.vue index f7d066aa..b50c63a8 100644 --- a/openhis-ui-vue3/src/views/doctorstation/components/prescription/orderGroupDrawer.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/prescription/orderGroupDrawer.vue @@ -590,7 +590,8 @@ function handleUseOrderGroup(row) { inventoryList: orderDetail.inventoryList || [], priceList: orderDetail.priceList || [], partPercent: orderDetail.partPercent || 1, - positionId: orderDetail.positionId, + // 🔧 Bug #218 修复:positionId 可能存储在 item 本身,优先使用 item.positionId + positionId: item.positionId || orderDetail.positionId, defaultLotNumber: orderDetail.defaultLotNumber, // 单位信息 @@ -615,7 +616,8 @@ function handleUseOrderGroup(row) { inventoryList: orderDetail.inventoryList || [], priceList: orderDetail.priceList || [], partPercent: orderDetail.partPercent || 1, - positionId: orderDetail.positionId, + // 🔧 Bug #218 修复:positionId 可能存储在 item 本身,优先使用 item.positionId + positionId: item.positionId || orderDetail.positionId, defaultLotNumber: orderDetail.defaultLotNumber, } }; diff --git a/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue b/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue index c9dbe7a1..aa0ecc3c 100644 --- a/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue @@ -2919,31 +2919,33 @@ function setValue(row) { prescriptionList.value[rowIndex.value].locationId = finalLocationId; prescriptionList.value[rowIndex.value].positionId = finalLocationId; } - } else { - getOrgList(); - // 会诊类型(adviceType == 5)和诊疗类型(adviceType == 3)的处理 - if (row.adviceType == 5) { - // 会诊类型:设置默认值 - prescriptionList.value[rowIndex.value].orgId = props.patientInfo.orgId; // 执行科室默认为申请医生的科室 - prescriptionList.value[rowIndex.value].quantity = 1; // 执行次数默认1次 - prescriptionList.value[rowIndex.value].unitPrice = row.priceList && row.priceList[0] ? row.priceList[0].price : (row.unitPrice || 0); - prescriptionList.value[rowIndex.value].totalPrice = prescriptionList.value[rowIndex.value].unitPrice; - prescriptionList.value[rowIndex.value].categoryEnum = 31; // 会诊的category_enum设置为31 } else { - // 诊疗类型(adviceType == 3) - prescriptionList.value[rowIndex.value].orgId = JSON.parse(JSON.stringify(row)).positionId; - prescriptionList.value[rowIndex.value].quantity = 1; - // 🔧 Bug #144 修复:安全访问 priceList,防止 orderDetailInfos 为空时出错 - if (row.priceList && row.priceList.length > 0) { - prescriptionList.value[rowIndex.value].unitPrice = row.priceList[0].price; - prescriptionList.value[rowIndex.value].totalPrice = row.priceList[0].price; + getOrgList(); + // 会诊类型(adviceType == 5)和诊疗类型(adviceType == 3)的处理 + if (row.adviceType == 5) { + // 会诊类型:设置默认值 + prescriptionList.value[rowIndex.value].orgId = props.patientInfo.orgId; // 执行科室默认为申请医生的科室 + prescriptionList.value[rowIndex.value].quantity = 1; // 执行次数默认1次 + prescriptionList.value[rowIndex.value].unitPrice = row.priceList && row.priceList[0] ? row.priceList[0].price : (row.unitPrice || 0); + prescriptionList.value[rowIndex.value].totalPrice = prescriptionList.value[rowIndex.value].unitPrice; + prescriptionList.value[rowIndex.value].categoryEnum = 31; // 会诊的category_enum设置为31 } else { - prescriptionList.value[rowIndex.value].unitPrice = 0; - prescriptionList.value[rowIndex.value].totalPrice = 0; - console.warn('医嘱项价格列表为空:', row.adviceName || '未知医嘱'); + // 诊疗类型(adviceType == 3) + prescriptionList.value[rowIndex.value].orgId = JSON.parse(JSON.stringify(row)).positionId; + // 🔧 Bug #218 修复:使用组套中维护的quantity,如果没有则默认1 + prescriptionList.value[rowIndex.value].quantity = row.quantity || 1; + // 🔧 Bug #144 修复:安全访问 priceList,防止 orderDetailInfos 为空时出错 + if (row.priceList && row.priceList.length > 0) { + prescriptionList.value[rowIndex.value].unitPrice = row.priceList[0].price; + // 🔧 Bug #218 修复:总金额 = 单价 × 数量 + prescriptionList.value[rowIndex.value].totalPrice = row.priceList[0].price * (row.quantity || 1); + } else { + prescriptionList.value[rowIndex.value].unitPrice = 0; + prescriptionList.value[rowIndex.value].totalPrice = 0; + console.warn('医嘱项价格列表为空:', row.adviceName || '未知医嘱'); + } } } - } } // 选择组套 - 适配新版 OrderGroupDrawer 组件 @@ -2986,7 +2988,8 @@ function handleSaveGroup(orderGroupList) { inventoryList: item.orderDetailInfos?.inventoryList || [], priceList: item.orderDetailInfos?.priceList || [], partPercent: item.orderDetailInfos?.partPercent || 1, - positionId: item.orderDetailInfos?.positionId, + // 🔧 Bug #218 修复:positionId 可能存储在 item 本身,优先使用 item.positionId + positionId: item.positionId || item.orderDetailInfos?.positionId, defaultLotNumber: item.orderDetailInfos?.defaultLotNumber, }; @@ -3016,7 +3019,8 @@ function handleSaveGroup(orderGroupList) { unitCode: item.unitCode, unitCode_dictText: item.unitCodeName || '', statusEnum: 1, - orgId: item.orderDetailInfos?.positionId || mergedDetail.positionId, + // 🔧 Bug #218 修复:优先使用 item.positionId,其次使用 orderDetailInfos.positionId + orgId: item.positionId || item.orderDetailInfos?.positionId || mergedDetail.positionId, dbOpType: prescriptionList.value[rowIndex.value].requestId ? '2' : '1', conditionId: conditionId.value, conditionDefinitionId: conditionDefinitionId.value,