receipt-printer/src/api/routes.ts
2026-02-12 08:07:58 +00:00

115 lines
3.7 KiB
TypeScript

import { Hono } from 'hono';
import { parseTemplate } from '../engine/parser';
import { renderTemplate } from '../engine/render';
import { extractSchema } from '../engine/schema';
import { PrinterConnector } from '../printer/connector';
import type { Template } from '../types/template';
const templates = new Map<string, Template>();
let printerConnector: PrinterConnector | null = null;
function getPrinter(): PrinterConnector {
if (!printerConnector) {
const ip = process.env.PRINTER_IP || '192.168.1.100';
const port = parseInt(process.env.PRINTER_PORT || '9100');
printerConnector = new PrinterConnector({ ip, port });
}
return printerConnector;
}
const api = new Hono();
// 模板管理
api.get('/templates', (c) => {
const list = Array.from(templates.values()).map(t => ({
id: t.id,
name: t.name,
description: t.description,
}));
return c.json({ success: true, templates: list });
});
api.get('/templates/:id', (c) => {
const id = c.req.param('id');
const template = templates.get(id);
if (!template) {
return c.json({ success: false, error: { code: 'TEMPLATE_NOT_FOUND', message: `Template '${id}' not found` }}, 404);
}
return c.json({ success: true, template });
});
api.post('/templates', async (c) => {
const body = await c.req.json();
if (!body.id || !body.config) {
return c.json({ success: false, error: { code: 'INVALID_REQUEST', message: 'Missing id or config' }}, 400);
}
try {
const config = typeof body.config === 'string' ? parseTemplate(body.config) : body.config;
const template: Template = { ...config, id: body.id };
templates.set(body.id, template);
return c.json({ success: true, template: { id: template.id, name: template.name }}, 201);
} catch (error) {
return c.json({ success: false, error: { code: 'INVALID_TEMPLATE', message: String(error) }}, 400);
}
});
api.get('/templates/:id/schema', (c) => {
const id = c.req.param('id');
const template = templates.get(id);
if (!template) {
return c.json({ success: false, error: { code: 'TEMPLATE_NOT_FOUND', message: `Template '${id}' not found` }}, 404);
}
const { schema, example } = extractSchema(template);
return c.json({ success: true, templateId: id, schema, example });
});
// 打印
api.post('/print/:templateId', async (c) => {
const templateId = c.req.param('templateId');
const template = templates.get(templateId);
if (!template) {
return c.json({ success: false, error: { code: 'TEMPLATE_NOT_FOUND', message: `Template '${templateId}' not found` }}, 404);
}
const body = await c.req.json();
const { data = {} } = body;
try {
const escData = renderTemplate(template, data);
const printer = getPrinter();
const jobId = printer.queue(escData);
return c.json({ success: true, jobId, status: 'queued', estimatedTime: '5s' });
} catch (error) {
return c.json({ success: false, error: { code: 'RENDER_ERROR', message: String(error) }}, 500);
}
});
// 打印机状态
api.get('/printer/status', async (c) => {
const printer = getPrinter();
const status = await printer.getStatus();
return c.json({
success: true,
printer: {
ip: process.env.PRINTER_IP || '192.168.1.100',
port: parseInt(process.env.PRINTER_PORT || '9100'),
...status,
queueLength: printer.getQueueLength()
}
});
});
api.post('/printer/test', (c) => {
const printer = getPrinter();
const testData = new Uint8Array([
0x1B, 0x40,
0x1B, 0x61, 0x01,
...new TextEncoder().encode('Printer Test Page\n'),
...new TextEncoder().encode('================\n'),
0x1B, 0x61, 0x00,
0x0A, 0x0A,
0x1D, 0x56, 0x00,
]);
const jobId = printer.queue(testData);
return c.json({ success: true, jobId, message: 'Test page queued' });
});
export { api as apiRoutes };