import net from 'net' import iconv from 'iconv-lite' export function printReceipt(printerIp, order) { return new Promise((resolve) => { const socket = new net.Socket() socket.setTimeout(8000) socket.connect(9100, printerIp, () => { // 打印机复位 socket.write(Buffer.from([0x1B, 0x40])) // ========================================== // 全局配置:58mm 一行固定 32 个字符 // ========================================== const lineWidth = 32 const line = '================================'.substring(0, lineWidth) const lineMin = '--------------------------------'.substring(0, lineWidth) // 居中函数 const center = (str) => { const s = String(str) const len = s.length const pad = Math.max(0, Math.floor((lineWidth - len) / 2)) return ' '.repeat(pad) + s + '\n' } // ========================================== // 标题:店名 + 结算单 + 桌号 → 全部居中对齐 // ========================================== socket.write(Buffer.from([0x1B, 0x21, 0x11])) // 放大店名 socket.write(iconv.encode(center(order.shop_name), 'gbk')) socket.write(Buffer.from([0x1B, 0x21, 0x00])) // 恢复正常 socket.write(iconv.encode(center(`结算单 #${order.orderInfo.orderNum}`), 'gbk')) socket.write(iconv.encode(center(`桌号:${order.orderInfo.tableName || ''}`), 'gbk')) socket.write(iconv.encode(line + '\n', 'gbk')) // ========================================== // 订单信息(全部撑满宽度) // ========================================== let content = '' content += `订单号:${order.orderInfo.orderNo}\n` content += `交易时间:${order.createdAt}\n` content += `收银员:${order.loginAccount}\n` content += lineMin + '\n' // ========================================== // 商品表格:完全对齐、撑满宽度 // ========================================== content += '品名 单价 数量 小计\n' content += lineMin + '\n' order.carts.forEach(item => { let name = String(item.name || '').substring(0, 10).padEnd(10, ' ') let price = String(item.salePrice || '0.00').padStart(6, ' ') let num = String(item.number || 1).padStart(3, ' ') let total = String(item.totalAmount || '0.00').padStart(3, ' ') content += name + price + num + total + '\n' }) content += lineMin + '\n' // ========================================== // 金额信息 // ========================================== content += `原价:${order.originAmount}\n` content += `折扣:${order.discountAllAmount}\n` // 发送前面内容 socket.write(iconv.encode(content, 'gbk')) // 实付放大 socket.write(Buffer.from([0x1B, 0x21, 0x11])) socket.write(iconv.encode(`实付:${order.orderAmount}\n`, 'gbk')) socket.write(Buffer.from([0x1B, 0x21, 0x00])) // 底部信息 let bottom = '' bottom += `备注:${order.remark || '无'}\n` bottom += `打印时间:${order.printTime}\n` bottom += line + '\n' bottom += '\n\n\n\n\n\n' socket.write(iconv.encode(bottom, 'gbk')) // 只切纸一次 socket.write(Buffer.from([0x1D, 0x56, 0x00])) setTimeout(() => { socket.end() resolve('ok') }, 400) }) socket.on('error', () => { }) socket.on('close', () => { }) socket.on('timeout', () => socket.destroy()) }) }