131 lines
3.5 KiB
TypeScript
131 lines
3.5 KiB
TypeScript
|
import { Printer } from "@node-escpos/core";
|
||
|
import USB from "@node-escpos/usb-adapter";
|
||
|
import { Task, Step, Printer as PrinterInterface } from '@shared/index';
|
||
|
import { steps } from '../db';
|
||
|
import { Knex } from 'knex';
|
||
|
import logger from '../logger';
|
||
|
|
||
|
export class SerialPrinter implements PrinterInterface {
|
||
|
private device: USB | null = null;
|
||
|
private printer: Printer<[]> | null = null;
|
||
|
|
||
|
constructor() {
|
||
|
this.initializePrinter();
|
||
|
}
|
||
|
|
||
|
private async initializePrinter() {
|
||
|
try {
|
||
|
this.device = new USB();
|
||
|
await new Promise<void>((resolve, reject) => {
|
||
|
this.device?.open((err) => {
|
||
|
if (err) {
|
||
|
logger.error('Failed to open printer:', err);
|
||
|
reject(err);
|
||
|
return;
|
||
|
}
|
||
|
resolve();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
const options = { encoding: "CP437" };
|
||
|
this.printer = new Printer(this.device, options);
|
||
|
logger.info('Printer initialized successfully');
|
||
|
} catch (error) {
|
||
|
logger.error('Failed to initialize printer:', error);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async getTaskSteps(db: Knex, task: Task): Promise<Step[]> {
|
||
|
return await steps(db).where('task_id', task.id).orderBy('order').select('*');
|
||
|
}
|
||
|
|
||
|
async printTask(task: Task, db: Knex): Promise<void> {
|
||
|
if (!this.printer || !this.device) {
|
||
|
throw new Error('Printer not initialized');
|
||
|
}
|
||
|
|
||
|
const taskSteps = await this.getTaskSteps(db, task);
|
||
|
|
||
|
try {
|
||
|
// Print header with task ID as barcode
|
||
|
await this.printer
|
||
|
.font('a')
|
||
|
.align('ct')
|
||
|
.style('b')
|
||
|
.size(1, 1) // Normal size (0.08 x 2.13 mm)
|
||
|
.text(`Task: ${task.name}`)
|
||
|
.text('='.repeat(32))
|
||
|
.text('')
|
||
|
.align('lt');
|
||
|
|
||
|
// Print task ID as barcode
|
||
|
await this.printer
|
||
|
.barcode(task.id.toString(), 'CODE128', { width: 2, height: 50 })
|
||
|
.text('')
|
||
|
.text('');
|
||
|
|
||
|
// Print steps
|
||
|
for (let i = 0; i < taskSteps.length; i++) {
|
||
|
const step = taskSteps[i];
|
||
|
await this.printer
|
||
|
.size(1, 1) // Normal size for step header
|
||
|
.text(`Step ${i + 1}: ${step.name}`)
|
||
|
.text('-'.repeat(32))
|
||
|
.size(0, 0) // Smaller size for instructions (0.08 x 2.13 mm)
|
||
|
.text(step.instructions)
|
||
|
.text('');
|
||
|
|
||
|
// Print step ID as barcode
|
||
|
await this.printer
|
||
|
.barcode(step.id.toString(), 'CODE128', { width: 2, height: 50 })
|
||
|
.text('');
|
||
|
}
|
||
|
|
||
|
await this.printer
|
||
|
.text('')
|
||
|
.text('')
|
||
|
.cut()
|
||
|
.close();
|
||
|
|
||
|
logger.info(`Printed task ${task.id}`);
|
||
|
} catch (error) {
|
||
|
logger.error('Failed to print task:', error);
|
||
|
throw error;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async printStep(step: Step, db: Knex): Promise<void> {
|
||
|
if (!this.printer || !this.device) {
|
||
|
throw new Error('Printer not initialized');
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
await this.printer
|
||
|
.font('a')
|
||
|
.align('ct')
|
||
|
.style('b')
|
||
|
.size(1, 1) // Normal size (0.08 x 2.13 mm)
|
||
|
.text(`Step: ${step.name}`)
|
||
|
.text('='.repeat(32))
|
||
|
.text('')
|
||
|
.align('lt')
|
||
|
.size(0, 0) // Smaller size for instructions
|
||
|
.text(step.instructions)
|
||
|
.text('')
|
||
|
.text('');
|
||
|
|
||
|
// Print step ID as barcode
|
||
|
await this.printer
|
||
|
.barcode(step.id.toString(), 'CODE128', { width: 2, height: 50 })
|
||
|
.text('')
|
||
|
.text('')
|
||
|
.cut()
|
||
|
.close();
|
||
|
|
||
|
logger.info(`Printed step ${step.id}`);
|
||
|
} catch (error) {
|
||
|
logger.error('Failed to print step:', error);
|
||
|
throw error;
|
||
|
}
|
||
|
}
|
||
|
}
|