using DevComponents.DotNetBar.SuperGrid; using JumpKick.HttpLib; using POS.Language.Language; using POSV.Bean; using POSV.Entity; using POSV.MessageEvent; using POSV.ShoppingCart; using POSV.Utils; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace POSV { public partial class ViceScreenForm : BaseForm { private OrderObject _orderObject; //当前选中的单品行记录 private OrderItem _orderItem = null; #region 默认参数 //无操作,图片全屏时间 private static int PICFULLSCREENSECOND = 5; private int _fullScreenSecond = PICFULLSCREENSECOND; //图片轮播时间间隔 private static int PICLUNBOINTERVAL = 5; //图片显示方式 private static ImageSizeModeEnum IMAGESIZEMODE = ImageSizeModeEnum.居中; //文本字体 private static SystemFont TXTFONT = SystemFont.正常; private SystemFont _txtFont = TXTFONT; private static Color TXTCOLOR = Color.Blue; private Color _txtColor = TXTCOLOR; //文本背景 private static Color TXTBGCOLOR = Color.White; private Color _txtBgColor = TXTBGCOLOR; //文本定位 private static ShowPositionEnum TXTSHOWPOSITION = ShowPositionEnum.顶部; private ShowPositionEnum _txtShowPosition = TXTSHOWPOSITION; //速度 private static SpeedEnum TXTSPEED = SpeedEnum.快; //是否显示商品图片 private static bool SHOWPRODUCTIMAGE = true; #endregion /// /// 商品图片集合 /// private Dictionary productImageDic = new Dictionary(); /// /// 轮播图片集合 /// List ads = new List(); //订单完成后倒计时准备全屏定时器 private System.Timers.Timer fullScreenTimer = new System.Timers.Timer(1000); //图片轮播定时器 private System.Timers.Timer picRollTimer = null; /// /// 广告图片轮播定时器状态 /// private bool _PicRollStatus = false; //文字轮播定时器 private System.Timers.Timer txtTimer = null; public ViceScreenForm() { InitializeComponent(); MsgEvent.RemoveListener(Constant.VICE_ORDER_NOTIFY, OrderNotify); MsgEvent.Receive(Constant.VICE_ORDER_NOTIFY, OrderNotify); MsgEvent.RemoveListener(Constant.VICE_CHANGED_NOTIFY, RefreshUI); MsgEvent.Receive(Constant.VICE_CHANGED_NOTIFY, RefreshUI); foreach (var item in this.orderItemGrid.PrimaryGrid.Columns) { var _col = item as GridColumn; if (_col != null) { _col.HeaderText = LangProxy.ToLang(_col.HeaderText); } } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.orderItemGrid.RowActivated += GridControlRowActivated; this.orderItemGrid.GetDetailRowHeight -= GridControlRowGetDetailHeight; this.orderItemGrid.GetDetailRowHeight += GridControlRowGetDetailHeight; this.orderItemGrid.PostRenderRow -= GridControlPostRenderRow; this.orderItemGrid.PostRenderRow += GridControlPostRenderRow; LoadSetting(); RollTxt(); //全屏倒计时 fullScreenTimer.Elapsed += (o, a) => { if (_fullScreenSecond == 0) { //全屏显示广告 this.Invoke(new Action(() => { if (!_PicRollStatus) { if (picRollTimer != null) { picRollTimer.Start(); } _PicRollStatus = true; } this.doubleBufferPanelX1.Visible = false; })); fullScreenTimer.Stop(); } _fullScreenSecond--; }; //默认显示巨为图片 this.pictureBox1.Image = global::POSV.Properties.Resources.jwydImage1; InstallPic(); Task.Factory.StartNew(() => { //组装商品对象 InstallProductImage(); }); } void GridControlRowGetDetailHeight(object sender, GridGetDetailRowHeightEventArgs e) { GridRow row = e.GridRow as GridRow; if (row != null) { OrderItem item = row.Tag as OrderItem; int isFlavor = StringUtils.GetInt(row["flavor"].Value); if (isFlavor == 1) { string text = item.FlavorNames; Rectangle r = row.FirstVisibleCell.ContentBounds; Rectangle t = row.LastVisibleCell.ContentBounds; Size rsize = e.SizeNeeded; rsize.Height = 0; rsize.Width = (t.Right - r.Left); var sf = TextFormatFlags.Left | TextFormatFlags.NoPadding | TextFormatFlags.WordBreak; Size size = TextRenderer.MeasureText(text, Constant.DEFAULT_FONT, rsize, sf); e.PostDetailHeight = size.Height; } } } void GridControlPostRenderRow(object sender, GridPostRenderRowEventArgs e) { GridRow row = e.GridRow as GridRow; if (row != null) { OrderItem item = row.Tag as OrderItem; //是否包含口味 int isFlavor = StringUtils.GetInt(row["flavor"].Value); Rectangle r = row.FirstVisibleCell.ContentBounds; Rectangle t = row.LastVisibleCell.ContentBounds; string text = item.FlavorNames; r.Width = t.Right - r.X;// - Dpi.Width5; r.Y = e.Bounds.Bottom - row.EffectivePostDetailRowHeight;// - Dpi.Height5; r.Height = row.EffectivePostDetailRowHeight; if (isFlavor == 1) { //e.Graphics.FillRectangle(Brushes.LightPink , r); //e.Graphics.DrawRectangle(Pens.RosyBrown , r); r.Inflate(-2, 1); var sf = TextFormatFlags.Left | TextFormatFlags.NoPadding | TextFormatFlags.WordBreak; TextRenderer.DrawText(e.Graphics, text, Constant.DEFAULT_FONT, r, row.IsSelected ? Color.DimGray : Color.DimGray, sf); } //绘制右边线 System.Drawing.Pen pen = new System.Drawing.Pen(SystemColors.ControlDark);//画笔 e.Graphics.DrawLine(pen, new Point(t.Right, t.Top - 1), new Point(t.Right, row.EffectivePostDetailRowHeight + t.Bottom)); pen.Dispose(); } } private void GridControlRowActivated(object sender, GridRowActivatedEventArgs e) { if (e.NewActiveRow != null) { GridPanel panel = e.GridPanel; panel.SetSelected(e.OldActiveRow, false); panel.SetSelected(e.NewActiveRow, true); panel.SetActiveRow(e.NewActiveRow); //当前行的对象 OrderItem orderItem = e.NewActiveRow.Tag as OrderItem; //设置当前活跃行 this._orderItem = orderItem; if (SHOWPRODUCTIMAGE) { //显示商品图片,停止广告轮播 if (picRollTimer != null && _PicRollStatus) { picRollTimer.Stop(); _PicRollStatus = false; } //显示商品图片 ShowProductImage(orderItem.ProductId); } } } /// /// 组装商品图片集合 /// private void InstallProductImage() { try { //有用的图片名称 List validNames = new List(); var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"images/productImg"); if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } List imageList = null; using (var db = Global.Instance.OpenDataBase) { string sql = "select * from pos_product_image group by productId"; imageList = db.Query(sql).ToList(); } if (imageList != null && imageList.Count > 0) { foreach (var image in imageList) { //验证本地是否存在当前商品图片 var fileName = string.Empty; if (!string.IsNullOrEmpty(image.StorageFileName) && image.StorageFileName.Contains("/")) { fileName = image.StorageFileName.Substring(image.StorageFileName.LastIndexOf('/') + 1); } if (!string.IsNullOrEmpty(fileName)) { string targetFileName = filePath + Path.DirectorySeparatorChar + fileName; validNames.Add(fileName); //加入商品图片缓存 productImageDic.Add(image.ProductId, targetFileName); if (File.Exists(targetFileName)) { LOGGER.Info("图片{0}已经下载,忽略本次操作", image.StorageFileName); continue; } if (!Global.Instance.Online) { LOGGER.Info("离线,无法下载图片{0}", image.StorageFileName); continue; } var url = image.Url; Http.Get(url).DownloadTo(targetFileName, onProgressChanged: (bytesCopied, totalBytes) => { if (totalBytes.HasValue) { LOGGER.Info("Downloading: " + (bytesCopied / totalBytes) * 100 + "%"); } }, onSuccess: (header) => { LOGGER.Info("Download Complete"); }).Go(); } } } //清理工作,清理下载的无用的商品图片,节省空间 DirectoryInfo root = new DirectoryInfo(filePath); foreach (FileInfo f in root.GetFiles()) { if (!validNames.Contains(f.Name)) { f.Delete(); } } } catch (Exception ex) { LOGGER.Error(ex, "商品图片下载异常"); } } private void ShowProductImage(string productId) { try { if (productImageDic.ContainsKey(productId)) { var imageFile = productImageDic[productId]; this.pictureBox1.Image = Image.FromFile(imageFile); } else { //显示商品图片,没有图片的商品,默认显示巨为logo,避免顾客理解错误 this.pictureBox1.Image = global::POSV.Properties.Resources.jwydImage1; } } catch (Exception ex) { LOGGER.Error(ex, "显示商品图片异常"); } } /// /// 更新UI /// protected virtual void RefreshUI(object sender, MsgEventArgs args) { //加载最新设置 LoadSetting(); //组装文本 RollTxt(); //组装图片,轮播 InstallPic(); //全屏倒计时 _fullScreenSecond = PICFULLSCREENSECOND; } /// /// 轮播文字 /// private void RollTxt() { List captionList = null; using (var db = Global.Instance.OpenDataBase) { captionList = db.Fetch(); } StringBuilder captionStr = new StringBuilder(); bool first = true; foreach (var caption in captionList) { if (!first) { captionStr.Append(" "); } first = false; captionStr.Append(caption.Content); } if (!string.IsNullOrEmpty(captionStr.ToString())) { //有文字,启动轮播文字 if (TXTSHOWPOSITION == ShowPositionEnum.顶部) { this.txtPanel.Dock = DockStyle.Top; } else { this.txtPanel.Dock = DockStyle.Bottom; } this.txtLabel.Text = captionStr.ToString(); this.txtLabel.Font = NewGetSystemFont(TXTFONT); this.txtLabel.ForeColor = TXTCOLOR; this.txtPanel.Style.BackColor1.Color = TXTBGCOLOR; this.txtPanel.Style.BackColor2.Color = TXTBGCOLOR; this.txtPanel.Height = (int)this.txtLabel.Font.Size + 20; this.txtPanel.Visible = true; //速度 int mill = 100; switch (TXTSPEED) { case SpeedEnum.极快: mill = 20; break; case SpeedEnum.特快: mill = 100; break; case SpeedEnum.快: mill = 200; break; case SpeedEnum.普通: mill = 300; break; case SpeedEnum.慢: mill = 400; break; case SpeedEnum.特慢: mill = 700; break; case SpeedEnum.极慢: mill = 1000; break; case SpeedEnum.静止: mill = 0; break; } //跑马灯文字 if (mill != 0) { if (txtTimer != null) { txtTimer.Stop(); txtTimer = null; } txtTimer = new System.Timers.Timer(mill); txtTimer.Elapsed += (o, args) => { this.Invoke(new Action(() => { txtLabel.Left = txtLabel.Left - (int)this.txtLabel.Font.Size; if (txtLabel.Right < 0) txtLabel.Left = txtPanel.Width; })); }; txtTimer.Start(); } else { if (txtTimer != null) { txtTimer.Stop(); txtTimer = null; } } } else { this.txtPanel.Visible = false; } } private Font NewGetSystemFont(SystemFont fontSize) { Font result = Constant.DEFAULT_FONT; switch (fontSize) { case SystemFont.默认: { result = new Font("宋体", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); } break; case SystemFont.正常: { result = new Font("宋体", 15F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); } break; case SystemFont.小字: { result = new Font("宋体", 10.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); } break; case SystemFont.大字: { result = new Font("宋体", 25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); } break; } return result; } public static void LoadSetting() { var paramStr = Global.Instance.GlobalConfigStringValue(ConfigConstant.DEVICE_VICE_PARAM); if (!string.IsNullOrEmpty(paramStr)) { var param = JsonUtils.Deserialize(paramStr); PICFULLSCREENSECOND = param.PicLunboFullScreenSec;//全屏 PICLUNBOINTERVAL = param.PicLunboInterval;//轮播速度 IMAGESIZEMODE = param.PicSizeMode;//图片显示方式 TXTFONT = param.TxtFont;//文本字体 TXTCOLOR = ColorTranslator.FromHtml(param.TxtColor);//文本颜色 TXTBGCOLOR = ColorTranslator.FromHtml(param.TxtBgColor);//文本背景颜色 TXTSHOWPOSITION = param.TxtShowPosition;//显示位置 TXTSPEED = param.TxtSpeed; SHOWPRODUCTIMAGE = param.ShowProductImage;//是否显示商品图片 } } /// /// 轮播图片 /// private void InstallPic() { Task.Factory.StartNew(new Action(() => { try { var adDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"images/ViceAd"); if (!Directory.Exists(adDirPath)) { //没有目录,创建目录 DirectoryInfo TheFolder = new DirectoryInfo(adDirPath); TheFolder.Create(); } List picList = new List(); using (var db = Global.Instance.OpenDataBase) { picList = db.Query("order by orderNo").ToList(); } //有效的图片名称 List validNames = new List(); //门店云端轮播图片 var targetNameList = new List(); try { foreach (var pic in picList) { var url = string.Format("{0}/{1}/{2}", pic.DfsAccessDomain, pic.GroupName, pic.StorageFileName); var name = string.Empty; if (!string.IsNullOrEmpty(url) && url.Contains("/")) { name = url.Substring(url.LastIndexOf('/') + 1); } if (!string.IsNullOrEmpty(name)) { validNames.Add(name); string targetFileName = adDirPath + Path.DirectorySeparatorChar + name; if (!File.Exists(targetFileName)) {//本地不存在,下载 if (!Global.Instance.Online) { LOGGER.Info("离线,无法下载图片{0}", name); continue; } WebClient webClient = new WebClient(); webClient.DownloadFile(url, targetFileName); } else { LOGGER.Info("轮播图片:{0} 已存在,取消本次下载", targetFileName); } targetNameList.Add(targetFileName); } } } catch (Exception ex) { LOGGER.Error(ex, "双屏图片文件下载异常!"); } if (Directory.Exists(adDirPath)) { //路径存在,查找文件 foreach (var targetName in targetNameList) { //遍历指定文件夹中的所有文件 try { FileStream fs = new FileStream(targetName, FileMode.Open, FileAccess.Read); ads.Add((Bitmap)System.Drawing.Bitmap.FromStream(fs)); } catch (Exception ex) { LOGGER.Error(ex, "加载双屏图片资源异常"); } } } if (ads.Count == 0) { this.pictureBox1.Image = global::POSV.Properties.Resources.jwydImage1; } else { int intervalMilli = PICLUNBOINTERVAL * 1000; int i = 0; if (picRollTimer != null) { picRollTimer.Stop(); picRollTimer = null; _PicRollStatus = false; } picRollTimer = new System.Timers.Timer(intervalMilli); picRollTimer.Elapsed += (o, args) => { if (i == ads.Count) { i = 0; } var image = ads[i]; this.Invoke(new Action(() => { switch (IMAGESIZEMODE) { case ImageSizeModeEnum.居中: this.pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage; break; case ImageSizeModeEnum.拉伸: this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; break; case ImageSizeModeEnum.等比缩放: this.pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; break; } this.pictureBox1.Image = image; })); i++; }; picRollTimer.Start(); _PicRollStatus = true; //立即显示第一张 this.pictureBox1.Image = ads[0]; i++; } //清理工作,清理下载的无用的轮播图片,节省空间 DirectoryInfo root = new DirectoryInfo(adDirPath); foreach (FileInfo f in root.GetFiles()) { if (!validNames.Contains(f.Name)) { f.Delete(); } } } catch (Exception ex) { LOGGER.Error(ex, "装载轮播广告图片异常"); } })); } protected virtual void OrderNotify(object sender, MsgEventArgs args) { try { Tuple arg = args.Data as Tuple; //停止倒计时 fullScreenTimer.Stop(); //非支付完成通知,显示点单列表 if (arg.Item1 != ViceNotifyType.FINISHEDORDER) { this.doubleBufferPanelX1.Visible = true; } object data = arg.Item2; switch (arg.Item1) { case ViceNotifyType.ADDORDERITEM: //新增记录 AddOrderItem(data); break; case ViceNotifyType.CLEARALLITEMS: //清空商品记录 ClearOrderRow(); break; case ViceNotifyType.DELETESINGLEITEM: //删除单条商品记录 DeleteSingleItem(data); break; case ViceNotifyType.CREATEORDER: //新建订单 _orderObject = data as OrderObject; break; case ViceNotifyType.FINISHEDORDER: //订单完成, 20秒倒计时,20秒没有通知,全屏轮播广告 //_fullScreenSecond = PICFULLSCREENSECOND; //if (_fullScreenSecond != 0)//0 不全屏 //{ // fullScreenTimer.Start(); //} break; case ViceNotifyType.UPDATEORDERITEM: //更新单条商品记录 UpdateOrderItem(data); break; case ViceNotifyType.UPDATEORDERALLITEM: //更新所有商品记录 UpdateAllGridRow(); break; case ViceNotifyType.BATCHADDORDERITEM: //批量新增订单项 _orderObject = data as OrderObject; ShowOrderItem(_orderObject); break; } RefreshUi(); //判断是否全屏倒计时 NoRowShowFullScreen(); } catch (Exception ex) { LOGGER.Error(ex, "副屏通知处理发生异常"); } } protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); //停止轮播 if (fullScreenTimer != null) { fullScreenTimer.Stop(); } if (picRollTimer != null) { picRollTimer.Stop(); _PicRollStatus = false; } if (txtTimer != null) { txtTimer.Stop(); } } /// /// 开启全屏轮播 /// private void NoRowShowFullScreen() { if (_orderObject == null || _orderObject.OrderStatus == OrderStatus.已完成 || _orderObject.Items == null || _orderObject.Items.Count == 0) { _fullScreenSecond = PICFULLSCREENSECOND; if (_fullScreenSecond != 0)//0 不全屏 { fullScreenTimer.Start(); } } } /// /// 更新商品信息 /// /// private void UpdateOrderItem(object data) { _orderItem = data as OrderItem; UpdateGridRow(); } /// /// 清空商品记录 /// /// /// private void ClearOrderRow() { GridPanel panel = this.orderItemGrid.PrimaryGrid; panel.Rows.Clear(); } /// /// 新增商品记录 /// /// /// private void AddOrderItem(object data) { GridRow row = data as GridRow; GridPanel panel = this.orderItemGrid.PrimaryGrid; if (row == null) { var _data = data as OrderItem; row = new GridRow(_data.Name, _data.Quantity, _data.Price, _data.Amount, _data.Flavor); row.Tag = _data; //将RowIndex映射 _data.GridRow = row; } panel.Rows.Add(row); if (panel.ActiveRow != null) { panel.SetSelected(panel.ActiveRow, false); panel.SetActiveRow(row); } panel.ClearSelectedRows();//清空之前选择的行 panel.SetSelected(row, true); } /// /// 删除商品记录 /// /// /// private void DeleteSingleItem(object data) { var _data = data as OrderItem; GridPanel panel = this.orderItemGrid.PrimaryGrid; if (_data != null) { panel.Rows.RemoveAt(_data.GridRow.Index); } else { int index = (int)data; panel.Rows.RemoveAt(index); } //选中最后一条 GridRow row = (GridRow)panel.Rows.LastOrDefault(); this._orderItem = null; if (row != null) { panel.SetActiveRow(row); panel.ClearSelectedRows();//清空之前选择的行 panel.SetSelected(row, true); } } /// /// 展示订单所有内容订单项 /// /// private void ShowOrderItem(OrderObject order) { if (order == null) { return; } List rowList = new List(); foreach (OrderItem item in order.Items) { //品名 string _name = item.DisplayName; //数量 decimal _num = item.Quantity; //售价 decimal _price = item.Price; //售价 decimal _amount = item.Amount; //是否包含做法 int _flavor = (item.FlavorNames == null ? 0 : 1); GridRow row = new GridRow(_name, _num, _price, _amount, _flavor); row.RowHeight = 0; row.Tag = item; rowList.Add(row); } GridPanel panel = this.orderItemGrid.PrimaryGrid; panel.Rows.Clear(); if (rowList.Count > 0) { panel.Rows.AddRange(rowList); panel.SetActiveRow(rowList.Last()); panel.ClearSelectedRows();//清空之前选择的行 panel.SetSelected(rowList.Last(), true); Application.DoEvents(); int h = panel.Rows.Sum(p => p.Size.Height); this.orderItemGrid.VScrollOffset = h; } RefreshUi(); } /// /// 更新订单界面 /// private void RefreshUi() { this.Invoke(new Action(() => { if (null != this._orderObject) { //找零 //this.orderChangeAmountLabel.Text = this._orderObject.ChangeAmount.ToString("f2"); //总金额 this.orderTotalAmountLabel.Text = string.Format( LangProxy.ToLang(this.orderTotalAmountLabel.Tag.ToString()), this._orderObject.Amount.ToString("f2")); //总优惠金额 this.orderTotalDiscountAmountLabel.Text = string.Format(LangProxy.ToLang(this.orderTotalDiscountAmountLabel.Tag.ToString()), this._orderObject.DiscountAmount.ToString("f2")); //应收 this.orderShouldAmountLabel.Text = string.Format(LangProxy.ToLang(this.orderShouldAmountLabel.Tag.ToString()), (this._orderObject.ReceivableAmount - this._orderObject.MalingAmount).ToString("f2")); //抹零金额 //this.orderMalingAmountLabel.Text = this._orderObject.MalingAmount.ToString("f2"); //这里有个问题 应该是实收 } })); } /// /// 更新grid /// private void UpdateGridRow() { this.Invoke(new Action(() => { if (_orderItem != null) { GridPanel panel = this.orderItemGrid.PrimaryGrid; //找到对应的row foreach (GridRow row in panel.Rows) { var rowItem = row.Tag as OrderItem; if (rowItem.Id == this._orderItem.Id) { row["name"].Value = this._orderItem.DisplayName; row["num"].Value = this._orderItem.Quantity; row["price"].Value = this._orderItem.Price; row["amount"].Value = this._orderItem.Amount; //是否包含做法 int _flavor = this._orderItem.FlavorNames == null ? 0 : 1; row["flavor"].Value = _flavor; panel.SetActiveRow(row); panel.ClearSelectedRows();//清空之前选择的行 panel.SetSelected(row, true); break; } } } })); } private void UpdateAllGridRow() { this.Invoke(new Action(() => { GridPanel panel = this.orderItemGrid.PrimaryGrid; foreach (GridRow row in panel.Rows) { OrderItem tagItem = (OrderItem)row.Tag; //var inx = _orderObject.Maps.IndexOf(tagItem); //OrderItem item = _orderObject.Maps[inx]; ////OrderItem item = _orderObject.Maps[tagItem.Id]; row["name"].Value = tagItem.DisplayName; row["num"].Value = tagItem.Quantity; row["price"].Value = tagItem.Price; row["amount"].Value = tagItem.Amount; //是否包含做法 int _flavor = tagItem.FlavorNames == null ? 0 : 1; row["flavor"].Value = _flavor; //row["amount"].Value = item.ShouldAmount; //row["discountAmount"].Value = item.TotalFavourableAmount; //row["makes"].Value = item.MakesDisplayName; } } )); } } }