# 电子面单打印组件
电子面单打印组件运行在商家本地电脑上,应用端通过 WebSocket 协议与之通信,完成面单的预览和打印。无论是使用商家后台打单,还是 ISV 打单软件,均需安装此组件。
# 下载与安装
打印组件支持 Windows(64 位 / 32 位)和 Mac 系统,请前往使用指南页面获取最新安装包:详见成长中心:微信小店「打印组件」使用指南
安装注意事项:
- Windows 安装时提示「需要 64 位系统」,请改用 32 位安装包
- 请务必使用最新版组件。旧版未卸载直接安装新版会导致电脑上存在两个打印组件,旧版打印新面单可能出现差异,建议先卸载旧版本
- 安装完成后需保持打印组件处于运行状态
# 使用前准备
打印面单前需按以下顺序完成设置:
- 开通电子面单:在微信小店后台绑定快递公司网点/月结账号
- 设置快递面单模板:选择或自定义面单打印样式
- 下载安装并运行打印组件:安装后保持运行状态
- 完成打印设置:确认打印机连接正常
# 对接流程总览
前端通过 WebSocket 与打印组件通信,完整流程如下:
其中前 4 步(连接 → 校验版本 → 获取打印机 → 预览/打印)均通过 WebSocket 指令完成,后 2 步(打印成功通知 → 订单发货)回到服务端 API 调用。下面逐步说明每个指令的用法。
# 通信机制
打印组件安装后会在本地启动一个 WebSocket Server,监听 127.0.0.1:12705。前端页面作为 WebSocket Client 连接上去,双方通过 JSON 消息通信。
通信模式为请求-响应:前端发送一条 JSON 指令,打印组件处理后返回一条 JSON 结果,通过 requestID 字段匹配请求和响应。
关键特性:
- 仅限本机通信:地址为
127.0.0.1,打印组件必须安装在与前端页面同一台电脑上 - 长连接复用:连接建立后可反复发送多条指令,无需每次重连
- 所有指令共用同一个连接:获取打印机列表、预览、打印等操作都在同一条 WebSocket 连接上完成
- 通过
command字段区分指令类型:getPrinterList/getAppInfo/preview/print - 通过
requestID字段匹配响应:前端为每条指令分配唯一 ID,打印组件在响应中原样返回
# Step 1:连接打印组件
打印组件监听本地固定端口,通过 WebSocket 建立连接:
const ws = new WebSocket('ws://127.0.0.1:12705');
ws.onopen = () => {
console.log('与打印组件建立连接成功');
};
ws.onerror = (err) => {
console.error('连接失败,请检查打印组件是否已启动');
};
连接失败时检查:1)打印组件是否已在本机启动;2)本地防火墙是否放行 12705 端口。
# Step 2:获取打印机列表
连接成功后,查询本机已连接的打印设备:
ws.send(JSON.stringify({
requestID: 'req_001',
command: 'getPrinterList'
}));
ws.onmessage = (e) => {
const resp = JSON.parse(e.data || '{}');
if (resp.command === 'getPrinterList') {
// resp.printerList: [{ name: '_KM_202_NEW_', displayName: 'KM-202(NEW)', status: 3 }]
console.log('可用打印机:', resp.printerList);
}
};
返回的 printerList 中,name 用于后续打印指令的 printer 参数。
# Step 3:预览面单
正式打印前可先预览,返回预览图片 URL:
ws.send(JSON.stringify({
command: 'preview',
requestID: 'req_003',
taskList: [{
taskID: 'task_001',
printInfo: '<获取打印报文接口返回的 print_info>',
printNum: { curNum: 1, sumNum: 1 }
}]
}));
// 返回:{ previewUrl: 'xxx' }
# print_info 如何传递给打印组件
print_info 由服务端 API 返回,但打印组件在前端本地通过 WebSocket 工作,两者不在同一侧。传递路径如下:
print_info 本身是一段不透明的字符串(包含面单的布局、收寄件信息、条码等渲染数据),开发者无需解析其内容,只需原样透传:
- 服务端调用 [API] 电子面单取号 / ewaybill_createorder(传了
template_id时直接返回)或 [API] 获取打印报文 / get_print_content,从响应中取出print_info - 服务端通过自己的业务接口(如 HTTP API)将
print_info返回给前端页面 - 前端拿到后,直接放入下方打印指令的
taskList[].printInfo字段发送即可
# Step 4:打印面单
核心打印指令,将 print_info 发送给打印组件出单:
ws.send(JSON.stringify({
command: 'print',
version: '2.0',
requestID: 'req_004',
printType: 1, // 1: 固定高度面单;2: 自定义 HTML 内容
size: { width: 76, height: 130 }, // 非标准尺寸或 printType=2 时必传(单位 mm)
printer: '_KM_202_NEW_', // 从 getPrinterList 获取的打印机 name
taskList: [{
taskID: 'task_001',
printInfo: '<获取打印报文接口返回的 print_info>',
printNum: { curNum: 1, sumNum: 1 },
splitControl: 0, // 0: 自动分页(默认);1: 禁止分页;2: 强制分页
showDeliveryLogo: 1 // 0: 不展示快递logo;1: 展示(默认)
}]
}));
主结构体参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
command | String | 是 | 固定为 'print' |
version | String | 是 | 固定为 '2.0' |
requestID | String | 是 | 请求唯一标识,调用方保证唯一 |
printType | Number | 是 | 1:打印固定高度面单(标准 130×76mm);2:打印自定义 HTML 内容(printInfo 需为 base64 编码的 HTML) |
size | Object | 否 | 纸张尺寸 { width, height }(单位 mm)。printType=2 或面单尺寸非标准 130×76mm 时必传 |
printer | String | 否 | 打印机标识,对应 getPrinterList 返回的 name 字段 |
taskList | Array | 是 | 打印任务列表,每个元素为一个 PrintTask |
PrintTask 参数(taskList 数组中的对象):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
taskID | String | 是 | 任务唯一标识,调用方保证唯一 |
printInfo | String | 是 | 打印报文。printType=1 时为接口返回的 print_info;printType=2 时为 base64 格式的 HTML |
printNum | Object | 是 | 打印计数:{ curNum: 当前张数, sumNum: 总张数 } |
splitControl | Number | 否 | 分页控制,默认 0。0:自动分页 / 1:禁止分页 / 2:强制分页(内容在第二页) |
showDeliveryLogo | Number | 否 | 快递公司 logo,默认 1。0:不展示 / 1:展示 |
customInfo | Object | 否 | 自定义模板:templateUrl(模板 URL)+ data(模板数据),详见下方「自定义模板详解」 |
extendData | Object | 否 | 覆盖寄件人信息:sender.address(provinceName / cityName / countyName / detailInfo)、sender.userName、sender.telNumber |
# 自定义模板详解
打印指令的 customInfo 参数支持自定义面单下方的附加内容区域(如商品清单、店铺 logo、条形码等)。模板引擎基于 Mustache.js。
官方参考模板:https://mmec-shop-1258344707.cos.ap-shanghai.myqcloud.com/shop/public/2023-11-10/a80c0110-3fb8-4190-bdcc-10124b7dd0ce.html(可直接访问查看模板结构)
# 模板语法
| 语法 | 说明 | 示例 |
|---|---|---|
{{name}} | 变量渲染(HTML 转义) | {{shopName}} → 测试小店 |
{{{name}}} | 变量渲染(不转义 HTML) | {{{description}}} → 商品<br>描述 |
{{#list}}...{{/list}} | 循环渲染列表 | 遍历商品列表 |
{{^list}}...{{/list}} | 取反(列表为空时显示) | 无商品时显示提示 |
# 条形码与二维码
模板中可使用专用标签生成条形码和二维码:
条形码:
<bar-code content="{{productBarcode}}" width="300" height="60"
config='{"displayValue": true, "textAlign": "left", "format": "auto"}'></bar-code>
config 完整配置(基于 JsBarcode):
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
format | String | "auto" (CODE128) | 条码类型 |
width | Number | 2 | 单条条码宽度 |
height | Number | 100 | 条码高度 |
displayValue | Boolean | false | 条码下方是否显示值 |
text | String | undefined | 覆盖条码下方显示的文本内容 |
fontOptions | String | "" | 字体样式:"bold" / "italic" / "bold italic" |
font | String | "monospace" | 字体名称 |
textAlign | String | "center" | 文字水平位置:"left" / "center" / "right" |
textPosition | String | "bottom" | 文字垂直位置:"top" / "bottom" |
textMargin | Number | 2 | 条码与文字间距 |
fontSize | Number | 20 | 文字字号 |
background | String | "#ffffff" | 背景颜色 |
lineColor | String | "#000000" | 条码颜色 |
margin | Number | 10 | 四周通用间距 |
marginTop | Number | undefined | 上方间距(优先级高于 margin) |
marginBottom | Number | undefined | 下方间距(优先级高于 margin) |
marginLeft | Number | undefined | 左侧间距(优先级高于 margin) |
marginRight | Number | undefined | 右侧间距(优先级高于 margin) |
二维码:
<qr-code content="{{productQRcode}}" width="120" height="120"></qr-code>
# 完整模板示例
<div>
<div style="font-weight: 700;">店铺名称 {{shopName}}</div>
{{#productInfo}}
<div>{{name}}, 数量: {{count}}, 编码: {{code}}, {{{description}}}</div>
{{/productInfo}}
<img src="{{imgSrc}}" width="300" height="50"/>
<bar-code content="{{productBarcode}}" width="300" height="60"
config='{"displayValue": true}'></bar-code>
<qr-code content="{{productQRcode}}" width="120" height="120"></qr-code>
</div>
对应 customInfo.data(templateUrl 指向上方 HTML 模板的托管地址):
customInfo: {
templateUrl: 'https://mmec-shop-1258344707.cos.ap-shanghai.myqcloud.com/shop/public/2023-11-10/a80c0110-3fb8-4190-bdcc-10124b7dd0ce.html', // 官方参考模板,实际使用时替换为自己的模板地址
data: {
shopName: "测试小店",
productInfo: [
{ name: "商品1", count: 1, code: "SKU001", description: "商品描述" },
{ name: "商品2", count: 2, code: "SKU002", description: "商品<br>描述" }
],
imgSrc: "https://example.com/logo.png",
productBarcode: "BARCODE001",
productQRcode: "https://example.com/product"
}
}
# 子母单打印
大件商品需拆分多个包裹时使用子母单。支持子母单的快递公司详见 [API] 电子面单子件追加 / ewaybill_addsuborder。
# 取号方式
两种方式获取子母单:
- 取号时一次性获取:调用 [API] 电子面单取号 / ewaybill_createorder 时传入
package_quantity参数(2~300),一次性获取母单号 + N 个子单号 - 取号后逐步追加:先正常取号获取母单,再通过 [API] 电子面单子件追加 / ewaybill_addsuborder 逐步追加子件
# 版本要求
打印组件需 1.52.0 及以上版本才支持子母单打印样式。建议打印前通过 getAppInfo 指令校验版本号,低版本需提示用户升级:
ws.send(JSON.stringify({
requestID: 'req_version',
command: 'getAppInfo'
}));
// 返回:{ appInfo: { version: '1.52.0' } }
# print_info 与子母单打印
以下三个接口都可以获取到子母单打印所需的 print_info:
- [API] 电子面单取号 / ewaybill_createorder
- [API] 电子面单子件追加 / ewaybill_addsuborder
- [API] 获取打印报文 / get_print_content
将 print_info 传给 1.52.0+ 打印组件后,默认会把所有子母单都打印出来(一个打印任务,输出多张面单)。
# 单独打印某个子单
如果只需打印某个特定子单,调用 [API] 获取打印报文 / get_print_content 时传入 sub_waybill_id(子单运单号),返回的 print_info 仅包含该子单,传入打印组件后只会打印该子单的面单。
# Step 5:打印结果处理与状态流转
打印指令发出后,通过 onmessage 监听打印组件返回的结果,根据成功或失败执行不同的后续操作。
ws.onmessage = (e) => {
const resp = JSON.parse(e.data || '{}');
if (resp.command === 'print') {
resp.results.forEach(r => {
if (r.success) {
console.log(`任务 ${r.taskID} 打印成功`);
// 1. 调用服务端 API:打印成功通知(ewaybill_printorder)
// 2. 调用服务端 API:订单发货(senddelivery)
} else {
console.error(`任务 ${r.taskID} 失败:${r.failureReason}`);
// 排查打印机状态后重试
}
});
}
};
返回参数:
| 参数 | 类型 | 说明 |
|---|---|---|
requestID | String | 与请求中的 requestID 一致 |
command | String | 固定为 "print" |
results | Array | 打印结果列表,与请求中 taskList 一一对应 |
results[].taskID | String | 与请求中的 taskID 一致 |
results[].success | Boolean | true 打印成功 / false 打印失败 |
results[].failureReason | String | 失败原因,成功时为空字符串 |
打印成功后必须完成两步状态流转:
- 通知平台出单结果:调用 [API] 打印成功通知 / ewaybill_printorder 扭转电子面单状态。批量场景使用 [API] 批量打印通知 / ewaybill_batchprintorder
- 完成订单发货:调用 [API] 订单发货 / senddelivery 将快递单号绑定到订单,流转订单状态为已发货
如果漏掉第 1 步,平台无法感知面单已出单;如果漏掉第 2 步,订单会一直停留在待发货状态。
# WebSocket 指令速查
| 指令 command | 功能 | 关键参数 |
|---|---|---|
getPrinterList | 获取打印机列表 | — |
getAppInfo | 获取版本号 | — |
preview | 预览面单 | taskList[].printInfo |
print | 打印面单 | taskList[].printInfo、printType、printer |