package service import ( "fmt" "time" "wails-app/internal/dao" "wails-app/internal/global" ) // EMD807 CSN SDK DLL 路径 (x64) const sdkDllPath = `D:\lq\资料\停车场 道闸 车牌识别 收费机\票机自制\打印机\EMD807嵌入式热敏票据打印模组\5、SDK指令集\Win_SDK_Demo_2023_08_14\Win_SDK_Demo_2023_08_14\lib\x64\CsnPrinterLibs.dll` type PrintService struct{} func NewPrintService() *PrintService { return &PrintService{} } // PrintTicket 打印入场小票 func (s *PrintService) PrintTicket(printerID uint, lotName, channelCode, plateNo string, ticketID uint, ticketNo string) error { var printer dao.Printer if err := global.GVA_DB.First(&printer, printerID).Error; err != nil { return fmt.Errorf("打印机未配置: id=%d", printerID) } // 根据 port_name 判断连接类型 var err error var srl *SerialPrinter var usbHandle uintptr useCSN := false if len(printer.PortName) >= 3 && printer.PortName[:3] == "COM" { srl, err = NewSerialPrinter(printer.PortName, printer.BaudRate) if err == nil { defer srl.Close() } } else { // USB → 使用 CSN SDK 直连 err = initCSN(sdkDllPath) if err == nil { name := printer.PortName // 如果配置的是 "USB" 或 "auto",自动枚举 if name == "USB" || name == "auto" || name == "" { name = csn_EnumUSB() if name == "" { name = printer.PortName } } usbHandle, err = csn_OpenUSB(name) if err == nil { useCSN = true defer csn_Close(usbHandle) } } if !useCSN { err = fmt.Errorf("无法连接打印机: %s", printer.PortName) } } if err != nil { global.GVA_DB.Model(&printer).Update("status", "offline") return fmt.Errorf("连接打印机失败: %w", err) } now := time.Now().Format("02-01-2006 15:04:05") slipNo := fmt.Sprintf("%d", ticketID) // ── CSN SDK 模式 ── if useCSN { csn_Reset() csn_Align(1) // 居中 csn_Text("PARKING TICKET", 2, 2, 0, 0) csn_Text("", 1, 1, 0, 0) csn_Text(lotName, 1, 1, 0, 0) csn_Text("A-General Car", 1, 1, 0, 0) csn_Text("", 1, 1, 0, 0) csn_Text("PARK AT YOUR OWN RISK", 1, 1, 0, 1) csn_Text("================================", 1, 1, 0, 0) csn_Align(0) // 左对齐 csn_Text("In-Time::"+now, 1, 1, 0, 0) if channelCode != "" { csn_Text("InGate::"+channelCode, 1, 1, 0, 0) } if plateNo != "" { csn_Text("Veh No::"+plateNo, 1, 1, 0, 0) } csn_Text("================================", 1, 1, 0, 0) csn_Text("Slip No::"+slipNo, 1, 1, 0, 0) csn_Text("================================", 1, 1, 0, 0) csn_Align(1) // 居中 csn_FeedLine() csn_QRCode(ticketNo, 4) csn_FeedLine() csn_Text("SCAN AND PAY WITH", 1, 1, 0, 0) csn_Text("NEW THE CANADIA BANK APP", 1, 1, 0, 0) csn_FeedLines(3) csn_FullCut() global.GVA_DB.Model(&printer).Update("status", "online") return nil } // ── 串口模式(原有 ESC/POS)── write := func(data []byte) { srl.Write(data) } line32 := "================================" write(InitCmd) write(AlignCenterCmd) write(DoubleHeightCmd) write(BoldOnCmd) write(ESCPOS_Text("PARKING TICKET")) write(BoldOffCmd) write(NormalCmd) write(ESCPOS_Text("")) write(ESCPOS_Text(lotName)) if len(lotName) > 32 { write(FontBCmd) write(AlignCenterCmd) write(ESCPOS_Text(lotName)) write(NormalCmd) } write(ESCPOS_Text("A-General Car")) write(ESCPOS_Text("")) write(ESCPOS_Text("PARK AT YOUR OWN RISK")) write(ESCPOS_Text(line32)) write(AlignLeftCmd) write(ESCPOS_Text("In-Time::" + now)) if channelCode != "" { write(ESCPOS_Text("InGate::" + channelCode)) } if plateNo != "" { write(ESCPOS_Text("Veh No::" + plateNo)) } write(ESCPOS_Text(line32)) write(ESCPOS_Text("Slip No::" + slipNo)) write(ESCPOS_Text(line32)) write(AlignCenterCmd) write(ESCPOS_Text("")) write(ESCPOS_QRCode(ticketNo)) write(ESCPOS_Text("")) write(AlignCenterCmd) write(ESCPOS_Text("SCAN AND PAY WITH")) write(ESCPOS_Text("NEW THE CANADIA BANK APP")) write(InitCmd) write(ESCPOS_Text("")) write(ESCPOS_Text("")) write(ESCPOS_Text("")) write(CutPaperCmd) global.GVA_DB.Model(&printer).Update("status", "online") return nil }