工厂 saas 项目,出货需要打印「发货单」、「质保卡」等
核心需求:自动打印、选择打印机、自定义打印模板设计
方案考虑
- window.print()
- 不能获取打印机列表,无法自动打印
- Lodop打印控件
- 授权费用高
- vue-plugin-hiprint
- 相比上面方案,自带模板设计,并且提供打印客户端,基本满足需求
- 缺点:hiprint 是闭源的,自定义模板不够灵活(没有点击拖拽元素触发的事件等等)
最后选择使用 vue-plugin-hiprint 开发初版。
功能点实现
隐藏不需要的参数
js
// 配置参数
hiprint.setConfig({
text: {
tabs: [], // 隐藏tabs分组
supportOptions: [
{
name: 'title',
hidden: true,
},
{
name: 'fontSize',
hidden: false,
},
],
},
});
查看所有参数:window.HIPRINT_CONFIG
注意:v0.0.56 无法隐藏参数的 tabs 分组,切到 v0.0.50
插入背景图片
背景图片只起参照作用,不参与打印
js
const insertBg = () => {
if (!state.currentTemplate.bgUrl) return
const bgImg = document.querySelector('#bg-img')
if (bgImg) {
bgImg.style.opacity = state.currentTemplate.bgAph / 100
bgImg.src = state.currentTemplate.bgUrl
} else {
const img = new Image()
img.id = 'bg-img'
img.style.display = 'block'
img.style.width = '100%'
img.style.height = '100%'
img.style.position = 'relative'
img.style.zIndex = '-1'
img.style['-webkit-user-drag'] = 'none'
img.style.opacity = state.currentTemplate.bgAph / 100
img.src = state.currentTemplate.bgUrl
img.onload = () => {
const printPaper = document.querySelector('.hiprint-printPaper')
printPaper.append(img)
}
}
}
打印预览
js
<!-- 打印预览弹窗 -->
<el-dialog class="preview-dialog" v-model="previewVisible" title="打印预览" top="10vh" width="1600">
<div class="preview-wrapper">
<div class="preview"></div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="previewVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
// 打印预览
const previewVisible = ref(false)
const printPreview = () => {
previewVisible.value = true
const html = hiprintTemplate.getHtml(printData)
// console.log('html: ', html)
do {
setTimeout(() => {
$('.preview').empty()
$('.preview').html(html)
}, 200)
return
} while ($('.preview').length <= 0)
}
/* 不同模板 间隙 */
.preview .hiprint-printTemplate {
background: #fff;
border-bottom: 10px solid #ccc;
}
/* 批量打印 间隙 */
.preview .hiprint-printTemplate .hiprint-printPanel:not(:last-of-type) {
border-bottom: 5px solid #ccc;
}
设置纸张大小和缩放
js
// 设置纸张大小
const handleChangePageSize = () => {
if (hiprintTemplate) {
hiprintTemplate.setPaper(state.currentTemplate.pageWidth, state.currentTemplate.pageHeight)
}
}
// 设置缩放
const handleChangeScale = () => {
hiprintTemplate.zoom(state.currentTemplate.scale / 100, false)
}
插入分页符
js
context.addPrintElementTypes('defaultModule', [
new hiprint.PrintElementTypeGroup('辅助', [
{
title: '分页符',
tid: 'defaultModule.pageBreak',
type: 'hline',
options: {
width: 200,
height: 10,
borderStyle: 'dotted',
borderColor: '#ff0000',
showInPage: 'none', // 打印隐藏
pageBreak: true, // 强制分页
},
},
]),
]);
// 针对始终隐藏的元素(分页符)
.alwaysHide {
background-color: unset !important;
}
横向打印
js
hiprintTemplate.print2(printData, {
printer: '',
title: '测试任务',
landscape: true, // 横向打印
pageSize: { // 纸张大小(必须)
width: state.currentTemplate.pageWidth * 1000,
height: state.currentTemplate.pageHeight * 1000,
},
});
注意:
- windows 系统可以直接修改打印机设置,而 mac 系统不行
- 打印机驱动会影响打印效果,必须安装原生驱动!
获取打印机列表
js
const getPrinterList = async () => {
setInterval(() => {
if (hiprint.hiwebSocket.opened) {
state.printerList = hiprint.hiwebSocket?.getPrinterList() || [];
console.log('打印机列表: ', state.printerList);
} else {
// 重新连接客户端
hiprint.hiwebSocket.setHost("http://localhost:17521")
}
}, 1000);
}
扩展:可以通过本地存储记住上次选择的打印机
批量自动打印
js
// 伪代码
const batchPrint = () => {
selectRows.forEach((row: any) => {
getOrderPrintData({ orderId: row.orderId }).then((res) => {
if (res.success) {
const printData = res.returnValue;
console.log('printData', printData);
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const printQueue = async () => {
for (const item of printItemListFilter) {
// 每次打印延迟5s,防止过快导致打印机接收不到
// await delay(5000)
let hiprintTemplate = new hiprint.PrintTemplate({
template: JSON.parse(item.templateContent),
});
hiprintTemplate.print2(printData, { printer: item.printerName, title: '订单出货打印' });
// 更新打印状态
const updateStatus = async (isSuccess: boolean) => {
};
// 发送任务到打印机成功
hiprintTemplate.on('printSuccess', async function (e) {
await updateStatus(true);
});
// 发送任务到打印机失败
hiprintTemplate.on('printError', async function (e) {
await updateStatus(false);
});
}
};
printQueue();
}
});
});
};
注意:mac 系统接收批量打印任务时必须要延迟,否则会丢包,而 winodws 系统不需要。当然为了保险和防止打印机过载工作,还是可以加上。
利用表格打印列表数据
js
// 注意点:隐藏边框、单元格合并、无数据处理、函数转义
{
tid: `customModule.productList`,
title: '产品列表',
type: 'table',
options: {
field: 'productList',
fields: [
{ text: '产品名称', field: 'name' },
{ text: '左上', field: 'upLeft' }
{ text: '右上', field: 'upRight' }
{ text: '左下', field: 'downLeft' }
{ text: '右下', field: 'downRight' }
],
// 隐藏边框
tableHeaderRepeat: 'none',
tableBorder: 'noBorder',
tableBodyRowBorder: 'noBorder',
tableBodyCellBorder: 'noBorder',
tableBodyRowHeight: 40, // 行高
width: 700, // 总宽
},
columns: [
[
{
title: '产品名称',
field: `name`,
rowspan: 2,
colspan: 1,
align: 'center',
},
{
title: '左上',
field: `upLeft`,
rowspan: 1,
colspan: 1,
align: 'center',
},
{
title: '右上',
field: `upRight`,
rowspan: 1,
colspan: 1,
align: 'center',
},
],
[
{
title: '左下',
field: `downLeft`,
rowspan: 1,
colspan: 1,
align: 'center',
// 函数都需要转义,防止保存时被 JSON.stringify() 过滤掉
renderFormatter: function (value, row, colIndex, options, rowIndex) {
if (!row.name) return ''
return `
<div>
<div style="padding: 4px;border-right: 1px solid;text-align: right;border-bottom: 1px solid;">${
row.upLeft || ' '
}</div>
<div style="padding: 4px;border-right: 1px solid;text-align: right;">${
row.downLeft || ' '
}</div>
</div>
`
}.toString(),
styler2: function (value, row, index, options) {
return { padding: 0 }
}.toString(),
},
{
title: '右下',
field: `downRight`,
rowspan: 1,
colspan: 1,
align: 'center',
renderFormatter: function (value, row, colIndex, options, rowIndex) {
if (!row.name) return ''
return `
<div>
<div style="padding: 4px;text-align: left;border-bottom: 1px solid;">${
row.upRight || ' '
}</div>
<div style="padding: 4px;text-align: left;">${
row.downRight || ' '
}</div>
</div>
`
}.toString(),
styler2: function (value, row, index, options) {
return { padding: 0 }
}.toString(),
},
],
],
}
局限:必须拖拽整个表格,无法将列单独拆开
关于打印客户端
mac 系统必须使用 x64 的安装包,否则打不开客户端
如果未连接到打印客户端并调用直接打印,会弹出 alert ,建议在触发打印的功能按钮上根据 hiprint.hiwebSocket.opened 做禁用和悬浮提示
可以将官网的安装包放到服务器上,方便用户直接下载
最后
参考学习
欢迎交流沟通。