fix(print): 优化打印功能调试日志和修复位置ID获取问题 BUG#217

- 在printUtils.js中添加详细的打印诊断日志,包含hiprint对象检查、模板数据检查、医院名称处理等步骤
- 修复orderGroupDrawer.vue中的positionId获取逻辑,优先使用item.positionId
- 修复prescriptionlist.vue中quantity和totalPrice的计算问题
- 修复服务器端DiagTreatMAppServiceImpl中pricingFlag过滤条件处理问题
- 修复EleInvoiceMapper.xml中orgClassEnum类型的CAST转换问题
- 优化打印错误处理和异常捕获机制
- 添加完整的打印流程日志跟踪功能
This commit is contained in:
2026-03-18 18:17:54 +08:00
parent 7c29c6359f
commit 0c06b05764
7 changed files with 177 additions and 52 deletions

View File

@@ -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<DiagnosisTreatmentDto> 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<DiagnosisTreatmentDto> diseaseTreatmentPage
= activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<DiagnosisTreatmentDto>(pageNo, pageSize), queryWrapper);

View File

@@ -33,4 +33,7 @@ public class DiagnosisTreatmentSelParam {
/** 检验类型ID */
private Long inspectionTypeId;
/** 划价标记 */
private Integer pricingFlag;
}

View File

@@ -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
</select>

View File

@@ -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);
console.log('打印模板:', processedTemplate.panels?.[0]?.name, '元素数量:', processedTemplate.panels?.[0]?.printElements?.length);
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('[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 '<style>@media print { @page { margin: 0; } }</style>';
},
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 '<style>@media print { @page { margin: 0; } }</style>';
},
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 || '打印过程中发生错误' });
}
});
}

View File

@@ -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);
}
}

View File

@@ -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,
}
};

View File

@@ -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,