面单打印
后端发出 ZPL 或快递方的 PDF,它就从对的仓库、对的标签机、按对的尺寸打出来。字节级一致的输出,真实可查的状态。
一个人在一张桌子上打一张面单很简单。三个仓库每天一千张,是另一个问题。
取快递方的面单、打开、选打印机、点打印。一天五十单它是瓶颈,一天五百单它是一个全职岗位。
4×6 的面单走通用 PDF 链路打出来变成 94%,条码就扫不出来了。字节级一致的 ZPL 是唯一可靠的答案。
你的发货服务连不上它,快递方的接口也连不上。总得有个东西在不开放网络的前提下把这段接起来。
仓库那台 Agent 保持连接常开,你这边只是一次 HTTPS 调用。
站点内任意一台电脑,Windows / macOS / Linux 都行。斑马、TSC、Godex、兄弟等已安装的标签机自动注册,各拿一个数字 printer_code。
用 content_type: raw 发 ZPL 拿到字节级一致的输出,或把快递方的 PDF 作为 content / content_url 发过去。按 printer_code 路由,A 仓永远不会打出 B 仓的面单。
带签名的 Webhook 推回 completed 或 failed 及原因码——没打出来的面单会变成一条告警,而不是一个丢掉的包裹。
const zpl = `^XA
^FO40,40^A0N,40,40^FDACME 仓储^FS
^FO40,100^BY3^BCN,120,Y,N,N^FD1Z999AA10123456784^FS
^FO40,260^A0N,30,30^FD收件地址:上海市徐汇区^FS
^XZ`;
await fetch('https://api.printbase.cloud/v1/print-jobs', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.PRINTBASE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
printer_code: warehouse.labelPrinterCode,
content_type: 'raw', // ZPL 直通斑马机
content: Buffer.from(zpl).toString('base64'),
copies: 1,
}),
});走 RAW ZPL 时由打印机自己渲染:不缩放、不过驱动,条码一次就能扫上。
只要是「某张面单必须从某个站点的某台机器出来、且由系统而不是人触发」的场景。
快递接口一返回面单,就直接打在负责这单的那个仓库,不用下载,也没有中间那一步人工。
一张订单表、一张打印机映射表、一个接口。订单所属仓库决定 printer_code,业务代码一行都不用改。
用带作用域的 API key 和组织,替多个客户打印,不必额外买一个多租户套餐。
退货面单和自提凭条在前台机上打出来,顾客还站在柜台前。
从 ^XA 到 ^XZ 原封不动到达打印机——条码、二维码、旋转、打印浓度都和模板渲染出来的一致,203 dpi 和 300 dpi 都支持。
把 PDF 作为 base64 或让 Agent 去下载的 URL 发过来即可。适合快递方只给 PDF、不给 ZPL 的情况。
DOWNLOAD_FAILED 说明签名面单链接在排队期间过期了;PRINTER_OFFLINE 说明该派人去打包台看看。不同的失败,不同的处理。
打印机、电脑、任务都归属于组织,一张 printer_code 映射表就足以把各个仓库分开。
可以。把 content_type 设为 raw,ZPL 用 base64 编码发送,由打印机原生渲染。这正是面单该走 RAW 的原因——没有任何环节会缩放或重采样你的条码。
用 content_type: pdf 发送,内联 base64 或给一个 content_url 让 Agent 去下载都行。如果是签名 URL,注意有效期要长过排队时间,否则会以 DOWNLOAD_FAILED 的形式失败。
只要装 Agent 的那台电脑能打的都支持。走 RAW 时打印机需要能理解你发的语言——斑马及兼容机的 ZPL、EPL、TSPL,或基于 ESC/POS 的标签机型。
用你自己的仓库到打印机映射表按 printer_code 路由;如果这些站点属于不同客户,再用独立组织和带作用域的 API key 隔离。
Webhook 会推送 print_job.completed 或 print_job.failed,带原因码、打印机名和电脑名。再加一个对未结束任务的定期对账扫描,就不会有任务无声消失。
有。每月 100 个打印任务、1 台电脑,永久免费,不用绑卡。