Проблема печати в браузере
Если вы когда-либо пытались распечатать чек из веб-приложения, вы знаете эту боль: window.print() открывает диалоговое окно печати, отображает страницу как PDF и не поддерживает команды ESC/POS, такие как автообрезка или пользовательская ширина бумаги.
Для термопринтеров чеков это критично. Вам нужны:
- Бесшумная печать — без диалогового окна, без взаимодействия с пользователем
- Команды ESC/POS — для автообрезки, жирного текста, выравнивания, штрих-кодов
- Надежное кодирование — UTF-8 в правильную кодовую страницу для вашего принтера
- Кроссплатформенная поддержка — Mac, Windows, Linux
Решение — это локальный WebSocket-мост — небольшое фоновое приложение, которое работает на компьютере пользователя, принимает задания на печать из вашего веб-приложения и отправляет необработанные команды ESC/POS на принтер.
Как работает WebSocket-мост
Ваше веб-приложение → WebSocket (ws://localhost:8765) → Агент печати → Термопринтер
Поток прост:
- Ваше веб-приложение открывает WebSocket-соединение с ws://localhost:8765
- Вы отправляете JSON-сообщение, описывающее чек
- Агент печати преобразует его в ESC/POS и отправляет на принтер
- Принтер печатает бесшумно — без диалогового окна, без взаимодействия с драйвером
MenuForma Print Agent реализует этот мост. Он бесплатный, с открытым исходным кодом и работает на Mac, Windows и Linux.
Справочник API
Соединение
const ws = new WebSocket('ws://localhost:8765');
ws.onopen = () => {
console.log('Агент печати подключен');
};
ws.onerror = () => {
console.log('Агент печати не запущен');
};
Проверка статуса агента
Отправьте ping, чтобы убедиться, что агент запущен:
ws.send(JSON.stringify({ type: 'ping' }));
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') {
console.log('Версия агента:', data.version);
}
};
Печать чека
const receipt = {
type: 'print',
printer: 'auto', // или конкретный IP, например '192.168.1.100'
data: {
storeName: 'Мой Ресторан',
storeAddress: 'Ул. Главная, 123',
orderNumber: '#1042',
tableNumber: 'Стол 5',
items: [
{ name: 'Пицца Маргарита', qty: 1, price: 14.90 },
{ name: 'Газированная вода', qty: 2, price: 3.50 },
],
subtotal: 21.90,
tax: 1.97,
total: 23.87,
paymentMethod: 'Карта',
footer: 'Спасибо, что поужинали у нас!',
}
};
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); // повторная попытка
};
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 вы можете инициировать печать из веб-хука заказа или из расширения браузера:
```javascript
// В вашем магазине 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);
// Показать резервный интерфейс или повторить попытку
}
};
Определение, установлен ли Print Agent
Прежде чем показывать функциональность печати в вашем пользовательском интерфейсе, проверьте, запущен ли агент:
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 термопринтеры и реализует полный API WebSocket, описанный в этом руководстве.
Для полной документации API и открытого исходного кода посетите страницу 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