Files
his/openhis-ui-vue3/src/utils/printUtils.js
zhangfei 9c3e603b94 Fix Bug #443: 手术计费:点击签发耗材时异常报错
当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。
在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值,
与NurseBillingAppService中的处理方式保持一致。
2026-05-08 09:14:18 +08:00

703 lines
25 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 打印工具类
* 集中管理所有打印相关功能
*/
import {hiprint} from 'vue-plugin-hiprint';
// 打印模板映射表 .
const TEMPLATE_MAP = {
// CLINIC_CHARGE: () => import('@/views/charge/cliniccharge/components/template.json'),
// DISPOSAL: () => import('@/views/clinicmanagement/disposal/components/disposalTemplate.json'),
//处方签
PRESCRIPTION: () => import('@/components/Print/Prescription.json'),
//处置单
DISPOSAL: () => import('@/components/Print/Disposal.json'),
//门诊日结
DAY_END: () => import('@/components/Print/DailyOutpatientSettlement.json'),
WESTERN_MEDICINE: () =>
import('@/views/pharmacymanagement/westernmedicine/components/templateJson.json'),
IN_HOSPITAL_DISPENSING: () =>
import('@/views/drug/inHospitalDispensing/components/templateJson.json'),
// 门诊挂号
OUTPATIENT_REGISTRATION: () => import('@/components/Print/OutpatientRegistration.json'),
// 门诊手术计费(含流程图)
OUTPATIENT_SURGERY_CHARGE: () => import('@/components/Print/OutpatientSurgeryCharge.json'),
//门诊收费
OUTPATIENT_CHARGE: () => import('@/components/Print/OutpatientBilling.json'),
//门诊病历
OUTPATIENT_MEDICAL_RECORD: () => import('@/components/Print/OutpatientMedicalRecord.json'),
//门诊输液贴
OUTPATIENT_INFUSION: () => import('@/components/Print/OutpatientInfusion.json'),
//手术记录
OPERATIVE_RECORD: () => import('@/components/Print/OperativeRecord.json'),
//红旗门诊病历
HQOUTPATIENT_MEDICAL_RECORD: () => import('@/components/Print/HQOutpatientMedicalRecord.json'),
//预交金
ADVANCE_PAYMENT: () => import('@/components/Print/AdvancePayment.json'),
//中药处方单
CHINESE_MEDICINE_PRESCRIPTION: () =>
import('@/components/Print/ChineseMedicinePrescription.json'),
//药房处方单
PHARMACY_PRESCRIPTION: () => import('@/components/Print/Pharmacy.json'),
//中药医生处方单
DOC_CHINESE_MEDICINE_PRESCRIPTION: () =>
import('@/components/Print/DocChineseMedicinePrescription.json'),
// ========== 新增模板原LODOP迁移==========
//腕带
WRIST_BAND: () => import('@/components/Print/WristBand.json'),
//分诊条
TRIAGE_TICKET: () => import('@/components/Print/TriageTicket.json'),
//输液标签
INJECT_LABEL: () => import('@/components/Print/InjectLabel.json'),
//床头卡
BED_CARD: () => import('@/components/Print/BedCard.json'),
//护理交接班
CHANGE_SHIFT_BILL: () => import('@/components/Print/ChangeShiftBill.json'),
//医嘱执行单
EXE_ORDER_SHEET: () => import('@/components/Print/ExeOrderSheet.json'),
//体温单
TEMPERATURE_SHEET: () => import('@/components/Print/TemperatureSheet.json'),
//会诊申请单
CONSULTATION: () => import('@/components/Print/Consultation.json'),
};
/**
* 极简打印方法
* @param {string} templateName 打印模板名称(常量或字符串)
* @param {Array|Object} data 打印数据
* @param {string} printerName 打印机名称(可选)
* @param {Object} options 打印选项(可选)
* @returns {Promise} 打印结果Promise
*/
export async function simplePrint(templateName, data, printerName, options = {}) {
try {
// 获取模板
const template = await loadTemplate(templateName);
// 执行打印,业务名称默认为模板名称
return await executePrint(data, template, printerName, options, templateName);
} catch (error) {
console.error('打印失败:', error);
throw error;
}
}
/**
* 加载打印模板
* @param {string} templateName 模板名称
* @returns {Promise<Object>} 模板对象
*/
async function loadTemplate(templateName) {
// 如果是常量形式,获取实际的键名
const templateKey = typeof templateName === 'symbol' ? templateName.description : templateName;
if (!TEMPLATE_MAP[templateKey]) {
throw new Error(`未找到打印模板: ${templateKey}`);
}
try {
const templateModule = await TEMPLATE_MAP[templateKey]();
return templateModule.default || templateModule;
} catch (error) {
console.error(`加载模板 ${templateKey} 失败:`, error);
throw error;
}
}
/**
* 带打印机选择的极简打印方法
* @param {string} templateName 打印模板名称
* @param {Array|Object} data 打印数据
* @param {Function} showPrinterDialog 显示打印机选择对话框的函数
* @param {Object} modal 消息提示对象
* @param {Function} callback 打印完成后的回调函数(可选)
* @returns {Promise} 打印结果Promise
*/
export async function simplePrintWithDialog(
templateName,
data,
showPrinterDialog,
modal,
callback
) {
try {
// 获取模板
const template = await loadTemplate(templateName);
// 执行打印
await selectPrinterAndPrint(data, template, showPrinterDialog, modal, callback, templateName);
} catch (error) {
modal.msgError(error.message || '打印失败');
if (callback) callback(error);
}
}
// 导出模板名称常量
export const PRINT_TEMPLATE = {
// CLINIC_CHARGE: 'CLINIC_CHARGE',
DAY_END: 'DAY_END',
WESTERN_MEDICINE: 'WESTERN_MEDICINE',
IN_HOSPITAL_DISPENSING: 'IN_HOSPITAL_DISPENSING',
//门诊挂号
OUTPATIENT_REGISTRATION: 'OUTPATIENT_REGISTRATION',
// 门诊手术计费
OUTPATIENT_SURGERY_CHARGE: 'OUTPATIENT_SURGERY_CHARGE',
//门诊收费
OUTPATIENT_CHARGE: 'OUTPATIENT_CHARGE',
//处方签
PRESCRIPTION: 'PRESCRIPTION',
//处置单
DISPOSAL: 'DISPOSAL',
//门诊病历
OUTPATIENT_MEDICAL_RECORD: 'OUTPATIENT_MEDICAL_RECORD',
//门诊输液贴
OUTPATIENT_INFUSION: 'OUTPATIENT_INFUSION',
//手术记录
OPERATIVE_RECORD: 'OPERATIVE_RECORD',
//红旗门诊病历
HQOUTPATIENT_MEDICAL_RECORD: 'HQOUTPATIENT_MEDICAL_RECORD',
//预交金
ADVANCE_PAYMENT: 'ADVANCE_PAYMENT',
//中药处方单
CHINESE_MEDICINE_PRESCRIPTION: 'CHINESE_MEDICINE_PRESCRIPTION',
//药房处方单
PHARMACY_PRESCRIPTION: 'PHARMACY_PRESCRIPTION',
//中药医生处方单
DOC_CHINESE_MEDICINE_PRESCRIPTION: 'DOC_CHINESE_MEDICINE_PRESCRIPTION',
// ========== 新增模板原LODOP迁移==========
//腕带
WRIST_BAND: 'WRIST_BAND',
//分诊条
TRIAGE_TICKET: 'TRIAGE_TICKET',
//输液标签
INJECT_LABEL: 'INJECT_LABEL',
//床头卡
BED_CARD: 'BED_CARD',
//护理交接班
CHANGE_SHIFT_BILL: 'CHANGE_SHIFT_BILL',
//医嘱执行单
EXE_ORDER_SHEET: 'EXE_ORDER_SHEET',
//体温单
TEMPERATURE_SHEET: 'TEMPERATURE_SHEET',
//会诊申请单
CONSULTATION: 'CONSULTATION',
};
/**
* 获取打印机列表
* @returns {Array} 打印机列表
*/
export function getPrinterList() {
try {
if (hiprint && hiprint.hiwebSocket && hiprint.hiwebSocket.connected) {
const printerList = hiprint.hiwebSocket.getPrinterList();
return printerList || [];
} else {
console.warn('打印服务未连接,返回空打印机列表');
return [];
}
} catch (error) {
console.error('获取打印机列表失败:', error);
return [];
}
}
import useUserStore from '@/store/modules/user';
import {ElMessage} from 'element-plus';
/**
* 获取当前登录用户ID
* @returns {string} 用户ID
*/
function getCurrentUserId() {
try {
// 从Pinia store中获取当前用户ID
const userStore = useUserStore();
return userStore.id || '';
} catch (e) {
console.error('获取用户ID失败:', e);
return '';
}
}
/**
* 生成打印机缓存键
* @param {string} businessName 打印业务名称
* @returns {string} 缓存键
*/
function getPrinterCacheKey(businessName) {
const userId = getCurrentUserId();
return `selectedPrinter_${businessName || 'default'}_${userId}`;
}
/**
* 从缓存获取上次选择的打印机
* @param {string} businessName 打印业务名称
* @returns {string} 打印机名称
*/
export function getCachedPrinter(businessName = 'default') {
const cacheKey = getPrinterCacheKey(businessName);
return localStorage.getItem(cacheKey) || '';
}
/**
* 保存打印机选择到缓存
* @param {string} printerName 打印机名称
* @param {string} businessName 打印业务名称
*/
export function savePrinterToCache(printerName, businessName = 'default') {
if (printerName) {
const cacheKey = getPrinterCacheKey(businessName);
localStorage.setItem(cacheKey, printerName);
}
}
/**
* 执行打印操作
* @param {Array} data 打印数据
* @param {Object} template 打印模板
* @param {string} printerName 打印机名称(可选)
* @param {Object} options 打印选项(可选)
* @param {string} businessName 打印业务名称(可选)
* @returns {Promise} 打印结果Promise
*/
export function executePrint(data, template, printerName, options = {}, businessName = 'default') {
return new Promise((resolve, reject) => {
try {
// 调试信息
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();
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('[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('[6] 创建打印模板失败:', templateError);
console.error('错误堆栈:', templateError.stack);
console.error('模板内容:', JSON.stringify(processedTemplate, null, 2));
throw new Error('打印模板创建失败: ' + templateError.message);
}
const printOptions = {
title: '打印标题',
height: 210,
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) {
// 客户端已连接且指定了打印机,使用静默打印
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('[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) {
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 || '打印过程中发生错误' });
}
});
}
/**
* 选择打印机并执行打印
* @param {Array} data 打印数据
* @param {Object} template 打印模板
* @param {Function} showPrinterDialog 显示打印机选择对话框的函数
* @param {Object} modal 消息提示对象
* @param {Function} callback 打印完成后的回调函数
* @param {string} businessName 打印业务名称(可选)
*/
export async function selectPrinterAndPrint(
data,
template,
showPrinterDialog,
modal,
callback,
businessName = 'default'
) {
try {
// 获取打印机列表
const printerList = getPrinterList();
if (printerList.length === 0) {
modal.msgWarning('未检测到可用打印机');
return;
}
// 获取缓存的打印机
const cachedPrinter = getCachedPrinter(businessName);
let selectedPrinter = '';
// 判断打印机选择逻辑
if (printerList.length === 1) {
selectedPrinter = printerList[0].name;
await executePrint(data, template, selectedPrinter, {}, businessName);
if (callback) callback();
} else if (cachedPrinter && printerList.some((printer) => printer.name === cachedPrinter)) {
selectedPrinter = cachedPrinter;
await executePrint(data, template, selectedPrinter, {}, businessName);
if (callback) callback();
} else {
// 调用显示打印机选择对话框的函数
showPrinterDialog(printerList, async (chosenPrinter) => {
try {
await executePrint(data, template, chosenPrinter, {}, businessName);
if (callback) callback();
} catch (error) {
modal.msgError(error.message || '打印失败');
}
});
}
} catch (error) {
modal.msgError(error.message || '获取打印机列表失败');
}
}
// 预览打印
export function previewPrint(elementDom) {
if (elementDom) {
// 初始化已在 main.js 中完成,无需重复调用
// hiprint.init();
const hiprintTemplate = new hiprint.PrintTemplate();
// printByHtml为预览打印
hiprintTemplate.printByHtml(elementDom, {});
} else {
ElMessage({
type: 'error',
message: '加载模版失败',
});
}
}
/**
* 打印门诊挂号收据(使用浏览器打印,模板与补打挂号一致)
* @param {Object} data 打印数据
* @param {Object} options 打印选项
* @returns {Promise} 打印结果 Promise
*/
export function printRegistrationReceipt(data, options = {}) {
return new Promise((resolve, reject) => {
try {
// 构建打印内容的 HTML
const printContent = `
<div class="print-header">
<div class="header-content">
<div class="document-title">门诊预约挂号凭条</div>
<div class="print-time">打印时间:${data.printTime || new Date().toLocaleString()}</div>
</div>
</div>
<div class="print-section">
<div class="section-title">患者基本信息</div>
<div class="info-row">
<span class="label">患者姓名:</span>
<span class="value">${data.patientName || '-'}</span>
</div>
<div class="info-row">
<span class="label">就诊卡号:</span>
<span class="value">${data.cardNo || data.busNo || '-'}</span>
</div>
<div class="info-row">
<span class="label">身份证号:</span>
<span class="value">${data.idCard ? maskIdCard(data.idCard) : '-'}</span>
</div>
<div class="info-row">
<span class="label">联系电话:</span>
<span class="value">${data.phone || '-'}</span>
</div>
</div>
<div class="print-section">
<div class="section-title">挂号信息</div>
<div class="info-row">
<span class="label">就诊科室:</span>
<span class="value">${data.organizationName || '-'}</span>
</div>
<div class="info-row">
<span class="label">医生姓名:</span>
<span class="value">${data.practitionerName || '-'}</span>
</div>
<div class="info-row">
<span class="label">挂号类型:</span>
<span class="value">${data.healthcareName || '-'}</span>
</div>
<div class="info-row">
<span class="label">挂号时间:</span>
<span class="value">${data.visitTime || data.chargeTime || '-'}</span>
</div>
</div>
<div class="print-section">
<div class="section-title">费用信息</div>
<table class="fee-table">
<thead>
<tr>
<th>项目</th>
<th>数量</th>
<th>单价</th>
<th>金额</th>
</tr>
</thead>
<tbody>
<tr>
<td>挂号费</td>
<td>1</td>
<td>¥${parseFloat(data.price || 0).toFixed(2)}</td>
<td>¥${parseFloat(data.price || 0).toFixed(2)}</td>
</tr>
${parseFloat(data.activityPrice || 0) > 0 ? `
<tr>
<td>诊疗费</td>
<td>1</td>
<td>¥${parseFloat(data.activityPrice || 0).toFixed(2)}</td>
<td>¥${parseFloat(data.activityPrice || 0).toFixed(2)}</td>
</tr>` : ''}
${parseFloat(data.medicalRecordFee || 0) > 0 ? `
<tr>
<td>病历费</td>
<td>1</td>
<td>¥${parseFloat(data.medicalRecordFee || 0).toFixed(2)}</td>
<td>¥${parseFloat(data.medicalRecordFee || 0).toFixed(2)}</td>
</tr>` : ''}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="total-label">合计:</td>
<td class="total-value">¥${parseFloat(data.totalPrice || data.amount || 0).toFixed(2)}</td>
</tr>
</tfoot>
</table>
</div>
<!-- 流水号显示在左下角 -->
<div class="serial-number-bottom-left">
<span class="serial-label">流水号:</span>
<span class="serial-value">${data.serialNo || data.encounterId || '-'}</span>
</div>
<div class="print-footer">
<div class="reminder">温馨提示:请妥善保管此凭条,就诊时请携带。</div>
</div>
<!-- 二维码区域 -->
<div class="qr-code-section">
<div class="qr-code-container">
<div id="qrcode-print" class="qrcode-print"></div>
<div class="qr-code-label">扫码查看挂号信息</div>
</div>
</div>
`;
// 创建新窗口用于打印
const printWindow = window.open('', '_blank');
if (!printWindow) {
reject(new Error('无法打开打印窗口,请检查浏览器弹窗设置'));
return;
}
// 写入打印内容
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>门诊预约挂号凭条</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; margin: 0; }
.print-header { margin-bottom: 20px; position: relative; }
.header-content { text-align: center; }
.document-title { font-size: 16px; font-weight: bold; margin-bottom: 10px; }
.print-time { font-size: 12px; color: #666; text-align: right; }
.print-section { margin-bottom: 20px; }
.section-title { font-size: 14px; font-weight: bold; margin-bottom: 10px; border-bottom: 1px solid #ddd; padding-bottom: 5px; }
.info-row { margin-bottom: 8px; font-size: 13px; }
.label { display: inline-block; width: 100px; font-weight: bold; }
.value { display: inline-block; }
.fee-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
.fee-table th, .fee-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.fee-table th { background-color: #f5f5f5; font-weight: bold; }
.total-label { font-weight: bold; text-align: right; }
.total-value { font-weight: bold; color: red; }
.serial-number-bottom-left { position: absolute; bottom: 20px; left: 20px; font-size: 14px; font-weight: bold; }
.serial-number-bottom-left .serial-label { font-weight: bold; margin-right: 5px; }
.serial-number-bottom-left .serial-value { font-weight: bold; color: #333; }
.print-content { position: relative; min-height: 500px; padding-bottom: 60px; }
.print-footer { margin-top: 20px; font-size: 12px; color: #666; }
.reminder { text-align: center; padding: 10px; background-color: #f9f9f9; border-radius: 4px; }
.qr-code-section { margin-top: 20px; display: flex; justify-content: center; align-items: center; padding: 15px; }
.qr-code-container { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.qrcode-print { width: 120px; height: 120px; }
.qr-code-label { font-size: 12px; color: #666; text-align: center; }
@media print { body { padding: 0; } .qr-code-section { page-break-inside: avoid; } }
</style>
</head>
<body>
<div class="print-content">
${printContent}
</div>
</body>
</html>
`);
printWindow.document.close();
printWindow.onload = function() {
setTimeout(() => {
printWindow.print();
resolve({ success: true, message: '打印窗口已打开' });
}, 250);
};
} catch (error) {
console.error('打印门诊挂号收据失败:', error);
reject(error);
}
});
}
/**
* 脱敏身份证号
* @param {string} idCard 身份证号
* @returns {string} 脱敏后的身份证号
*/
function maskIdCard(idCard) {
if (!idCard) return '';
if (idCard.length >= 10) {
const prefix = idCard.substring(0, 6);
const suffix = idCard.substring(idCard.length - 4);
const stars = '*'.repeat(Math.max(0, idCard.length - 10));
return prefix + stars + suffix;
} else if (idCard.length >= 6) {
const prefix = idCard.substring(0, 3);
const suffix = idCard.substring(idCard.length - 1);
return prefix + '*'.repeat(idCard.length - 4) + suffix;
}
return idCard;
}
// 默认导出简化的打印方法
export default {
print: simplePrint,
printWithDialog: simplePrintWithDialog,
TEMPLATE: PRINT_TEMPLATE,
executePrint,
selectPrinterAndPrint,
getPrinterList,
getCachedPrinter,
savePrinterToCache,
};