C# 收银机顾显,客显及打印小票

最近做winform收银机,设计顾显及打印小票总结。

1、顾显(串口COM1)

只涉及到总计,所以只是简单的功能。

public static ClientDisplayResult Display(decimal total, bool isClear=false)
        {
            var result = new ClientDisplayResult();
            string[] ports = SerialPort.GetPortNames();
            if (ports.Length == 0)
            {
                result.Result = false;
                result.Message = "未检测到串行通信接口";
                Logger.Error(result.Message);
                return result;
            }

            SerialPort serialPort = new SerialPort();
            try
            {
                // 串行端口 Windows:COM1  
                serialPort.PortName = "COM1";
                //串口波特率 默认:2400
                serialPort.BaudRate = 2400;
                //停止位 默认
                serialPort.StopBits = StopBits.One;
                //数据位 默认
                serialPort.DataBits = 8;

                if (!serialPort.IsOpen)
                {
                    serialPort.Open();
                }
                //清空接收缓冲区数据
                serialPort.DiscardInBuffer();

                if (isClear)
                {
                    //清屏\f
                    serialPort.WriteLine(((char)12).ToString());
                }
                else
                {
                    //状态,合计提示灯亮(ESCs2)
                    var text = ((char)27).ToString() + ((char)115).ToString() + ((char)50).ToString();
                    serialPort.Write(text);
                    //显示收款金额(EscQA金额CR)
                    text = ((char)27).ToString() + ((char)81).ToString() + ((char)65).ToString() + total.ToString() + ((char)13).ToString();
                    serialPort.Write(text);
                }
                result.Result = true;
                return result;
            }
            catch (Exception ex)
            {
                Logger.Error("顾显异常",ex);
                result.Result = false;
                result.Message = ex.Message;
                return result;
            }
            finally
            {
                serialPort.Close();
                serialPort.Dispose();
            }
        }

2、打印小票(并口打印)及打开钱箱(OpenDrawer方法)

通过Windows API接口

public class LPTControl
    {
        #region API函数

        [StructLayout(LayoutKind.Sequential)]
        private struct OVERLAPPED
        {
            int Internal;
            int InternalHigh;
            int Offset;
            int OffSetHigh;
            int hEvent;
        }
        [DllImport("kernel32.dll")]
        private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);

        [DllImport("kernel32.dll")]
        private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, out int lpNumberOfBytesWritten, out OVERLAPPED lpOverlapped);

        [DllImport("kernel32.dll")]
        private static extern bool CloseHandle(int hObject);

        #endregion

        public enum PrintPosition { Left, Center, Right }

        private int iHandle;

        private const int ColWidth = 32;


        private bool Write(string data)
        {
            if (iHandle != -1)
            {
                int i;
                OVERLAPPED x;
                byte[] byteData = System.Text.Encoding.Default.GetBytes(data);
                return WriteFile(iHandle, byteData, byteData.Length, out i, out x);
            }
            else
            {
                return false;
            }
        }
        private bool Write(byte[] data)
        {
            if (iHandle != -1 && data.Length > 0)
            {
                int i;
                OVERLAPPED x;
                return WriteFile(iHandle, data, data.Length, out i, out x);
            }
            else
            {
                return false;
            }
        }

        public bool OpenPort()
        {
            iHandle = CreateFile("LPT1", 0x40000000, 0, 0, 3, 0, 0);
            if (iHandle != -1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public bool Close()
        {
            return CloseHandle(iHandle);
        }

        public bool WriteLine(string data, PrintPosition position = PrintPosition.Left)
        {
            int length = Encoding.Default.GetBytes(data).Length;

            if (length < ColWidth)
            {
                if (position == PrintPosition.Right)
                {
                    data = data.PadLeft(ColWidth - (length - data.Length), ' ');
                }
                else if (position == PrintPosition.Center)
                {
                    data = data.PadLeft(length + (ColWidth - length) / 2 - (length - data.Length), ' ');
                }
            }

            bool result = Write(data);
            if (result)
            {
                result = NewRow();
            }
            return result;
        }
        private bool NewRow()
        {
            bool result = false;
            var byteData = new byte[] { 27, 10, 13 };
            return result = Write(byteData);
        }

        public bool PrintEmptyRow(int rowCount = 1)
        {
            bool result = false;
            string data = string.Empty.PadLeft(ColWidth, ' ');

            for (int i = 0; i < rowCount; i++)
            {
                result = WriteLine(data);
                if (!result) break;
            }
            return result;
        }

        public bool PrintLine(bool isDoubleLine = false)
        {
            if (isDoubleLine)
            {
                return WriteLine("================================");
            }
            else
            {
                return WriteLine("--------------------------------");
            }
        }

        public bool OpenDrawer()
        {
            bool result = Write(((char)27).ToString() + "p" + ((char)0).ToString() + ((char)60).ToString() + ((char)255).ToString());
            return result;
        }

    }

调用:

public static void Print(OrderInfo orderInfo)
        {
            try
            {
                if (orderInfo != null)
                {
                    var orderDetailList = GetOrderDetail(orderInfo.OrderId);
                    if (orderDetailList.IsNullOrEmpty())
                    {
                        Logger.Error("订单详情获取异常:OrderId" + orderInfo.OrderId);
                        return;
                    }
                    LPTControl control = new LPTControl();
                    var result = control.OpenPort();
                    if (!result)
                    {
                        Logger.Error("LPT1端口打开失败");
                        return;
                    }
                    control.WriteLine(orderInfo.SupermarketName, LPTControl.PrintPosition.Center);
                    control.PrintEmptyRow();
                    control.WriteLine($"订单号:{orderInfo.OrderId}");
                    control.WriteLine($"时间:{orderInfo.PayTime}");
                    control.WriteLine($"收银员:{orderInfo.AccountName}");
                    control.PrintLine(true);
                    int i = 1;
                    foreach (var item in orderDetailList)
                    {
                        control.WriteLine($"{i}、{item.GoodsName}");

                        var price = (decimal)item.Price;
                        var num = $"{item.GoodsCount}*{price.ToString("#0.00")}".PadLeft(13, ' ');
                        var total = (price * item.GoodsCount).ToString("#0.00").PadLeft(10, ' ');

                        var text = $"   {item.SKUID}{num}{total}";
                        control.WriteLine(text);
                        i++;
                    }
                    control.PrintLine();
                    if (orderInfo.OrderType == OrderType.Dispatching)
                    {
                        control.WriteLine($"配送费:{orderInfo.DeliveryAmount.ToString("#0.00")}元");
                    }

                    if (orderInfo.UsedScoreAmount > 0)
                    {
                        control.WriteLine($"积分抵扣:{ orderInfo.UsedScoreAmount}元");
                    }
                    var payType = orderInfo.PayWay.GetDescription();
                    if (orderInfo.OrderBusinessType == OrderBuyType.ToShop)
                    {
                        payType = OrderPayWay.CashPay.GetDescription();
                    }
                    control.WriteLine($"支付方式:{payType}");
                    control.WriteLine($"合计:{orderInfo.Total.ToString("#0.00")}元");
                    control.WriteLine($"应付:{ orderInfo.PayedAmount.ToString("#0.00")}元");
                    if (orderInfo.UserTotal > 0)
                    {
                        control.WriteLine($"赠送积分:{ orderInfo.UserTotal}");
                    }
                    if (orderInfo.OrderType == OrderType.Dispatching)
                    {
                        control.PrintLine(true);
                        control.WriteLine($"联系人:{orderInfo.TrueName}");
                        control.WriteLine($"手机号:{ orderInfo.DisplayMobile}");
                        control.WriteLine($"地址:{orderInfo.Address}");
                        control.WriteLine($"配送时间:{orderInfo.ExpectDispatchTimeText}");
                    }
                    control.PrintLine();
                    control.WriteLine("谢谢惠顾,欢迎下次光临!");
                    control.PrintEmptyRow(5);
                    control.OpenDrawer();
                    control.Close();
                    System.Threading.Thread.Sleep(500);
                }
                else
                {
                    Logger.Error("订单异常");
                }
            }
            catch (Exception ex)
            {
                Logger.Error("打印小票异常", ex);
            }
        }