Percetakan ESC/POS dari Pelayar: Panduan Pembangun

Masalah Pencetakan Pelayar

Jika anda pernah cuba mencetak resit dari aplikasi web, anda tahu kesukarannya: window.print() membuka dialog cetak, memaparkan halaman sebagai PDF, dan tiada sokongan untuk arahan ESC/POS seperti potong automatik atau lebar kertas tersuai.

Untuk pencetak resit terma, ini adalah masalah besar. Anda memerlukan:

  • Pencetakan senyap — tiada dialog, tiada interaksi pengguna
  • Arahan ESC/POS — untuk potong automatik, teks tebal, penjajaran, kod bar
  • Pengekodan yang boleh dipercayai — UTF-8 ke halaman kod yang betul untuk pencetak anda
  • Sokongan merentas platform — Mac, Windows, Linux

Penyelesaiannya adalah jambatan WebSocket tempatan — aplikasi latar belakang kecil yang berjalan pada komputer pengguna, menerima tugas cetakan dari aplikasi web anda, dan menghantar arahan ESC/POS mentah ke pencetak.


Bagaimana Jambatan WebSocket Berfungsi

Aplikasi Web Anda → WebSocket (ws://localhost:8765) → Ejen Cetak → Pencetak Terma

Alirannya mudah:

  1. Aplikasi web anda membuka sambungan WebSocket ke ws://localhost:8765
  2. Anda menghantar muatan JSON yang menerangkan resit
  3. Ejen Cetak menukarnya kepada ESC/POS dan menghantarnya ke pencetak
  4. Pencetak mencetak secara senyap — tiada dialog, tiada interaksi pemacu

MenuForma Print Agent melaksanakan jambatan ini. Ia percuma, sumber terbuka, dan berjalan pada Mac, Windows, dan Linux.


Rujukan API

Sambungan

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

ws.onopen = () => {
  console.log('Ejen Cetak disambungkan');
};

ws.onerror = () => {
  console.log('Ejen Cetak tidak berjalan');
};

Semak Status Ejen

Hantar ping untuk mengesahkan ejen sedang berjalan:

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

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

Cetak Resit

const receipt = {
  type: 'print',
  printer: 'auto',   // atau IP tertentu seperti '192.168.1.100'
  data: {
    storeName: 'Restoran Saya',
    storeAddress: '123 Jalan Utama',
    orderNumber: '#1042',
    tableNumber: 'Meja 5',
    items: [
      { name: 'Pizza Margherita', qty: 1, price: 14.90 },
      { name: 'Air Berkarbonat', qty: 2, price: 3.50 },
    ],
    subtotal: 21.90,
    tax: 1.97,
    total: 23.87,
    paymentMethod: 'Kad',
    footer: 'Terima kasih kerana menjamu selera bersama kami!',
  }
};

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

Contoh Integrasi 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); // cuba semula
      };
      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 };
}

Integrasi Shopify

Untuk kedai Shopify, anda boleh mencetuskan pencetakan daripada cangkuk web Pesanan atau daripada sambungan pelayar:

// Dalam etalase Shopify atau sambungan pentadbir anda
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,
      }
    }));
  };
}

Konfigurasi Pencetak

Medan "printer" dalam muatan cetakan menerima:

Nilai Penerangan
"auto" Gunakan pencetak yang dikonfigurasi dalam tetapan Print Agent
"192.168.1.100" Sambung terus ke pencetak rangkaian melalui IP
"USB" Gunakan pencetak USB pertama yang dikesan

Pengendalian Ralat

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);
    // Tunjukkan UI sandaran atau cuba semula
  }
};

Mengesan Sama Ada Print Agent Dipasang

Sebelum menunjukkan fungsi cetakan dalam UI anda, semak sama ada ejen sedang berjalan:

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);
    };
  });
}

// Penggunaan
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
  // Tunjukkan gesaan muat turun
  window.open('/print-agent', '_blank');
}

Muat Turun Print Agent

MenuForma Print Agent adalah percuma dan tersedia untuk Mac, Windows, dan Linux. Ia menyokong pencetak terma USB, rangkaian, dan Bluetooth, dan melaksanakan API WebSocket penuh yang diterangkan dalam panduan ini.

Untuk dokumentasi API penuh dan kod sumber terbuka, lawati halaman Print Agent.

Related Articles

MenuForma Products