You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

568 lines
22 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using POSV.Entity;
using System.Diagnostics;
using POSV.Utils;
using DevComponents.DotNetBar.Metro;
using DevComponents.DotNetBar;
using POSV.Component;
using POSV.ThirdPartyOrderData;
namespace POSV.WeiXin
{
[ToolboxItem(true)]
public partial class WeixinProductX : BaseUserControl
{
/// <summary>
/// 商品控件默认宽度
/// </summary>
public const int PRODUCT_DEFAULT_WIDTH = 104;
/// <summary>
/// 商品控件默认高度
/// </summary>
public const int PRODUCT_DEFAULT_HEIGHT = 76;
/// <summary>
/// 数据源
/// </summary>
private List<ListProductSpec> _dataSource = null;
//这样可以加快多次创建item速度否则每次要耗时2毫秒
private Image _defaultImage = global::POSV.Properties.Resources._2x;
/// <summary>
/// 选中的商品列表
/// </summary>
public List<ListProductSpec> SelectedProducts { get; private set; } = new List<ListProductSpec>();
/// <summary>
/// 选中的品类
/// </summary>
public List<string> SelectedCategorys { get; private set; } = new List<string>();
public WeixinProductX()
{
InitializeComponent();
this.itemPanel.ResizeItemsToFit = false;
this.itemPanel.BackgroundStyle.Class = "MetroTileGroupTitle";//很关键
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (this.DesignMode) return;
ReCalSize();
this.Resize += OnResize;
}
private void OnResize(object sender, EventArgs e)
{
switch (this.FindForm().WindowState)
{
case FormWindowState.Normal:
case FormWindowState.Maximized:
{
ReCalSize();
}
break;
}
}
private void ReCalSize()
{
//计算能显示的列数
var _width = this.ItemWidth + this.ItemSpace - 1;
if (_width != 0)
{
this.Columns = ((this.Width - this.Padding.Left - this.Padding.Right) / _width);
}
//根据行数,重新规划高度
var _height = this.ItemHeight + this.ItemSpace - 1;
if (_height != 0)
{
this.Rows = ((this.Height - this.Padding.Top - this.Padding.Bottom) / _height);
}
this.ItemHeight = (this.Height - this.Padding.Top - this.Padding.Bottom) / this.Rows - this.ItemSpace;
BindDataSource(this._dataSource, this.SelectedCategorys);
}
public void BindDataSource(List<ListProductSpec> dataSource, List<string> selectedCategorys)
{
try
{
if (this.SelectedProducts == null)
{
this.SelectedProducts = new List<ListProductSpec>();
}
this.SelectedCategorys = selectedCategorys;
if(this.SelectedCategorys == null)
{
this.SelectedCategorys = new List<string>();
}
if (dataSource == null)
{
dataSource = new List<ListProductSpec>();
}
//加入分页,避免污染源数据,新建集合
List<ListProductSpec> list = new List<ListProductSpec>();
if (this.SelectedCategorys.Count > 0)
{
var searchProductByCategorys = dataSource.FindAll(x => this.SelectedCategorys.Contains(x.categoryId));
list.AddRange(searchProductByCategorys == null ? new List<ListProductSpec>() : searchProductByCategorys);
this.SelectedProducts.RemoveAll(x => !this.SelectedCategorys.Contains(x.categoryId));
}
else
{
list.AddRange(dataSource);
}
this._dataSource = list;
//可以考虑更优化的分摊机制?张莹
int deltaX = this.Width - this.Padding.Left - this.Padding.Right - (this.ItemWidth + this.ItemSpace) * this.Columns - this.ItemSpace;
int deltaY = this.Height - this.Padding.Top - this.Padding.Bottom - (this.ItemHeight + this.ItemSpace) * this.Rows - this.ItemSpace;
this.TotalCount = this._dataSource.Count;
this.PageSize = this.Columns * this.Rows;
//清空历史数据
this.itemPanel.Items.Clear();
//复制新的数据源,进行分页运算
var merge = WeixinProductXMerge.Merge(this.Rows, this.Columns, this._dataSource, false);
var pager = ListPager(merge);
ItemContainer mainContainer = new ItemContainer();
mainContainer.Name = "productContainer";
mainContainer.MultiLine = (this.Rows > 1);
mainContainer.ItemSpacing = this.ItemSpace;
mainContainer.LayoutOrientation = eOrientation.Horizontal;
//2020-03-03 张莹 add 按照规格商品显示
for (int i=0;i < pager.Count;i++)
{
ListProductSpec entity = pager[i];
MetroTileItem item = new MetroTileItem();
item.Name = entity.specId;
item.Checked = false;
item.TileStyle.PaddingLeft = item.TileStyle.PaddingRight = 0;
item.EnableMarkup = true;
item.OptionGroup = "product";
item.TileStyle.BorderWidth = 0;
//正常情况下的背景颜色
item.TileStyle.BackColor = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BackColor2 = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BorderColor = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BorderColor2 = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.CornerDiameter = 12;
item.TileStyle.CornerType = eCornerType.Rounded;
item.TitleTextAlignment = ContentAlignment.TopCenter;
//将宽度进行补偿
int _width = this.ItemWidth + (this.Columns > 0 ? (deltaX / this.Columns) : 0);
int _height = this.ItemHeight + deltaY;
//显示大小
item.TileSize = new Size(_width, _height);
//显示编码后,调整呈现位置
item.TileStyle.TextAlignment = DevComponents.DotNetBar.eStyleTextAlignment.Center;
item.TileStyle.TextLineAlignment = DevComponents.DotNetBar.eStyleTextAlignment.Near;
item.TitleTextAlignment = System.Drawing.ContentAlignment.BottomCenter;
//品名
item.TileStyle.TextColor = ColorTranslator.FromHtml("#444444");
//显示已售罄
item.TitleTextColor = ColorTranslator.FromHtml("#444444");
//是否售罄0-售罄
decimal stock = 0.0M;
decimal.TryParse(string.IsNullOrEmpty(entity.stock) ? "0" : entity.stock, out stock);
//绑定商品Tag属性
item.Tag = ObjectUtils.Copy(entity);
switch (entity.productName)
{
case Constant.PREV_PAGER:
{
item.TileStyle.BackgroundImage = _defaultImage;
item.Image = global::POSV.Properties.Resources._2x;
item.ImageTextAlignment = ContentAlignment.MiddleCenter;
item.Text = string.Empty;
}
break;
case Constant.NEXT_PAGER:
{
item.TileStyle.BackgroundImage = _defaultImage;
item.Image = global::POSV.Properties.Resources._2x;
item.ImageTextAlignment = ContentAlignment.MiddleCenter;
item.Text = string.Empty;
}
break;
default:
{
//显示编码后,调整呈现位置
if(stock <= 0)
{
item.TitleText = "已售罄";
}
//绑定商品名称+规格名称
string productName = entity.productName;
string specName = "";
if (!string.IsNullOrEmpty(entity.specName))
{
specName = "\r\n[" + entity.specName + "]";
}
item.Text = string.Format("{0}{1}", productName, specName);
if (this.SelectedProducts.Exists(x=>x.specId.Equals(entity.specId)))
{
//选中情况下的背景颜色
item.TileStyle.BackColor = ColorTranslator.FromHtml("#00C7BA");
item.TileStyle.BackColor2 = ColorTranslator.FromHtml("#00C7BA");
item.TileStyle.BorderColor = ColorTranslator.FromHtml("#00C7BA");
item.TileStyle.BorderColor2 = ColorTranslator.FromHtml("#00C7BA");
//选中后菜品名称的颜色
item.TileStyle.TextColor = ColorTranslator.FromHtml("#FFFFFF");
item.TitleTextColor = ColorTranslator.FromHtml("#FFFFFF");
}
else
{
if (stock <= 0)
{
//正常情况下的背景颜色
item.TileStyle.BackColor = Color.DimGray;
item.TileStyle.BackColor2 = Color.DimGray;
item.TileStyle.BorderColor = Color.DimGray;
item.TileStyle.BorderColor2 = Color.DimGray;
item.TileStyle.TextColor = Color.White;
item.TitleTextColor = Color.White;
}
else
{
//正常情况下的背景颜色
item.TileStyle.BackColor = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BackColor2 = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BorderColor = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BorderColor2 = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.TextColor = ColorTranslator.FromHtml("#444444");
item.TitleTextColor = ColorTranslator.FromHtml("#444444");
}
}
}
break;
}
item.MouseDown -= OnProductMouseDown;
item.MouseDown += OnProductMouseDown;
mainContainer.SubItems.Add(item);
}
this.itemPanel.Items.Insert(0, mainContainer);
this.itemPanel.Invalidate();
}
catch (Exception ex)
{
LOGGER.Error(ex, "构建商品控件内容异常");
}
}
private void OnProductMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
MetroTileItem item = (MetroTileItem)sender;
var spec = item.Tag as ListProductSpec;
switch (spec.productName)
{
case Constant.PREV_PAGER:
{
this.PageNumber = spec.Pager;
this.BindDataSource(this._dataSource, this.SelectedCategorys);
}
break;
case Constant.NEXT_PAGER:
{
this.PageNumber = spec.Pager;
this.BindDataSource(this._dataSource, this.SelectedCategorys);
}
break;
default:
{
//已经被选中,再次点击取消选中
if (this.SelectedProducts.Exists(x => x.specId.Equals(spec.specId)))
{
//是否售罄0-售罄
decimal stock = 0.0M;
decimal.TryParse(string.IsNullOrEmpty(spec.stock) ? "0" : spec.stock, out stock);
if (stock <= 0)
{
//正常情况下的背景颜色
item.TileStyle.BackColor = Color.DimGray;
item.TileStyle.BackColor2 = Color.DimGray;
item.TileStyle.BorderColor = Color.DimGray;
item.TileStyle.BorderColor2 = Color.DimGray;
item.TileStyle.TextColor = Color.White;
item.TitleTextColor = Color.White;
}
else
{
//正常情况下的背景颜色
item.TileStyle.BackColor = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BackColor2 = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BorderColor = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.BorderColor2 = ColorTranslator.FromHtml("#E7EAF1");
item.TileStyle.TextColor = ColorTranslator.FromHtml("#444444");
item.TitleTextColor = ColorTranslator.FromHtml("#444444");
}
this.SelectedProducts.RemoveAll(x=>x.specId.Equals(spec.specId));
}
else
{
//选中情况下的背景颜色
item.TileStyle.BackColor = ColorTranslator.FromHtml("#00C7BA");
item.TileStyle.BackColor2 = ColorTranslator.FromHtml("#00C7BA");
item.TileStyle.BorderColor = ColorTranslator.FromHtml("#00C7BA");
item.TileStyle.BorderColor2 = ColorTranslator.FromHtml("#00C7BA");
//选中后菜品名称的颜色
item.TileStyle.TextColor = ColorTranslator.FromHtml("#FFFFFF");
item.TitleTextColor = ColorTranslator.FromHtml("#FFFFFF");
this.SelectedProducts.Add(spec);
}
}
break;
}
}
}
public event WeixinProductXEventHandler ProductXClick;
protected virtual void OnProductXClick(WeixinProductXEventArgs e)
{
ProductXClick?.Invoke(this, e);
}
/// <summary>
/// 分页List数据
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public List<T> ListPager<T>(List<T> data)
{
var result = new List<T>();
result.AddRange(data.Skip((this.PageNumber - 1) * this.PageSize).Take(this.PageSize));
return result;
}
private MetroTileItem _selectedItem = null;
public MetroTileItem SelectedItem
{
get { return this._selectedItem; }
private set { this._selectedItem = value; }
}
/// <summary>
/// 每页数量
/// </summary>
public int PageSize { get; private set; }
/// <summary>
/// 总页数
/// </summary>
public int PageCount => this.PageSize <= 0 ? 0 : ((TotalCount + this.PageSize - 1) / this.PageSize);
/// <summary>
/// 当前页码
/// </summary>
public int PageNumber { get; set; }
/// <summary>
/// 总数量
/// </summary>
public int TotalCount { get; private set; }
private int _columns = 1;
/// <summary>
/// 显示的列数
/// </summary>
public int Columns
{
get
{
return _columns;
}
set
{
_columns = (value < 0 ? 1 : value);
}
}
private int _rows = 1;
/// <summary>
/// 显示行数
/// </summary>
public int Rows
{
get
{
return _rows;
}
set
{
_rows = (value < 0 ? 1 : value);
}
}
public int ItemHeight { get; set; } = PRODUCT_DEFAULT_HEIGHT;
public int ItemWidth { get; set; } = PRODUCT_DEFAULT_WIDTH;
/// <summary>
/// 控件间距
/// </summary>
public int ItemSpace { get; set; } = 2;
}
public delegate void WeixinProductXEventHandler(object sender, WeixinProductXEventArgs e);
public class WeixinProductXEventArgs : EventArgs
{
public ListProductSpec Product;
public WeixinProductXEventArgs(ListProductSpec data)
{
this.Product = data;
}
}
public class WeixinProductXMerge
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static List<ListProductSpec> Merge(int rows, int cols, List<ListProductSpec> dataSource, bool touchEnabled)
{
Stopwatch sw = Stopwatch.StartNew();
//启用触摸屏,不分页
if (touchEnabled)
{
return dataSource;
}
//移除可能存在的分页标识
dataSource.RemoveAll(x => Constant.PREV_PAGER.Equals(x.productName) || Constant.NEXT_PAGER.Equals(x.productName));
int pageSize = rows * cols;
int totalCount = dataSource.Count;
//启用分页
int pageCount = ((totalCount - 1) + (pageSize - 2) - 1) / (pageSize - 2);
if (pageCount > 1)
{
int offset = 0;
for (int page = 1; page <= pageCount; page++)
{
if (page == 1)
{
offset = page * pageSize - 1;
var entity = new ListProductSpec();
entity.id = IdWorkerUtils.Instance.NextId();
entity.productName = Constant.NEXT_PAGER;
entity.Pager = (page + 1);
dataSource.Insert(offset, entity);
}
else if (page < pageCount)
{
offset = page * pageSize - 2;
var entity = new ListProductSpec();
entity.id = IdWorkerUtils.Instance.NextId();
entity.productName = Constant.PREV_PAGER;
entity.Pager = (page - 1);
dataSource.Insert(offset, entity);
offset++;
entity = new ListProductSpec();
entity.id = IdWorkerUtils.Instance.NextId();
entity.productName = Constant.NEXT_PAGER;
entity.Pager = (page + 1);
dataSource.Insert(offset, entity);
}
else
{
var entity = new ListProductSpec();
entity.id = IdWorkerUtils.Instance.NextId();
entity.productName = Constant.PREV_PAGER;
entity.Pager = (page - 1);
dataSource.Add(entity);
}
}
}
logger.Info("小程序商品控件插入分页控件,耗时<{0}>", sw.ElapsedMilliseconds);
return dataSource;
}
}
}