打印功能实现
概述
在微搭应用开发中,打印功能是许多业务场景(如订单管理、仓储物流、零售收银等)的核心需求。本文将详细介绍如何在微搭应用中实现打印机调用,包括网页打印、云打印服务集成以及小程序打印方案。
适用场景
- 订单打印:电商订单、外卖订单、配送单打印
- 票据打印:收据、发票、凭证打印
- 标签打印:商品标签、条码标签、物流标签
- 报表打印:业务报表、统计报表、审批单据
实现方案
方案一:网页打印(Web 应用)
适用于微搭 Web 应用,通过浏览器的原生打印 API 实现打印功能。
1. 基础打印实现
创建一个自定义方法 printContent:
export default async function ({ event, data }) {
// 触发浏览器打印对话框
window.print();
}
在按钮的点击事件中调用该方法即可触发打印。
2. 打印指定区域内容
如果只想打印页面中的特定区域,可以使用以下方法:
export default async function ({ event, data }) {
// 1. 获取要打印的内容元素
const printArea = document.getElementById('print-area');
if (!printArea) {
$w.utils.showToast({
title: "打印区域未找到",
icon: "error",
duration: 2000,
});
return;
}
// 2. 保存原始页面内容
const originalContent = document.body.innerHTML;
// 3. 替换页面内容为打印区域内容
document.body.innerHTML = printArea.innerHTML;
// 4. 触发打印
window.print();
// 5. 恢复原始页面内容
document.body.innerHTML = originalContent;
// 6. 重新加载页面(可选,用于恢复页面交互)
window.location.reload();
}
3. 使用打印样式优化
在应用的自定义 CSS 中添加打印专用样式:
/* 打印时隐藏不需要的元素 */
@media print {
/* 隐藏导航栏、按钮等非打印元素 */
.no-print,
.navbar,
.sidebar,
button {
display: none !important;
}
/* 打印区域样式优化 */
.print-area {
width: 100%;
padding: 20px;
font-size: 14px;
}
/* 强制分页 */
.page-break {
page-break-after: always;
}
/* 避免元素被截断 */
.no-break {
page-break-inside: avoid;
}
}
在需要打印的容器组件上添加 print-area 类名:
在微搭中的操作步骤:
- 选中需要打印的容器组件(如容器、表单容器等)
- 在右侧属性面板中,点击「组件配置」→「样式」
- 找到「className」配置项,输入
print-area - 同时设置组件的 ID 为
print-area(在「基础」配置中设置)
4. 高级打印功能
使用第三方库 print-js 实现更强大的打印功能:
步骤 1:引入 print-js 库
在应用设置中添加外部依赖:
https://printjs-4de6.kxcdn.com/print.min.js
https://printjs-4de6.kxcdn.com/print.min.css
步骤 2:实现打印方法
export default async function ({ event, data }) {
try {
// 打印 HTML 元素
printJS({
printable: 'print-area', // 元素 ID
type: 'html',
targetStyles: ['*'], // 保留所有样式
style: `
.print-area {
font-family: Arial, sans-serif;
font-size: 14px;
line-height: 1.6;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
`,
});
} catch (error) {
console.error('打印失败:', error);
$w.utils.showToast({
title: "打印失败,请重试",
icon: "error",
duration: 2000,
});
}
}
打印 PDF 文件:
export default async function ({ event, data }) {
// 假设 data.pdfUrl 是 PDF 文件的链接
const pdfUrl = data.pdfUrl || 'https://example.com/document.pdf';
printJS({
printable: pdfUrl,
type: 'pdf',
showModal: true, // 显示加载弹窗
});
}
打印图片:
export default async function ({ event, data }) {
const imageUrl = data.imageUrl || 'https://example.com/image.jpg';
printJS({
printable: imageUrl,
type: 'image',
header: '商品标签', // 可选的标题
});
}
打印 JSON 数据表格:
export default async function ({ event, data }) {
const tableData = [
{ name: '产品A', quantity: 10, price: 100 },
{ name: '产品B', quantity: 5, price: 200 },
{ name: '产品C', quantity: 8, price: 150 },
];
printJS({
printable: tableData,
type: 'json',
properties: ['name', 'quantity', 'price'], // 要显示的字段
header: '<h3>产品清单</h3>', // 表格标题
gridHeaderStyle: 'color: #000; border: 1px solid #ddd; padding: 8px;',
gridStyle: 'border: 1px solid #ddd; padding: 8px;',
});
}
方案二:云打印服务(推荐)
通过集成云打印服务(如飞鹅云打印、易联云等),实现远程打印和批量打印。
以飞鹅云打印为例
步骤 1:注册飞鹅云打印账号
访问 飞鹅云打印官网 注册账号,添加打印机设备。
步骤 2:创建云函数
在云开发控制台创建云函数 printOrder:
const cloud = require('@cloudbase/node-sdk');
const crypto = require('crypto');
const axios = require('axios');
// 飞鹅云打印配置
const FEI_E_CONFIG = {
user: 'your_feie_user', // 飞鹅云用户名
ukey: 'your_feie_ukey', // 飞鹅云 UKEY
sn: 'your_printer_sn', // 打印机编号
};
// 生成飞鹅云签名
function generateSign(params) {
const keys = Object.keys(params).sort();
const str = keys.map(key => `${key}=${params[key]}`).join('&') + FEI_E_CONFIG.ukey;
return crypto.createHash('sha1').update(str).digest('hex');
}
exports.main = async (event, context) => {
const { content, times = 1 } = event;
try {
// 构建打印内容(飞鹅云格式)
const printContent = `
<CB>订单详情</CB><BR>
<C>--------------------------------</C><BR>
订单号:${content.orderNo}<BR>
下单时间:${content.orderTime}<BR>
<C>--------------------------------</C><BR>
<B>商品清单</B><BR>
${content.items.map(item =>
`${item.name} x${item.quantity} ¥${item.price}<BR>`
).join('')}
<C>--------------------------------</C><BR>
<RIGHT>总计:<BOLD>¥${content.totalAmount}</BOLD></RIGHT><BR>
<C>================================</C><BR>
<C>感谢您的购买!</C><BR>
<QR>https://example.com/order/${content.orderNo}</QR>
`.trim();
// 调用飞鹅云打印 API
const params = {
user: FEI_E_CONFIG.user,
stime: Math.floor(Date.now() / 1000),
sig: '',
apiname: 'Open_printMsg',
sn: FEI_E_CONFIG.sn,
content: printContent,
times: times,
};
params.sig = generateSign(params);
const response = await axios.post(
'http://api.feieyun.cn/Api/Open/',
new URLSearchParams(params)
);
console.log('打印结果:', response.data);
return {
success: true,
data: response.data,
};
} catch (error) {
console.error('打印失败:', error);
return {
success: false,
error: error.message,
};
}
};
步骤 3:在微搭应用中调用
创建打印按钮的点击事件方法:
export default async function ({ event, data }) {
try {
// 1. 获取订单数据
const orderData = {
orderNo: 'ORD202603200001',
orderTime: new Date().toLocaleString(),
items: [
{ name: '商品A', quantity: 2, price: 50 },
{ name: '商品B', quantity: 1, price: 100 },
],
totalAmount: 200,
};
// 2. 调用云函数打印
const result = await $w.cloud.callFunction({
name: 'printOrder',
data: {
content: orderData,
times: 1, // 打印份数
},
});
if (result.success) {
$w.utils.showToast({
title: "打印成功",
icon: "success",
duration: 2000,
});
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('打印失败:', error);
$w.utils.showToast({
title: "打印失败: " + error.message,
icon: "error",
duration: 3000,
});
}
}
飞鹅云打印标签说明
| 标签 | 说明 | 示例 |
|---|---|---|
<BR> | 换行 | 商品名称<BR> |
<CB>文本</CB> | 居中加粗 | <CB>标题</CB> |
<C>文本</C> | 居中 | <C>内容</C> |
<B>文本</B> | 加粗 | <B>重要</B> |
<BOLD>文本</BOLD> | 加粗(同 B) | <BOLD>金额</BOLD> |
<RIGHT>文本</RIGHT> | 右对齐 | <RIGHT>¥100</RIGHT> |
<QR>内容</QR> | 二维码 | <QR>订单链接</QR> |
<BARCODE>内容</BARCODE> | 条形码 | <BARCODE>12345</BARCODE> |
<CUT> | 切纸 | <CUT> |
方案三:小程序打印
微信小程序环境下可以通过蓝牙连接打印机或使用云打印服务。
1. 蓝牙打印机连接
export default async function ({ event, data }) {
try {
// 1. 初始化蓝牙模块
await wx.openBluetoothAdapter();
// 2. 开始搜索蓝牙设备
await wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
});
$w.utils.showToast({
title: "正在搜索打印机...",
icon: "loading",
duration: 2000,
});
// 3. 监听蓝牙设备发现
wx.onBluetoothDeviceFound((res) => {
console.log('发现设备:', res.devices);
// 根据设备名称或 UUID 过滤打印机
const printers = res.devices.filter(device =>
device.name && device.name.includes('Printer')
);
if (printers.length > 0) {
// 连接第一个找到的打印机
connectPrinter(printers[0].deviceId);
}
});
} catch (error) {
console.error('蓝牙初始化失败:', error);
$w.utils.showToast({
title: "蓝牙初始化失败",
icon: "error",
duration: 2000,
});
}
}
// 连接打印机
async function connectPrinter(deviceId) {
try {
await wx.createBLEConnection({ deviceId });
$w.utils.showToast({
title: "打印机连接成功",
icon: "success",
duration: 2000,
});
// 连接成功后可以发送打印指令
// ...
} catch (error) {
console.error('连接打印机失败:', error);
}
}
2. 使用云打印服务
小程序中同样可以调用方案二中的云函数实现云打印。
最佳实践
1. 打印前预览
在打印前提供预览功能,让用户确认打印内容:
export default async function ({ event, data }) {
// 显示打印预览弹窗
$w.utils.showModal({
title: '打印预览',
content: '确认打印此订单吗?',
success: (res) => {
if (res.confirm) {
// 用户确认后执行打印
window.print();
}
},
});
}
2. 批量打印
实现批量打印多个订单:
export default async function ({ event, data }) {
const selectedOrders = $w.dataList1.selectedItems; // 获取选中的订单
if (!selectedOrders || selectedOrders.length === 0) {
$w.utils.showToast({
title: "请先选择要打印的订单",
icon: "error",
duration: 2000,
});
return;
}
// 批量调用云函数打印
const promises = selectedOrders.map(order =>
$w.cloud.callFunction({
name: 'printOrder',
data: { content: order },
})
);
try {
await Promise.all(promises);
$w.utils.showToast({
title: `成功打印 ${selectedOrders.length} 个订单`,
icon: "success",
duration: 2000,
});
} catch (error) {
console.error('批量打印失败:', error);
$w.utils.showToast({
title: "部分订单打印失败",
icon: "error",
duration: 2000,
});
}
}
3. 打印历史记录
将打印记录保存到数据库:
export default async function ({ event, data }) {
const app = await $w.cloud.getCloudInstance();
const db = app.database();
try {
// 打印前保存记录
await db.collection('print_history').add({
orderNo: data.orderNo,
printTime: new Date(),
printBy: $w.auth.currentUser.uid,
status: 'pending',
});
// 执行打印
const result = await $w.cloud.callFunction({
name: 'printOrder',
data: { content: data },
});
// 更新打印状态
await db.collection('print_history')
.where({ orderNo: data.orderNo })
.update({
status: result.success ? 'success' : 'failed',
result: result.data,
});
} catch (error) {
console.error('保存打印记录失败:', error);
}
}
4. 错误处理
完善的错误处理机制:
export default async function ({ event, data }) {
try {
// 验证打印数据
if (!data || !data.orderNo) {
throw new Error('订单数据不完整');
}
// 检查打印机状态(云打印)
const printerStatus = await checkPrinterStatus();
if (!printerStatus.online) {
throw new Error('打印机离线,请检查设备状态');
}
// 执行打印
const result = await $w.cloud.callFunction({
name: 'printOrder',
data: { content: data },
});
if (!result.success) {
throw new Error(result.error || '打印失败');
}
$w.utils.showToast({
title: "打印成功",
icon: "success",
duration: 2000,
});
} catch (error) {
console.error('打印错误:', error);
// 根据错误类型提供不同的提示
let errorMessage = '打印失败,请重试';
if (error.message.includes('离线')) {
errorMessage = '打印机离线,请检查设备';
} else if (error.message.includes('数据')) {
errorMessage = '订单数据异常,请刷新后重试';
}
$w.utils.showToast({
title: errorMessage,
icon: "error",
duration: 3000,
});
}
}
// 检查打印机状态
async function checkPrinterStatus() {
// 调用云函数查询打印机状态
const result = await $w.cloud.callFunction({
name: 'checkPrinter',
data: {},
});
return result.data;
}
常见问题
Q1: 网页打印时样式丢失怎么办?
A: 使用 @media print 定义专门的打印样式,并在 print-js 中使用 targetStyles: ['*'] 保留所有样式。
Q2: 如何实现静默打印(无需弹出对话框)?
A: 浏览器出于安全考虑,无法直接实现静默打印。可以使用云打印服务(如飞鹅云)实现远程静默打印。
Q3: 小程序如何连接网络打印机?
A: 小程序无法直接连接网络打印机,建议使用云打印服务或通过服务器中转。
Q4: 打印内容出现乱码怎么办?
A: 检查字符编码设置,确保使用 UTF-8 编码。对于云打印服务,查看对应文档的编码要求。
Q5: 如何实现打印队列管理?
A: 在云函数中维护打印队列,使用数据库记录打印任务状态,通过定时任务轮询处理。