Печать 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('Агент печати подключен');
};

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

MenuForma Products