从浏览器进行ESC/POS打印:开发者指南

浏览器打印问题

如果你曾尝试从网络应用打印收据,你就会明白其中的痛苦:window.print()会打开一个打印对话框,将页面渲染为PDF,并且完全不支持ESC/POS命令,例如自动切纸或自定义纸张宽度。

对于热敏收据打印机来说,这是一个致命的缺陷。你需要:

  • 静默打印 — 无对话框,无用户交互
  • ESC/POS命令 — 用于自动切纸、粗体文本、对齐、条形码
  • 可靠编码 — UTF-8到打印机正确的代码页
  • 跨平台支持 — Mac、Windows、Linux

解决方案是本地WebSocket桥接——一个在用户计算机上运行的小型后台应用程序,它接受来自你的网络应用的打印任务,并将原始ESC/POS命令发送到打印机。


WebSocket桥接的工作原理

你的网络应用 → WebSocket (ws://localhost:8765) → 打印代理 → 热敏打印机

流程很简单:

  1. 你的网络应用打开一个WebSocket连接到ws://localhost:8765
  2. 你发送一个描述收据的JSON负载
  3. 打印代理将其转换为ESC/POS并发送到打印机
  4. 打印机静默打印——无对话框,无驱动程序交互

MenuForma Print Agent实现了这个桥接。它是免费、开源的,并且可以在Mac、Windows和Linux上运行。


API参考

连接

const ws = new WebSocket('ws://localhost:8765');

ws.onopen = () => {
  console.log('Print Agent connected');
};

ws.onerror = () => {
  console.log('Print Agent not running');
};

检查代理状态

发送一个ping来验证代理是否正在运行:

ws.send(JSON.stringify({ type: 'ping' }));

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === 'pong') {
    console.log('Agent version:', data.version);
  }
};

打印收据

const receipt = {
  type: 'print',
  printer: 'auto',   // 或特定IP,如 '192.168.1.100'
  data: {
    storeName: 'My Restaurant',
    storeAddress: '123 Main St',
    orderNumber: '#1042',
    tableNumber: 'Table 5',
    items: [
      { name: 'Margherita Pizza', qty: 1, price: 14.90 },
      { name: 'Sparkling Water', qty: 2, price: 3.50 },
    ],
    subtotal: 21.90,
    tax: 1.97,
    total: 23.87,
    paymentMethod: 'Card',
    footer: 'Thank you for dining with us!',
  }
};

ws.send(JSON.stringify(receipt));

React集成示例

import { useEffect, useRef, useCallback, useState } from 'react';

function usePrintAgent() {
  const wsRef = useRef(null);
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    const connect = () => {
      const ws = new WebSocket('ws://localhost:8765');
      ws.onopen = () => setConnected(true);
      ws.onclose = () => {
        setConnected(false);
        setTimeout(connect, 3000); // retry
      };
      wsRef.current = ws;
    };
    connect();
    return () => wsRef.current?.close();
  }, []);

  const print = useCallback((receiptData) => {
    if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
      throw new Error('Print Agent not connected');
    }
    wsRef.current.send(JSON.stringify({ type: 'print', data: receiptData }));
  }, []);

  return { connected, print };
}

Shopify集成

对于Shopify商店,你可以从订单webhook或浏览器扩展触发打印:

// 在你的Shopify店面或管理扩展中
async function printShopifyOrder(order) {
  const ws = new WebSocket('ws://localhost:8765');
  
  ws.onopen = () => {
    ws.send(JSON.stringify({
      type: 'print',
      data: {
        storeName: order.shop_name,
        orderNumber: order.name,
        items: order.line_items.map(item => ({
          name: item.title,
          qty: item.quantity,
          price: parseFloat(item.price),
        })),
        total: parseFloat(order.total_price),
        paymentMethod: order.payment_gateway,
      }
    }));
  };
}

打印机配置

打印负载中的“printer”字段接受:

描述
"auto" 使用Print Agent设置中配置的打印机
"192.168.1.100" 通过IP直接连接到网络打印机
"USB" 使用第一个检测到的USB打印机

错误处理

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.type === 'print_success') {
    console.log('Printed successfully');
  } else if (response.type === 'print_error') {
    console.error('Print failed:', response.error);
    // 显示备用UI或重试
  }
};

检测Print Agent是否已安装

在UI中显示打印功能之前,请检查代理是否正在运行:

async function isPrintAgentAvailable() {
  return new Promise((resolve) => {
    const ws = new WebSocket('ws://localhost:8765');
    const timeout = setTimeout(() => {
      ws.close();
      resolve(false);
    }, 1000);
    ws.onopen = () => {
      clearTimeout(timeout);
      ws.close();
      resolve(true);
    };
    ws.onerror = () => {
      clearTimeout(timeout);
      resolve(false);
    };
  });
}

// 用法
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
  // 显示下载提示
  window.open('/print-agent', '_blank');
}

下载Print Agent

MenuForma Print Agent是免费的,适用于Mac、Windows和Linux。它支持USB、网络和蓝牙热敏打印机,并实现了本指南中描述的完整WebSocket API。

如需完整的API文档和开源代码,请访问Print Agent页面

Related Articles

MenuForma Products