打印机池的设计与实现

打印机池的设计与实现

先说一个应用场景——中厨。

服务员先在点菜电脑上点菜,点好的菜单信息要在各出品部的“出品印机”上打印出来,各出品部的师傅再按照菜单来做菜。

不同的菜,要在不同的出品打印机上打印,有的菜要在多个出品打印机上打印。

整个中厨大概有十来个出品部门,有的出品部门有一台出品打印机,有的出口部门有几台。

笔者把这些打印机统称为“打印机池”。

// 单元功用:打印相关
// 单元设计:cxg
// 设计日期:2014-05-12
// 每一台打印机都有自己的任务队列和处理任务队列的线程
// 快餐只有一个出品部门

unit untPrintTask;

interface

uses
  System.SysUtils, System.Classes,
  Datasnap.DBClient, frxclass,
  System.Generics.Collections;

type
  TBillContent = record // 小票内容
    machineNo: string; // POS机号
    skyName: string; // 收款员姓名
    saleNo: string; // 小票号
    saleTime: TDateTime; // 销售时间
    amount: Currency; // 应收
    pay: Currency; // 支付
    change: Currency; // 找零
    prnData: OleVariant; // 小票明细:商品名称、单价、数量、金额。。。。。。
    deskNo:string; // 台号
    payType: string; // 支付方式
  end;

type
  TPrinterInfo = record // 打印机信息
    prnNo: Integer; // 印机编号
    prnName: string; // 印机名称
    prnType: string; // 结账、厨打
    prnWidth: Integer; // 50mm\76mm\80mm
    remark: string; // 备注
    prnModel: string; // 打印模版
  end;

type
  TOneTimePrint = record // 一次打印
    printerInfo: TPrinterInfo; // 打印机信息
    billContent: TBillContent; // 小票内容
  end;

type
  TPrintTaskThread = class(TThread)  // 打印任务线程
  private
    FPrintQueue: TQueue<TOneTimePrint>;   // 打印队列
  protected
    procedure Execute; override;
  public
    constructor Create; overload;
    destructor Destroy; override;
    property PrintQueue: TQueue<TOneTimePrint> read FPrintQueue
      write FPrintQueue;
  end;

var
  g_PrintTasks: TDictionary<string, TPrintTaskThread>;  // <打印机名字, TPrintTask>

implementation

{ TPrintTask }

uses untFastReport, UntSysConst;

constructor TPrintTaskThread.Create;
begin
  Create(False);
  FreeOnTerminate := False;
  // 创建打印队列
  FPrintQueue := TQueue<TOneTimePrint>.Create;
end;

destructor TPrintTaskThread.Destroy;
begin
  // 释放打印队列
  FreeAndNil(FPrintQueue);
  inherited;
end;

procedure TPrintTaskThread.Execute;
var
  OneTimePrint: TOneTimePrint;
  dm: TdmFastReport;
  c: TfrxComponent;
begin
  while not Self.Terminated do
  begin
    if Assigned(FPrintQueue) and (FPrintQueue.Count > 0) then
    begin
      // 从任务队列中提取一个任务
      OneTimePrint := FPrintQueue.Dequeue;
      dm := TdmFastReport.Create(nil);
      try
        try
          // 小票明细数据
          dm.cds.Data := OneTimePrint.billContent.prnData;
          // 小票模板
          dm.report.LoadFromFile(OneTimePrint.printerInfo.prnModel);
          // 哪个打印机
          dm.report.PrintOptions.Printer := OneTimePrint.printerInfo.prnName;
          // 变量赋值

          c:=dm.report.FindObject('mmShopName');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := UserInfo.ShopName;

          c := dm.report.FindObject('mmMachineNo');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := OneTimePrint.billContent.machineNo;

          c:=dm.report.FindObject('mmSKY');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := OneTimePrint.billContent.skyName;

          c:= dm.report.FindObject('mmBillNo');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := OneTimePrint.billContent.saleNo;

          c:=dm.report.FindObject('mmSaleTime');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := FormatDateTime('yyyy-mm-dd hh:nn',OneTimePrint.billContent.saleTime);

          c:= dm.report.FindObject('mmDeskNo');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := OneTimePrint.billContent.deskNo;  // 台号

          c:= dm.report.FindObject('mmPayType');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := OneTimePrint.billContent.payType;

          c:= dm.report.FindObject('mmAmount');
          if c<> nil then
            TfrxMemoView(c).Memo.Text := FormatCurr('0.00', OneTimePrint.billContent.amount);

          c:=dm.report.FindObject('mmPay');
          if c<>nil then
            TfrxMemoView(c).Memo.Text := FormatCurr('0.00', OneTimePrint.billContent.pay);

          c:= dm.report.FindObject('mmGiveChange');
          if c<> nil then
            TfrxMemoView(c).Memo.Text := FormatCurr('0.00', OneTimePrint.billContent.change);

          // 开始打印
          dm.report.PrepareReport();
          dm.report.Print;
        except
          // 打印失败,重新加入任务队列
          Self.FPrintQueue.Enqueue(OneTimePrint);
        end;
      finally
        FreeAndNil(dm);
      end;
    end;
    // 线程休眠
    Sleep(1000);
  end;
end;

end.
procedure TfrmSettleAccount.PrintBill;
var
  OneTimePrint: TOneTimePrint;
  p: TPrintTaskThread;
begin
  // 结帐打印机和出品打印机都打印相同的模板
  frmPos.cdsPrinter.First;
  while not frmPos.cdsPrinter.Eof do
  begin
    // 打印机信息
    OneTimePrint.printerInfo.prnNo := frmPos.cdsPrinter.FieldByName('prnNo')
      .AsInteger;
    OneTimePrint.printerInfo.prnName := frmPos.cdsPrinter.FieldByName
      ('prnName').Text;
    OneTimePrint.printerInfo.prnType := frmPos.cdsPrinter.FieldByName
      ('prnType').Text;
    OneTimePrint.printerInfo.prnWidth := UserInfo.PaperWidth;
    OneTimePrint.printerInfo.remark := frmPos.cdsPrinter.FieldByName
      ('remark').Text;
    // 不同宽度的打印机加载不同的打印模板
    case OneTimePrint.printerInfo.prnWidth of
      58:
        OneTimePrint.printerInfo.prnModel :=
          ExtractFilePath(Application.ExeName) + 'report\pos58.fr3';
      76:
        OneTimePrint.printerInfo.prnModel :=
          ExtractFilePath(Application.ExeName) + 'report\pos76.fr3';
      80:
        OneTimePrint.printerInfo.prnModel :=
          ExtractFilePath(Application.ExeName) + 'report\pos80.fr3';
    end;
    // 小票内容
    OneTimePrint.billContent.machineNo := UserInfo.MachineId;
    OneTimePrint.billContent.skyName := UserInfo.UserName;
    OneTimePrint.billContent.saleNo := UserInfo.saleNo;
    OneTimePrint.billContent.saleTime := Now;
    OneTimePrint.billContent.amount := self.Total.totalAmount;
    OneTimePrint.billContent.pay := self.Total.totalAmount;
    OneTimePrint.billContent.Change := StrToCurr(edtChange.Text);
    OneTimePrint.billContent.prnData := frmPos.cdsSaleD.Data;
    OneTimePrint.billContent.payType := frmPos.cdsSaleM.FieldByName
      ('payType').Text;
    OneTimePrint.billContent.deskNo := frmPos.edtDeskNo.Text;
    // 加入打印队列
    if g_PrintTasks.TryGetValue(frmPos.cdsPrinter.FieldByName('prnName').Text, p)
    then
    begin
      p.PrintQueue.Enqueue(OneTimePrint);
    end;
    frmPos.cdsPrinter.Next;
  end;
end;

  

posted @ 2018-11-08 16:02  delphi中间件  阅读(1088)  评论(0编辑  收藏  举报