การพิมพ์ ESC/POS จากเบราว์เซอร์: คู่มือสำหรับนักพัฒนา

ปัญหาการพิมพ์บนเบราว์เซอร์

หากคุณเคยลองพิมพ์ใบเสร็จจากเว็บแอป คุณจะรู้ถึงความยุ่งยาก: window.print() จะเปิดกล่องโต้ตอบการพิมพ์, แสดงผลหน้าเว็บเป็น PDF, และไม่มีการรองรับคำสั่ง ESC/POS เช่น การตัดอัตโนมัติ หรือการกำหนดความกว้างกระดาษเองเลย

สำหรับเครื่องพิมพ์ใบเสร็จความร้อน นี่คือปัญหาใหญ่ คุณจำเป็นต้องมี:

  • การพิมพ์แบบเงียบ — ไม่มีกล่องโต้ตอบ ไม่มีการโต้ตอบจากผู้ใช้
  • คำสั่ง ESC/POS — สำหรับการตัดอัตโนมัติ, ตัวหนา, การจัดตำแหน่ง, บาร์โค้ด
  • การเข้ารหัสที่เชื่อถือได้ — UTF-8 ไปยังหน้าโค้ดที่ถูกต้องสำหรับเครื่องพิมพ์ของคุณ
  • การรองรับข้ามแพลตฟอร์ม — Mac, Windows, Linux

ทางออกคือ WebSocket bridge ในเครื่อง — แอปพลิเคชันพื้นหลังขนาดเล็กที่ทำงานบนคอมพิวเตอร์ของผู้ใช้ รับงานพิมพ์จากเว็บแอปของคุณ และส่งคำสั่ง ESC/POS ดิบไปยังเครื่องพิมพ์


WebSocket Bridge ทำงานอย่างไร

Your Web App  →  WebSocket (ws://localhost:8765)  →  Print Agent  →  Thermal Printer

ขั้นตอนง่ายๆ:

  1. เว็บแอปของคุณเปิดการเชื่อมต่อ WebSocket ไปยัง ws://localhost:8765
  2. คุณส่ง JSON payload ที่อธิบายใบเสร็จ
  3. Print Agent แปลงเป็น 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');
};

ตรวจสอบสถานะ Agent

ส่ง ping เพื่อตรวจสอบว่า Agent กำลังทำงานอยู่:

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',   // or specific IP like '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, เครือข่าย และ Bluetooth และใช้งาน WebSocket API เต็มรูปแบบตามที่อธิบายไว้ในคู่มือนี้

สำหรับเอกสารประกอบ API ฉบับเต็มและซอร์สโค้ดโอเพนซอร์ส โปรดเยี่ยมชม หน้า Print Agent

Related Articles

MenuForma Products