Vấn đề in ấn trên trình duyệt
Nếu bạn đã từng cố gắng in một hóa đơn từ một ứng dụng web, bạn sẽ hiểu nỗi đau: window.print() mở một hộp thoại in, hiển thị trang dưới dạng PDF và không hỗ trợ các lệnh ESC/POS như tự động cắt hoặc chiều rộng giấy tùy chỉnh.
Đối với máy in hóa đơn nhiệt, đây là một vấn đề lớn. Bạn cần:
- In không tiếng ồn — không hộp thoại, không tương tác người dùng
- Lệnh ESC/POS — để tự động cắt, in đậm, căn chỉnh, mã vạch
- Mã hóa đáng tin cậy — UTF-8 sang trang mã chính xác cho máy in của bạn
- Hỗ trợ đa nền tảng — Mac, Windows, Linux
Giải pháp là một cầu nối WebSocket cục bộ — một ứng dụng nền nhỏ chạy trên máy tính của người dùng, chấp nhận các lệnh in từ ứng dụng web của bạn và gửi các lệnh ESC/POS thô đến máy in.
Cách thức hoạt động của cầu nối WebSocket
Ứng dụng web của bạn → WebSocket (ws://localhost:8765) → Print Agent → Máy in nhiệt
Quy trình rất đơn giản:
- Ứng dụng web của bạn mở kết nối WebSocket tới ws://localhost:8765
- Bạn gửi một payload JSON mô tả hóa đơn
- Print Agent chuyển đổi nó sang ESC/POS và gửi đến máy in
- Máy in in không tiếng ồn — không hộp thoại, không tương tác với trình điều khiển
MenuForma Print Agent triển khai cầu nối này. Nó miễn phí, mã nguồn mở và chạy trên Mac, Windows và Linux.
Tham khảo API
Kết nối
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
console.log('Print Agent connected');
};
ws.onerror = () => {
console.log('Print Agent not running');
};
Kiểm tra trạng thái Agent
Gửi một ping để xác minh agent đang chạy:
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);
}
};
In hóa đơn
const receipt = {
type: 'print',
printer: 'auto', // hoặc IP cụ thể như '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));
Ví dụ tích hợp 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 }; }
---
## Tích hợp Shopify
Đối với các cửa hàng Shopify, bạn có thể kích hoạt in từ một webhook Đơn hàng hoặc từ một tiện ích mở rộng trình duyệt:
````javascript
// Trong cửa hàng Shopify hoặc tiện ích mở rộng quản trị của bạn
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,
}
}));
};
}
Cấu hình máy in
Trường "printer" trong tải trọng in chấp nhận:
| Giá trị | Mô tả |
|---|---|
| "auto" | Sử dụng máy in được cấu hình trong cài đặt Print Agent |
| "192.168.1.100" | Kết nối trực tiếp với máy in mạng bằng IP |
| "USB" | Sử dụng máy in USB được phát hiện đầu tiên |
Xử lý lỗi
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);
// Hiển thị giao diện dự phòng hoặc thử lại
}
};
Phát hiện xem Print Agent đã được cài đặt chưa
Trước khi hiển thị chức năng in trong giao diện người dùng của bạn, hãy kiểm tra xem tác nhân có đang chạy không:
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);
};
});
}
// Cách sử dụng
const agentAvailable = await isPrintAgentAvailable();
if (!agentAvailable) {
// Hiển thị lời nhắc tải xuống
window.open('/print-agent', '_blank');
}
Tải xuống Print Agent
MenuForma Print Agent miễn phí và có sẵn cho Mac, Windows và Linux. Nó hỗ trợ các máy in nhiệt USB, mạng và Bluetooth, đồng thời triển khai API WebSocket đầy đủ được mô tả trong hướng dẫn này.
Để có tài liệu API đầy đủ và mã nguồn mở, hãy truy cập trang Print Agent.
Related Articles
- The UK Hospitality Labor Crisis: Why QR Menus Are the Key to Survival
- 2025 US Restaurant Tech Trends: The Widespread Adoption of Digital Ordering and Cloud Platforms
- The Unstoppable Boom of Online Food Delivery: How US and UK Restaurants Can Capture a Trillion-Dollar Market