commit e89b64ea3a965cc2734af55827873c0960e71243 Author: hehaibing-1996 Date: Mon Apr 15 18:43:28 2024 +0800 !提交代码 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48a07ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc diff --git a/WCS.BLL/Config/LocalFile.cs b/WCS.BLL/Config/LocalFile.cs new file mode 100644 index 0000000..3a40d3d --- /dev/null +++ b/WCS.BLL/Config/LocalFile.cs @@ -0,0 +1,105 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.Config +{ + /// + /// 本地文件 + /// + public class LocalFile + { + /// + /// 程序运行名称(BaseUi.exe) + /// + public static readonly string AppName = AppDomain.CurrentDomain.FriendlyName; + /// + /// 程序运行目录 + /// + public static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory; + /// + /// 数据目录 + /// + public static readonly string DataDir = Path.Combine(AppDir, "data"); + /// + /// 日志目录 + /// + public static readonly string LogDir = Path.Combine(AppDir, "logs"); + /// + /// 运行主程序 + /// + public static readonly string AppPath = Path.Combine(AppDir, AppDomain.CurrentDomain.FriendlyName); + /// + /// 配置文件路径 + /// + public static readonly string ConfigPath = Path.Combine(DataDir, "jsconfig.json"); + /// + /// 货架模组编码正则表达式 + /// + public static readonly string ModuleCodePattern = "^[ABCD][0-9]{2}-R[0-9]{1,2}C[0-9]{1,2}$"; + + static object lockConfig = new object(); + + //static JsConfig config; + ///// + ///// 配置信息 + ///// + //public static JsConfig Config + //{ + // get + // { + // if (config != null) + // return config; + // else + // { + // try + // { + // if (File.Exists(ConfigPath)) + // lock (lockConfig) + // config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath, Encoding.UTF8)); + // else + // config = null; + // } + // catch (Exception) + // { + // config = null; + // } + // } + // return config ?? new JsConfig(); + // } + //} + + ///// + ///// 刷新配置信息。将本地的配置信息重新加载到内存中 + ///// + //public static void UpdateConfig() + //{ + // if (File.Exists(ConfigPath)) + // lock (lockConfig) + // config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath, Encoding.UTF8)); + // else + // config = null; + //} + + ///// + ///// 保存配置信息。将内存中的配置信息保存到本地 + ///// + //public static void SaveConfig() + //{ + // try + // { + // lock (lockConfig) + // File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(Config, Formatting.Indented), Encoding.UTF8); + // } + // catch (Exception ex) + // { + // UpdateConfig(); + // throw ex; + // } + //} + } +} diff --git a/WCS.BLL/DbModels/InventoryDetail.cs b/WCS.BLL/DbModels/InventoryDetail.cs new file mode 100644 index 0000000..3707137 --- /dev/null +++ b/WCS.BLL/DbModels/InventoryDetail.cs @@ -0,0 +1,117 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.DbModels; + +namespace WCS.BLL.DbModels +{ + /// + /// 库存明细表 + /// + [SugarTable("inventory_detail")] + public class InventoryDetail + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + #region 库位属性 + /// + /// 入库的库位表ID + /// + [SugarColumn(ColumnName = "store_id", IsNullable = false, ColumnDescription = "库位ID")] + public int StoreId { get; set; } + + /// + /// 入库的库位编码 + /// + [SugarColumn(ColumnName = "store_code", Length = 50, IsNullable = false, ColumnDescription = "库位编码")] + public string StoreCode { get; set; } + + [Navigate(NavigateType.OneToOne, nameof(StoreId))] + public StoreInfo StoreInfo { get; set; } + #endregion + + #region 物料属性 + /// + /// 物料编码(SN) + /// + [SugarColumn(ColumnName = "mat_sn", Length = 200, IsNullable = false, ColumnDescription = "物料SN")] + public string MatSN { get; set; } + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = true, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = true, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string MatSpec { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string MatBatch { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + #endregion + + /// + /// 入库时间 + /// + [SugarColumn(ColumnName = "instore_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime InstoreTime { get; set; } = DateTime.Now; + + /// + /// 入库操作人 + /// + [SugarColumn(ColumnName = "instore_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string InstoreUser { get; set; } + + /// + /// 物料是否已被锁定 + /// + [SugarColumn(ColumnName = "is_locked", IsNullable = false, ColumnDescription = "物料是否已被锁定")] + public bool IsLocked { get; set; } = false; + + /// + /// 序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + /// + /// 是否已经选择 + /// + [SugarColumn(IsIgnore = true)] + public bool IsSelected { get; set; } + } +} diff --git a/WCS.BLL/DbModels/MatBaseInfo.cs b/WCS.BLL/DbModels/MatBaseInfo.cs new file mode 100644 index 0000000..5bc5ca8 --- /dev/null +++ b/WCS.BLL/DbModels/MatBaseInfo.cs @@ -0,0 +1,121 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + ///物料基础信息 + /// + [SugarTable("mat_base_info")] + public partial class MatBaseInfo + { + /// + /// Desc: + /// Default: + /// Nullable:False + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = false, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = false, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string? MatSpec { get; set; } + + /// + /// Desc:物料单位 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "mat_unit", Length = 100, IsNullable = true, ColumnDescription = "物料单位")] + public string? MatUnit { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string? MatBatch { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } = 100; + + + /// + /// Desc:更新人 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_user", IsNullable = true, Length = 50, ColumnDescription = "更新人")] + public string? ModifyUser { get; set; } + + /// + /// Desc:更新时间 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_time", IsNullable = true, ColumnDescription = "更新时间")] + public DateTime? ModifyTime { get; set; } = DateTime.Now; + + /// + /// 是否启用 + /// + [SugarColumn(ColumnName = "is_enable", ColumnDescription = "是否启用")] + public bool IsEnable { get; set; } = true; + + [SugarColumn(IsIgnore = true)] + public string IsEnableStr + { + get + { + if (IsEnable) + return "启用"; + else + return "禁用"; + } + } + /// + /// 用于绑定DataGrid中是否选择 + /// + [SugarColumn(IsIgnore = true)] + public bool IsSelected { get; set; } + + /// + /// 用于绑定中显示序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + + + } +} diff --git a/WCS.BLL/DbModels/MatInfo.cs b/WCS.BLL/DbModels/MatInfo.cs new file mode 100644 index 0000000..71fac64 --- /dev/null +++ b/WCS.BLL/DbModels/MatInfo.cs @@ -0,0 +1,94 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + ///物料信息表 + /// + [SugarTable("mat_info")] + public class MatInfo + { + /// + /// 主键 Id 自增 + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_Sn", Length = 200, IsNullable = false, ColumnDescription = "物料唯一码")] + public string MatSn { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = false, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = false, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string? MatSpec { get; set; } + + + [SugarColumn(ColumnName = "mat_unit", Length = 100, IsNullable = true, ColumnDescription = "物料单位")] + public string? MatUnit { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string? MatBatch { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } + + /// + /// 是否启用 + /// + [SugarColumn(ColumnName = "is_printed", ColumnDescription = "是否已打印")] + public bool IsPrinted { get; set; } = true; + /// + /// Desc:更新人 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_user", IsNullable = true, Length = 50, ColumnDescription = "更新人")] + public string? ModifyUser { get; set; } + + /// + /// Desc:更新时间 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "modify_time", IsNullable = true, ColumnDescription = "更新时间")] + public DateTime? ModifyTime { get; set; } = DateTime.Now; + } +} diff --git a/WCS.BLL/DbModels/ModuleInfo.cs b/WCS.BLL/DbModels/ModuleInfo.cs new file mode 100644 index 0000000..e5e2112 --- /dev/null +++ b/WCS.BLL/DbModels/ModuleInfo.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.HardWare; + +namespace WCS.DAL.DbModels +{ + public partial class ModuleInfo + { + + /// + /// 模组Id + /// + public int Id { get; set; } + + /// + /// 模组编码 + /// + public string ModuleCode { get; set; } + + /// + /// 货架Id + /// + public int ShelfId { get; set; } + + /// + /// 货架编码 + /// + public string ShelfCode { get; set; } + + /// + /// 板子的Id + /// + public int BoardId { get; set; } + + /// + /// 板子上有几个灯 + /// + public int LightCount { get; set; } + + /// + /// 板子所连接模块的Ip + /// + public string CleintIp { get; set; } + + /// + /// 第几行 + /// + public string R { get; set; } + + /// + /// 第几列 + /// + public string C { get; set; } + + /// + /// 串联后大货架编码;大货架编码:未串联时是与货架编码是一对一的关系;串联后与货架编码是一对多 + /// + public string Bigshelfcode { get; set; } + + /// + /// 是否被禁用 + /// + public bool IsEnable { get; set; } + + + public Mode CurentMode { get; set; } = Mode.待机模式; + } +} diff --git a/WCS.BLL/DbModels/OutOrder.cs b/WCS.BLL/DbModels/OutOrder.cs new file mode 100644 index 0000000..d924566 --- /dev/null +++ b/WCS.BLL/DbModels/OutOrder.cs @@ -0,0 +1,61 @@ +using SqlSugar; + +namespace WCS.BLL.DbModels +{ + /// + /// 出库单据 + /// + [SugarTable("out_order")] + public class OutOrder + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 出库单据号 + /// + [SugarColumn(ColumnName = "order_number", Length = 50, IsNullable = false, ColumnDescription = "出库单据号")] + public string OrderNumber { get; set; } + + /// + /// 单据状态 + /// + [SugarColumn(ColumnName = "order_status", IsNullable = false, ColumnDescription = "单据状态")] + public OutOrderStatus OrderStatus { get; set; } = OutOrderStatus.未出库; + + /// + /// 单据来源 + /// + [SugarColumn(ColumnName = "order_source", Length = 50, IsNullable = true, ColumnDescription = "单据来源")] + public string OrderSource { get; set; } + + /// + /// 单据类型 + /// + [SugarColumn(ColumnName = "order_type", Length = 50, IsNullable = true, ColumnDescription = "单据类型")] + public string OrderType { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime CreateTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string CreateUser { get; set; } + + } + + public enum OutOrderStatus + { + 未出库 = 0, + 部分出库 = 1, + 全部出库 = 2 + } +} diff --git a/WCS.BLL/DbModels/OutOrderDetail.cs b/WCS.BLL/DbModels/OutOrderDetail.cs new file mode 100644 index 0000000..4bdc6c5 --- /dev/null +++ b/WCS.BLL/DbModels/OutOrderDetail.cs @@ -0,0 +1,60 @@ +using SqlSugar; + + +namespace WCS.BLL.DbModels +{ + /// + /// 出库单据明细表 + /// + [SugarTable("out_order_detail")] + public class OutOrderDetail + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 出库单据的主键ID + /// + [SugarColumn(ColumnName = "order_id", IsNullable = false)] + public int OrderId { get; set; } + + /// + /// 出库单据号 + /// + [SugarColumn(ColumnName = "order_number", Length = 50, IsNullable = false, ColumnDescription = "出库单据号")] + public string OrderNumber { get; set; } + + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = true, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string MatBatch { get; set; } + + /// + /// 物料需求数量 + /// + [SugarColumn(ColumnName = "req_qty", IsNullable = false, ColumnDescription = "物料需求数量")] + public int ReqQty { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime CreateTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string CreateUser { get; set; } + } +} diff --git a/WCS.BLL/DbModels/OutOrderMatDetail.cs b/WCS.BLL/DbModels/OutOrderMatDetail.cs new file mode 100644 index 0000000..3597411 --- /dev/null +++ b/WCS.BLL/DbModels/OutOrderMatDetail.cs @@ -0,0 +1,130 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.DbModels; + +namespace WCS.BLL.DbModels +{ + /// + /// 出库物料明细(库存数据加锁后缓存对应的数据并记录状态) + /// + [SugarTable("out_order_mat_detail")] + public class OutOrderMatDetail + { + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 出库单据的主键ID + /// + [SugarColumn(ColumnName = "order_id", IsNullable = false)] + public int OrderId { get; set; } + + /// + /// 出库单据号 + /// + [SugarColumn(ColumnName = "order_number", Length = 50, IsNullable = false, ColumnDescription = "出库单据号")] + public string OrderNumber { get; set; } + + /// + /// 出库单据明细的ID + /// + [SugarColumn(ColumnName = "out_order_detail_id", IsNullable = true)] + public int OutOrderDetailId { get; set; } + + /// + /// 库存的ID + /// + [SugarColumn(ColumnName = "inventory_detail_id", IsNullable = true)] + public int InventoryDetailId { get; set; } + + #region 库位属性 + /// + /// 入库的库位表ID + /// + [SugarColumn(ColumnName = "store_id", IsNullable = false, ColumnDescription = "库位ID")] + public int StoreId { get; set; } + + /// + /// 入库的库位编码 + /// + [SugarColumn(ColumnName = "store_code", Length = 50, IsNullable = false, ColumnDescription = "库位编码")] + public string StoreCode { get; set; } + + [Navigate(NavigateType.OneToOne, nameof(StoreId))] + public StoreInfo StoreInfo { get; set; } + #endregion + + #region 物料属性 + /// + /// 物料编码(SN) + /// + [SugarColumn(ColumnName = "mat_sn", Length = 200, IsNullable = false, ColumnDescription = "物料SN")] + public string MatSN { get; set; } + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "mat_code", Length = 100, IsNullable = true, ColumnDescription = "物料编号")] + public string MatCode { get; set; } + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "mat_name", Length = 150, IsNullable = true, ColumnDescription = "物料名称")] + public string MatName { get; set; } + + /// + /// 物料规格 + /// + [SugarColumn(ColumnName = "mat_spec", Length = 150, IsNullable = true, ColumnDescription = "物料规格")] + public string MatSpec { get; set; } + + /// + /// 物料批次 + /// + [SugarColumn(ColumnName = "mat_batch", Length = 150, IsNullable = true, ColumnDescription = "物料批次")] + public string MatBatch { get; set; } + + /// + /// 物料数量 + /// + [SugarColumn(ColumnName = "mat_qty", IsNullable = false, ColumnDescription = "物料数量")] + public int MatQty { get; set; } + + /// + /// 物料供应商 + /// + [SugarColumn(ColumnName = "mat_supplier", Length = 150, IsNullable = true, ColumnDescription = "物料供应商")] + public string? MatSupplier { get; set; } + + /// + /// 物料客户 + /// + [SugarColumn(ColumnName = "mat_customer", Length = 150, IsNullable = true, ColumnDescription = "物料客户")] + public string? MatCustomer { get; set; } + #endregion + + /// + /// 该物料是否已出库 + /// + [SugarColumn(ColumnName = "is_sended", IsNullable = false, ColumnDescription = "该物料是否已出库")] + public bool IsSended { get; set; } = false; + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false, ColumnDescription = "入库时间")] + public DateTime CreateTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_user", Length = 100, IsNullable = true, ColumnDescription = "操作员")] + public string CreateUser { get; set; } + } +} diff --git a/WCS.BLL/DbModels/ShelfInfo.cs b/WCS.BLL/DbModels/ShelfInfo.cs new file mode 100644 index 0000000..df5f5f6 --- /dev/null +++ b/WCS.BLL/DbModels/ShelfInfo.cs @@ -0,0 +1,99 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.HardWare; + +namespace WCS.DAL.DbModels +{ + [SugarTable("shelf_info")] + public class ShelfInfo + { + + /// + /// 主键 自增Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 货架编码;货架一般按照报警灯来区分 一个报警灯指示的是一个货架 + /// + [SugarColumn(ColumnName = "shelf_code", Length = 50, IsNullable = false, ColumnDescription = "货架编码;货架一般按照报警灯来区分 一个报警灯指示的是一个货架")] + public string ShelfCode { get; set; } + + /// + /// 货架类型Id + /// + [SugarColumn(ColumnName = "shelf_type_id", IsNullable = false, ColumnDescription = "货架类型Id")] + public int ShelfTypeId { get; set; } + + /// + /// 货架类型名称 + /// + [SugarColumn(ColumnName = "shelf_type_name", Length = 50, IsNullable = false, ColumnDescription = "货架类型名称")] + public string ShelfTypeName { get; set; } + + /// + /// 货架当前状态 + /// + [SugarColumn(ColumnName = "current_mode", IsNullable = false, ColumnDescription = "货架当前状态")] + public Mode CurrentMode { get; set; } + + /// + /// 货架行数 + /// + [SugarColumn(ColumnName = "row_counts", IsNullable = false, ColumnDescription = "货架行数")] + public int Rowcounts { get; set; } + + /// + /// 货架列数 + /// + [SugarColumn(ColumnName = "column_counts", IsNullable = false, ColumnDescription = "货架列数")] + public int Columncounts { get; set; } + + /// + /// 货架对应警示灯的Id + /// + [SugarColumn(ColumnName = "light_id", IsNullable = false, ColumnDescription = "货架对应警示灯的Id")] + public int LightId { get; set; } + + /// + /// 货架对应Can模块的Ip + /// + [SugarColumn(ColumnName = "client_ip", Length = 50, IsNullable = false, ColumnDescription = "货架对应Can模块的Ip")] + public string ClientIp { get; set; } + + /// + /// 货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架) + /// + [SugarColumn(ColumnName = "group_name", Length = 50, IsNullable = false, ColumnDescription = "货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架)")] + public string GroupName { get; set; } + + + /// + /// 是否串联绑定 + /// + [SugarColumn(ColumnName = "is_bind", IsNullable = false, ColumnDescription = "是否串联绑定")] + public bool IsBind { get; set; } + + /// + /// 串联绑定后的大货架编码 + /// + [SugarColumn(ColumnName = "Bind_shelf_code", IsNullable = true, ColumnDescription = "串联绑定后的大货架编码")] + public string? BindShelfCode { get; set; } = string.Empty; + + /// + /// 序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + /// + /// 是否已经选择 + /// + [SugarColumn(IsIgnore = true)] + public bool IsSelected { get; set; } + } +} diff --git a/WCS.BLL/DbModels/ShelfTypeInfo.cs b/WCS.BLL/DbModels/ShelfTypeInfo.cs new file mode 100644 index 0000000..6b0db4b --- /dev/null +++ b/WCS.BLL/DbModels/ShelfTypeInfo.cs @@ -0,0 +1,22 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + /// 货架类型 + /// + [SugarTable("shelf_type")] + public class ShelfTypeInfo + { + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + [SugarColumn(ColumnName = "shelf_type_name", Length = 50, IsNullable = true, ColumnDescription = "货架类型名称")] + public string ShelfTypeName { get; set; } + } +} diff --git a/WCS.BLL/DbModels/StoreInfo.cs b/WCS.BLL/DbModels/StoreInfo.cs new file mode 100644 index 0000000..f061e30 --- /dev/null +++ b/WCS.BLL/DbModels/StoreInfo.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL.DbModels +{ + public partial class StoreInfo + { + + /// + /// 库位Id + /// + public int Id { get; set; } + + /// + /// 库位编码 + /// + public string StoreCode { get; set; } + + /// + /// 模组Id + /// + public int ModuleId { get; set; } + + /// + /// 模组编号 + /// + public string ModuleCode { get; set; } + + /// + /// 货架Id + /// + public int ShelfId { get; set; } + + /// + /// 货架号 + /// + public string ShelfCode { get; set; } + + /// + /// 板子的Id + /// + public int BoardId { get; set; } + + /// + /// 板子上第几个灯 + /// + public int LightNumber { get; set; } + + /// + /// 优先级;为钢网柜推荐库位预留 + /// + public int Priority { get; set; } + + /// + /// 当前物料;货架这种一对一且带检测的就给这个赋值,方便出入库时的查询 + /// + public string CurrentMatSn { get; set; } + + /// + /// 当前电压;当前电压,调试排查问题用 + /// + public decimal CurrentVoltage { get; set; } + + /// + /// 标准电压;标准电压,调试排查问题用 + /// + public decimal StandardVoltage { get; set; } + + /// + /// 偏差电压;偏差电压,调试排查问题用 + /// + public decimal OffsetVoltage { get; set; } + } +} diff --git a/WCS.BLL/DbModels/SystemApiLogRecord.cs b/WCS.BLL/DbModels/SystemApiLogRecord.cs new file mode 100644 index 0000000..e1ae5a9 --- /dev/null +++ b/WCS.BLL/DbModels/SystemApiLogRecord.cs @@ -0,0 +1,102 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.DbModels +{ + /// + /// 系统接口日志记录 + /// + [SugarTable("system_api_log_record")] + public class SystemApiLogRecord + { + /// + /// 主键Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsNullable = false, IsIdentity = true)] + public int Id { get; set; } + + [SugarColumn(ColumnName = "request_type", IsNullable = false, ColumnDescription = "调用/被调用 0 = 被调用,1 = 调用")] + /// + /// 调用/被调用 0 = 被调用 1 = 调用 + /// + public string RequestType { get; set; } = "被调用"; + + /// + /// 用户名称 + /// + [SugarColumn(ColumnName = "user_name", IsNullable = true, ColumnDescription = "用户名称")] + public string UserName { get; set; } + + /// + /// 设备类型 + /// + [SugarColumn(ColumnName = "device_type", IsNullable = true, ColumnDescription = "用户名称")] + public string DeviceType { get; set; } + + /// + /// 设备Ip + /// + [SugarColumn(ColumnName = "device_ip", IsNullable = true, ColumnDescription = "设备Ip")] + public string DeviceIp { get; set; } + + /// + /// 请求地址 + /// + [SugarColumn(ColumnName = "request_url", IsNullable = true, ColumnDescription = "请求地址")] + public string RequestUrl { get; set; } + + /// + /// 请求Body + /// + [SugarColumn(ColumnName = "request_body", IsNullable = true, ColumnDescription = "请求Body")] + public string RequestBody { get; set; } + + /// + /// 请求Body + /// + [SugarColumn(ColumnName = "query_string", IsNullable = true, ColumnDescription = "请求Body")] + public string QueryString { get; set; } + + /// + /// 是否响应 + /// + [SugarColumn(ColumnName = "is_response", IsNullable = true, ColumnDescription = "是否响应")] + public bool IsResponse { get; set; } + + /// + /// 响应返回内容 + /// + [SugarColumn(ColumnName = "response_json", IsNullable = true, ColumnDescription = "响应返回内容")] + public string ResponseJson { get; set; } + + /// + /// 开始请求时间 + /// + [SugarColumn(ColumnName = "request_time", IsNullable = true, ColumnDescription = "开始请求时间")] + public DateTime RequestTime { get; set; } + + /// + /// 响应时间 + /// + [SugarColumn(ColumnName = "response_time", IsNullable = true, ColumnDescription = "响应时间")] + public DateTime ResponseTime { get; set; } + + /// + /// 请求处理时长(ms) + /// + [SugarColumn(ColumnName = "execution_time", IsNullable = true, ColumnDescription = "请求处理时长(ms)")] + public long ExecutionTime { get; set; } + + /// + /// 序号 + /// + [SugarColumn(IsIgnore = true)] + public int RowNumber { get; set; } + + } +} + diff --git a/WCS.BLL/HardWare/IModuleBase.cs b/WCS.BLL/HardWare/IModuleBase.cs new file mode 100644 index 0000000..9b04c1a --- /dev/null +++ b/WCS.BLL/HardWare/IModuleBase.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.HardWare +{ + public interface IModuleBase + { + /// + /// 模组Id + /// + int ModuleId { get; set; } + + /// + /// 是否启用 + /// + bool IsEnable { get; set; } + + /// + /// 当前模式 + /// + Mode CurrentMode { get; set; } + + /// + /// 设置当前模式 + /// + void SetCurrentMode(); + } +} diff --git a/WCS.BLL/HardWare/IShelfBase.cs b/WCS.BLL/HardWare/IShelfBase.cs new file mode 100644 index 0000000..6089ff1 --- /dev/null +++ b/WCS.BLL/HardWare/IShelfBase.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.HardWare +{ + /// + /// 货架基类 + /// + public interface IShelfBase + { + /// + /// 货架ID 数据库中那个 + /// + public int ShelfId { get; set; } + + /// + /// 货架编码 + /// + public string ShelfCode { get; set; } + + /// + /// 货架模组行数 + /// + public int RowCounts { get; set; } + + /// + /// 货架模组列数 + /// + public int ColumnCounts { get; set; } + + /// + /// 货架当前模式 + /// + public Mode CurentMode { get; set; } + + public MatInfoModel InStoreData { get; set; } + + public string OutOrderNumber { get; set; }//出库模式中的单据 + + public string ModulesStr { get; set; } + + /// + /// 货架组别 + /// + public string GroupName { get; set; } + /// + /// 模组 + /// + //public List Modules { get; set; } + + /// + /// 设置货架模式 + /// + public void SetCurrentMode(); + + /// + /// 货架进入入库模式 + /// + public void GoInInstore(string? IPAdress); + + /// + /// 货架退出入库模式 + /// + public void GoOutInstore(); + + /// + /// 货架进入出库模式 + /// + public void GoInOutstore(); + + /// + /// 货架退出出库模式 + /// + public void GoOutOutstore(); + + /// + /// 货架进入盘点模式 + /// + public void GoInStocktaking(); + + /// + /// 货架退出盘点模式 + /// + public void GoOutStocktaking(); + + /// + /// 货架报警 + /// + public void Warning(); + + /// + /// 货架复位 + /// + public void Reset(); + } + + public enum Mode + { + 待机模式 = 0, + 入库模式 = 1, + 出库模式 = 2, + 盘点模式 = 3 + } +} diff --git a/WCS.BLL/HardWare/IWarningLightBase.cs b/WCS.BLL/HardWare/IWarningLightBase.cs new file mode 100644 index 0000000..d6cbfe1 --- /dev/null +++ b/WCS.BLL/HardWare/IWarningLightBase.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.HardWare +{ + public interface IWarningLightBase + { + public void BlueLight(); + } +} diff --git a/WCS.BLL/HardWare/SingleLightShelf.cs b/WCS.BLL/HardWare/SingleLightShelf.cs new file mode 100644 index 0000000..35ec74a --- /dev/null +++ b/WCS.BLL/HardWare/SingleLightShelf.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.HardWare +{ + public class SingleLightShelf : IShelfBase + { + public int ShelfId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ShelfCode { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public int RowCounts { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public int ColumnCounts { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public Mode CurentMode { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ModulesStr { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string GroupName { get; set; } + public MatInfoModel InStoreData { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public string OutOrderNumber { get; set; } + + public void GoInInstore(string IPAdress) + { + throw new NotImplementedException(); + } + + public void GoInOutstore() + { + throw new NotImplementedException(); + } + + public void GoInStocktaking() + { + throw new NotImplementedException(); + } + + public void GoOutInstore() + { + throw new NotImplementedException(); + } + + public void GoOutOutstore() + { + throw new NotImplementedException(); + } + + public void GoOutStocktaking() + { + throw new NotImplementedException(); + } + + public void Reset() + { + throw new NotImplementedException(); + } + + public void SetCurrentMode() + { + throw new NotImplementedException(); + } + + public void Warning() + { + throw new NotImplementedException(); + } + } +} diff --git a/WCS.BLL/HardWare/SmartShelf.cs b/WCS.BLL/HardWare/SmartShelf.cs new file mode 100644 index 0000000..ad04c17 --- /dev/null +++ b/WCS.BLL/HardWare/SmartShelf.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.DAL; +using WCS.DAL.Db; +using WCS.DAL.DbModels; +using WCS.Model; + +namespace WCS.BLL.HardWare +{ + /// + /// 智能货架 + /// + public class SmartShelf : IShelfBase + { + public SmartShelf(ShelfInfo shelfInfo) + { + ShelfId = shelfInfo.Id; + ShelfCode = shelfInfo.ShelfCode; + RowCounts = shelfInfo.Rowcounts; + ColumnCounts = shelfInfo.Columncounts; + CurentMode = shelfInfo.CurrentMode; + + //初始化Module + Task.Run(() => + { + var modules = DbHelp.db.Queryable().Where(t => t.ShelfId == ShelfId).ToList(); + foreach (var module in modules) + { + Modules.Add(new SmartShelfModule() + { + ModuleId = module.Id, + ModuleCode = module.ModuleCode, + IsEnable = module.IsEnable, + CurrentMode = module.CurentMode + }); + } + ModulesStr = string.Join(";", Modules.Select(t => t.ModuleCode)); + }); + + //初始化TCPCleint + TcpCleint = new TCPClient("127.0.0.1:20002", "127.0.0.1:20003"); + TcpCleint.Connect(); + TcpCleint.tcpClient.Received += (client, e) => + { + var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); + e.ByteBlock.Clear(); + var len = data.Length; + for (int index = 0; index < data.Length - TcpCleint.PreFixLength; index++) + { + //协议拆包 通过前缀校验是否为完整数据包 + var prefixInData = data.Skip(index).Take(TcpCleint.PreFixLength); + var isEqual = prefixInData.SequenceEqual(TcpCleint.Prefix); + if (isEqual) + { + var dataTemp = data.Skip(index).Take(TcpCleint.PreFixLength + TcpCleint.DataLength).ToArray(); + if (dataTemp.Length < TcpCleint.PreFixLength + TcpCleint.DataLength)//拆包后不满足一条指令的长度 + { + continue; + } + index += (TcpCleint.PreFixLength + TcpCleint.DataLength - 1);//每次循环index会+1 所以这里-1 + //获取板子ID + var boardId = (data[TcpCleint.PreFixLength + 0] << 8) + data[TcpCleint.PreFixLength + 1]; + //协议处理 判断功能位 + switch (dataTemp[TcpCleint.PreFixLength + 2]) + { + case 0x01: + ; + break; + default: + ; + break; + } + } + } + return EasyTask.CompletedTask; + }; + } + + public int ShelfId { get; set; } + public string ShelfCode { get; set; } + public int RowCounts { get; set; } + public int ColumnCounts { get; set; } + public Mode CurentMode { get; set; } + public string ModulesStr { get; set; }//当前货架所有模组的Str + public string GroupName { get; set; } + public List Modules { get; set; } = new List(); + public TCPClient TcpCleint { get; set; } + + public IWarningLightBase WarningLight { get; set; } + public List ExceptionMessages { get; set; } = new List(); + + public string? InstoreIpAddress { get; set; } = string.Empty; + + public MatInfoModel InStoreData { get; set; } + + public string OutOrderNumber { get; set; } + + public void GoInInstore(string? IPAddress) + { + //判断当前模式是否为待机模式 + if (this.CurentMode != Mode.待机模式) + { + return; + } + else + { + this.CurentMode = Mode.入库模式; + } + //货架所有模组发送指令进入入库模式 + foreach (var module in Modules.Where(t => t.IsEnable).ToList()) + { + module.GoInInstoreMode(TcpCleint); + } + //延时获取异常 + var timeOut = 3000; + var timeSpan = TimeSpan.FromMilliseconds(0); + var beginTime = DateTime.Now; + while (timeSpan <= TimeSpan.FromMilliseconds(timeOut)) + { + timeSpan = DateTime.Now - beginTime; + //接收到第一个异常就不继续循环了 + if (ExceptionMessages.Count() > 0) + { + var deficientTime = timeOut - (int)timeSpan.TotalMilliseconds; + if (deficientTime > 0) + Thread.Sleep(deficientTime); + //出现异常的未进入入库模式,有红灯进行指引 + //未出现异常的需要退出入库模式 + GoOutInstore(); + return; + } + //延时处理 + Thread.Sleep(50); + } + //警示灯亮起 + //WarningLight.BlueLight(); + //绑定当前入库PDA的IP + InstoreIpAddress = IPAddress; + //返回成功 + return; + + } + + public void GoInInstoreReturn() + { + + } + + public void GoOutInstore() + { + //看货架是否为入库模式 + if (CurentMode != Mode.入库模式) + { + return; + } + else + { + this.CurentMode = Mode.待机模式; + } + //货架所有模组发送指令退出入库模式 + foreach (var module in Modules.Where(t => t.IsEnable) + .Where(t => t.CurrentMode == Mode.入库模式) + .ToList()) + { + module.GoOutInstoreMode(TcpCleint); + } + } + + public void GoInOutstore() + { + throw new NotImplementedException(); + } + + public void GoInStocktaking() + { + throw new NotImplementedException(); + } + + + public void GoOutOutstore() + { + throw new NotImplementedException(); + } + + public void GoOutStocktaking() + { + throw new NotImplementedException(); + } + + void IShelfBase.Reset() + { + throw new NotImplementedException(); + } + + void IShelfBase.SetCurrentMode() + { + throw new NotImplementedException(); + } + + void IShelfBase.Warning() + { + throw new NotImplementedException(); + } + } +} diff --git a/WCS.BLL/HardWare/SmartShelfModule.cs b/WCS.BLL/HardWare/SmartShelfModule.cs new file mode 100644 index 0000000..9323f16 --- /dev/null +++ b/WCS.BLL/HardWare/SmartShelfModule.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.Db; +using WCS.DAL.DbModels; + +namespace WCS.BLL.HardWare +{ + public class SmartShelfModule : IModuleBase + { + #region 协议明细 + /// + /// 进入入库模式 + /// + public byte[] GoInInstoreData = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /// + /// 退出入库模式 + /// + public byte[] GoOutInstoreData = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + #endregion + public int ModuleId { get; set; } + public string ModuleCode { get; set; } + public bool IsEnable { get; set; } + public Mode CurrentMode { get; set; } + + public void SetCurrentMode() + { + + } + + public void GoInInstoreMode(TCPClient tcpCleint) + { + + if (CurrentMode != Mode.待机模式) + { + //退出对应的模式 然后再发送进入入库模式 + } + + var storeInfos = DbHelp.db.Queryable() + .Where(t => t.BoardId == ModuleId) + .OrderBy(t => t.LightNumber) + .ToList(); + char[] data = "0000000000000000".ToCharArray(); + var boardStoreNumber = storeInfos.Count(); + foreach (var storeInfo in storeInfos) + { + if (!string.IsNullOrEmpty(storeInfo.CurrentMatSn) && storeInfo.LightNumber > 0 && storeInfo.LightNumber <= boardStoreNumber) + { + data[storeInfo.LightNumber - 1] = '1'; + } + } + var dataStr = string.Join("", data.Reverse()); + var data1 = dataStr.Substring(8, 8); + var data2 = dataStr.Substring(0, 8); + GoInInstoreData[1] = Convert.ToByte(data1, 2); + GoInInstoreData[2] = Convert.ToByte(data2, 2); + + tcpCleint.Send(tcpCleint.GenerateMessage(ModuleId, GoInInstoreData)); + } + + public void GoOutInstoreMode(TCPClient tcpCleint) + { + if (CurrentMode == Mode.入库模式) + { + tcpCleint.Send(tcpCleint.GenerateMessage(ModuleId, GoOutInstoreData)); + } + else + { + //退出对应的模式 回到待机状态 并记录对应的状态日志(这个分支肯定是异常了) + //记录错误日志 + } + } + + + + } +} diff --git a/WCS.BLL/Manager/ShelfManager.cs b/WCS.BLL/Manager/ShelfManager.cs new file mode 100644 index 0000000..aba6b95 --- /dev/null +++ b/WCS.BLL/Manager/ShelfManager.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.DbModels; +using WCS.BLL.HardWare; +using WCS.DAL.Db; +using WCS.DAL.DbModels; + +namespace WCS.BLL.Manager +{ + public static class ShelfManager + { + public static List Shelves { get; set; } = new List(); + static ShelfManager() + { + + } + + public static void InitShelves() + { + DbHelp.db.CodeFirst.InitTables(typeof(ModuleInfo), typeof(ShelfInfo), typeof(StoreInfo) + , typeof(InventoryDetail), typeof(OutOrder), typeof(OutOrderDetail), typeof(OutOrderMatDetail) + , typeof(ShelfTypeInfo), typeof(MatBaseInfo), typeof(MatInfo) + ); + + DbHelp.dbLog.CodeFirst.InitTables(typeof(SystemApiLogRecord)); + + var shelvesInDb = DbHelp.db.Queryable().ToList(); + foreach (var shelfInDb in shelvesInDb) + { + Shelves.Add(InitShelf(shelfInDb)); + } + } + + public static IShelfBase InitShelf(ShelfInfo shelfInDb) + { + switch (shelfInDb.ShelfTypeId) + { + case 1: + return new SmartShelf(shelfInDb) + { + ShelfId = shelfInDb.Id, + ShelfCode = shelfInDb.ShelfCode, + GroupName = shelfInDb.GroupName, + }; + default: + return null; + } + } + + public static void GoInInstore() + { + + } + + } +} diff --git a/WCS.BLL/Services/IService/IHomerService.cs b/WCS.BLL/Services/IService/IHomerService.cs new file mode 100644 index 0000000..95ade5b --- /dev/null +++ b/WCS.BLL/Services/IService/IHomerService.cs @@ -0,0 +1,8 @@ + +namespace WCS.BLL.Services.IService +{ + public interface IHomerService + { + + } +} diff --git a/WCS.BLL/Services/IService/IInstoreService.cs b/WCS.BLL/Services/IService/IInstoreService.cs new file mode 100644 index 0000000..779ac5c --- /dev/null +++ b/WCS.BLL/Services/IService/IInstoreService.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.Services.IService +{ + public interface IInstoreService + { + public ResponseBase shelfGoInInStore(ShelfGoInInstoreRequest request); + public ResponseBase shelfGoOutInStore(ShelfGoOutInStoreRequest request); + public ResponseBase queryByMatSn(QueryByMatSnRequest request); + public Task queryInstoreStatus(QueryByMatSnRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IInterfaceRecordService.cs b/WCS.BLL/Services/IService/IInterfaceRecordService.cs new file mode 100644 index 0000000..24fab4d --- /dev/null +++ b/WCS.BLL/Services/IService/IInterfaceRecordService.cs @@ -0,0 +1,17 @@ + +using WCS.BLL.DbModels; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + + public interface IInterfaceRecordService + { + public Task> getInterfaceRecord(GetInterfaceRecordsRequest request); + + public Task> exportInterfaceRecord(GetInterfaceRecordsRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IMatBaseInfoService.cs b/WCS.BLL/Services/IService/IMatBaseInfoService.cs new file mode 100644 index 0000000..902a22b --- /dev/null +++ b/WCS.BLL/Services/IService/IMatBaseInfoService.cs @@ -0,0 +1,26 @@ + +using WCS.BLL.DbModels; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + + public interface IMatBaseInfoService + { + public Task> getMatBaseInfo(GetMatBaseInfoRequest request); + + public Task> exportMatBaseInfo(GetMatBaseInfoRequest request); + + public Task>> importMatBaseInfo(List lists,string userName,string deviceType); + + public Task> addOrUpdateMatBaseInfo(AddMatBaseInfoRequest request); + + public Task> deleteMatBaseInfo(DeleteMatBaseInfosRequest request); + + public Task>> getMatCodeList(GetMatCodeListRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IMatInventoryDetailService.cs b/WCS.BLL/Services/IService/IMatInventoryDetailService.cs new file mode 100644 index 0000000..d8363db --- /dev/null +++ b/WCS.BLL/Services/IService/IMatInventoryDetailService.cs @@ -0,0 +1,18 @@ + +using WCS.BLL.DbModels; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + + public interface IMatInventoryDetailService + { + public Task> getMatInventoryDetail(GetMatInventoryDetailRequest request); + + public Task> exportMatInventoryDetail(GetMatInventoryDetailRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IOutstoreService.cs b/WCS.BLL/Services/IService/IOutstoreService.cs new file mode 100644 index 0000000..549d945 --- /dev/null +++ b/WCS.BLL/Services/IService/IOutstoreService.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace WCS.BLL.Services.IService +{ + public interface IOutstoreService + { + public Task SysOutOrderByMatCode(SysOutOrderByMatCodeRequest request); + + public Task SysOutOrderByMatSn(SysOutOrderByMatSnRequest request); + + public Task GetOutOrderList(GetOutOrderListRequest request); + + public Task GetOutOrderDetail(GetOutOrderDetailRequest request); + + public Task GoInOutstore(GetOutOrderDetailRequest request); + + public Task GoOutOutstore(GetOutOrderDetailRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IStoreInfoService.cs b/WCS.BLL/Services/IService/IStoreInfoService.cs new file mode 100644 index 0000000..4b81485 --- /dev/null +++ b/WCS.BLL/Services/IService/IStoreInfoService.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.AuthDbModel; +using WCS.Model.ApiModel.User; +using WCS.Model; +using WCS.DAL.DbModels; +using WCS.Model.ApiModel.StoreInfo; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; + +namespace WCS.BLL.Services.IService +{ + public interface IStoreInfoService + { + /// + /// 查询货架列表 + /// + /// + /// + public Task> GetShelves(GetShelvesRequest request); + /// + /// 添加、更新、删除货架 + /// + /// + /// + public Task> addOrUpdateShelfInfo(AddShelfInfoRequest request); + } +} diff --git a/WCS.BLL/Services/IService/IUserService.cs b/WCS.BLL/Services/IService/IUserService.cs new file mode 100644 index 0000000..0c64920 --- /dev/null +++ b/WCS.BLL/Services/IService/IUserService.cs @@ -0,0 +1,29 @@ + +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.IService +{ + /// + /// 权限用户所有的后台处理方法 + /// + public interface IUserService + { + /// + /// 模糊查询用户列表 + /// + /// + /// + public Task>> GetUsers(GetUsersRequest request); + + public Task> AddUser(AddUserRequest request); + + public Task> UserLogin(UserLoginRequest request); + + public Task>> GetRoles(GetUsersRequest request); + + public Task> AddRole(AddRoleRequest request); + } +} diff --git a/WCS.BLL/Services/Service/HomerService.cs b/WCS.BLL/Services/Service/HomerService.cs new file mode 100644 index 0000000..2f12a50 --- /dev/null +++ b/WCS.BLL/Services/Service/HomerService.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.Services.IService; + +namespace WCS.BLL.Services.Service +{ + public class HomerService: IHomerService + { + public HomerService() { } + } +} diff --git a/WCS.BLL/Services/Service/InstoreService.cs b/WCS.BLL/Services/Service/InstoreService.cs new file mode 100644 index 0000000..5858294 --- /dev/null +++ b/WCS.BLL/Services/Service/InstoreService.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using WCS.BLL.Config; +using WCS.BLL.HardWare; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.DAL.Db; +using WCS.Model; + +namespace WCS.BLL.Services.Service +{ + public class InstoreService : IInstoreService + { + public InstoreService() { } + + public ResponseBase shelfGoInInStore(ShelfGoInInstoreRequest request) + { + //校验货架编码规则 + bool isValid = Regex.IsMatch(request.ModuleCode, LocalFile.ModuleCodePattern); + if (!isValid) + { + return new ResponseBase() + { + Code = 202, + Message = $"模组编码{request.ModuleCode}不满足模组编码规则!", + }; + } + //找到模组对应的货架 + var shelf = ShelfManager.Shelves.Where(t => t.ModulesStr.Contains(request.ModuleCode)).FirstOrDefault(); + if (shelf == null)//未找到 + { + return new ResponseBase() + { + Code = 201, + Message = "未找到模组对应的货架", + }; + } + //已找到模组对应货架 + shelf.GoInInstore(request.IpAdress); + + //成功进入入库模式 + return new ShelfGoInInstoreResponse() + { + Code = 200, + Message = "货架进入入库模式成功!", + Data = new ShelfGoInInstoreDto() + { + ShelfCode = shelf.ShelfCode, + ModulesStr = shelf.ModulesStr, + } + }; + } + + public ResponseBase shelfGoOutInStore(ShelfGoOutInStoreRequest request) + { + //获取货架 + var shelf = ShelfManager.Shelves.Where(t => t.ShelfCode == request.ShelfCode).FirstOrDefault(); + if (shelf == null)//货架不存在 + { + return new ResponseCommon() + { + Code = 201, + Message = $"退出入库模式失败:货架[{request.ShelfCode}]不存在!", + }; + } + //TO DO 判断扫码枪 是否被其他扫码枪所占用 如果占用 直接退出入库模式 不发指令 + //两个扫码枪互相占用入库会有问题 + shelf.GoOutInstore(); + + return new ResponseCommon() + { + Code = 200, + Message = $"货架[{request.ShelfCode}]已退出入库模式!", + }; + } + + public ResponseBase queryByMatSn(QueryByMatSnRequest request) + { + //获取货架 + var shelf = ShelfManager.Shelves.Where(t => t.ShelfCode == request.ShelfCode).FirstOrDefault(); + if (shelf == null)//货架不存在 + { + return new QueryByMatSnResponse() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不存在!", + }; + } + //判断当前是否是入库模式 + if (shelf.CurentMode != Mode.入库模式) + { + return new QueryByMatSnResponse() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不在入库模式!\r\n当前为{shelf.CurentMode}", + }; + } + //调用接口或者直接查询数据库 + if (1 == 1) + { + + } + //查询数据库 + else + { + + } + return new QueryByMatSnResponse() + { + Code = 200, + Data = new MatInfoModel(), + Message = "success" + }; + } + + public async Task queryInstoreStatus(QueryByMatSnRequest request) + { + //获取货架 + var shelf = ShelfManager.Shelves.Where(t => t.ShelfCode == request.ShelfCode).FirstOrDefault(); + if (shelf == null)//货架不存在 + { + return new ResponseCommon() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不存在!", + }; + } + //判断当前是否是入库模式 + if (shelf.CurentMode != Mode.入库模式) + { + return new ResponseCommon() + { + Code = 201, + Message = $"操作失败:货架[{request.ShelfCode}]不在入库模式!\r\n当前为{shelf.CurentMode}", + }; + } + //这个时间相当于需要入库扫码后需要等待的时间 + var timeOut = 5000; + var timeSpan = TimeSpan.FromMilliseconds(0); + var beginTime = DateTime.Now; + while (timeSpan <= TimeSpan.FromMilliseconds(timeOut)) + { + timeSpan = DateTime.Now - beginTime; + //已入库当前扫码的物料时 查询数据库 + if (shelf.InStoreData == null || (shelf.InStoreData as object) == null) + { + await Task.Delay(50); + //var inventoryDetail = DbHelp.db.Queryable().Where(t => t.MatSN == dto.matSn).First(); + //if (inventoryDetail != null) + //{ + // return Json(HttpResponseCommon.GetSuccessResponse($"{inventoryDetail.StoreCode}", null)); + //} + } + //延时处理 + Thread.Sleep(50); + } + + return new ResponseCommon() + { + Code = 200, + Message = $"success", + }; + } + } +} diff --git a/WCS.BLL/Services/Service/InterfaceRecordService.cs b/WCS.BLL/Services/Service/InterfaceRecordService.cs new file mode 100644 index 0000000..cab7205 --- /dev/null +++ b/WCS.BLL/Services/Service/InterfaceRecordService.cs @@ -0,0 +1,128 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class InterfaceRecordService : IInterfaceRecordService + { + public InterfaceRecordService() { } + + public async Task> getInterfaceRecord(GetInterfaceRecordsRequest request) + { + try + { + var recordsQueryable = DbHelp.dbLog.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.RequestType), t => t.RequestType == request.RequestType) + .WhereIF(!string.IsNullOrEmpty(request.RequestUrl), t => t.RequestUrl.Contains(request.RequestUrl)) + .WhereIF(!string.IsNullOrEmpty(request.RequestBody), t => t.RequestBody.Contains(request.RequestBody)); + if (request.TimeType == TimeType.请求时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.RequestTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.RequestTime); + } + else if (request.TimeType == TimeType.响应时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.ResponseTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.ResponseTime); + } + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + //Task.WaitAll(new Task[] { recordsTask, totalCountTask }); + + //var records = recordsTask.Result; + //var totalCount = totalCountTask.Result; + + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> exportInterfaceRecord(GetInterfaceRecordsRequest request) + { + try + { + var recordsQueryable = DbHelp.dbLog.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.RequestType), t => t.RequestType == request.RequestType) + .WhereIF(!string.IsNullOrEmpty(request.RequestUrl), t => t.RequestUrl.Contains(request.RequestUrl)) + .WhereIF(!string.IsNullOrEmpty(request.RequestBody), t => t.RequestBody.Contains(request.RequestBody)); + if (request.TimeType == TimeType.请求时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.RequestTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.RequestTime); + } + else if (request.TimeType == TimeType.响应时间) + { + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.StartTime <= t.ResponseTime); + recordsQueryable = recordsQueryable.WhereIF(request.StartTime != null, t => request.EndTime >= t.ResponseTime); + } + var records = await recordsQueryable.ToListAsync(); + //生成序号 + var index = 1; + records.ForEach(r => + { + r.RowNumber = index++; + }); + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + Lists = records + } + }; + + + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + } +} diff --git a/WCS.BLL/Services/Service/MatBaseInfoService.cs b/WCS.BLL/Services/Service/MatBaseInfoService.cs new file mode 100644 index 0000000..e1e7557 --- /dev/null +++ b/WCS.BLL/Services/Service/MatBaseInfoService.cs @@ -0,0 +1,416 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + /// + /// 物料基础信息 + /// + public class MatBaseInfoService : IMatBaseInfoService + { + public MatBaseInfoService() { } + + public async Task> getMatBaseInfo(GetMatBaseInfoRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.MatCode), t => t.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), t => t.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), t => t.MatSpec.Contains(request.MatSpec)) + .WhereIF(request.IsEnable != null, t => t.IsEnable == request.IsEnable.GetValueOrDefault()); + + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> exportMatBaseInfo(GetMatBaseInfoRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.MatCode), t => t.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), t => t.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), t => t.MatSpec.Contains(request.MatSpec)) + .WhereIF(request.IsEnable != null, t => t.IsEnable == request.IsEnable.GetValueOrDefault()); + var records = await recordsQueryable.ToListAsync(); + //生成序号 + var index = 1; + records.ForEach(r => + { + r.RowNumber = index++; + }); + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + Lists = records + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task>> importMatBaseInfo(List lists, string userName, string deviceType) + { + + //获取数据 + #region 校验导入的编号是否重复 + var matCodes = lists.Select(t => t.物料编码) + .ToList(); + var duplicates = matCodes.GroupBy(x => x) + .Where(g => g.Count() > 1) + .Select(g => g.Key).ToList(); + //有重复的情况 + if (duplicates.Count > 0) + { + return new ResponseCommon>() + { + Code = 201, + Message = "导入失败:文件中存在物料编码重复", + Data = duplicates + }; + } + #endregion + + #region 校验导入数据与数据库中数据是否有重复数据 + duplicates = await DbHelp.db.Queryable() + .Where(t => matCodes.Contains(t.MatCode)) + .Select(t => t.MatCode) + .ToListAsync(); + + //有重复的情况 + if (duplicates.Count > 0) + { + return new ResponseCommon>() + { + Code = 201, + Message = "导入失败:以下物料编码已存在", + Data = duplicates + }; + } + #endregion + + #region 导入数据 + try + { + await DbHelp.db.BeginTranAsync(); + foreach (var mat in lists) + { + var matBaseInfo = new MatBaseInfo() + { + MatCode = mat.物料编码, + MatName = mat.名称, + MatSpec = mat.规格, + MatUnit = mat.单位, + MatCustomer = mat.客户, + IsEnable = mat.状态 == "启用" ? true : false, + }; + await DbHelp.db.Insertable(matBaseInfo).ExecuteCommandAsync(); + } + await DbHelp.db.CommitTranAsync(); + return new ResponseCommon>() + { + Code = 200, + Message = "导入数据成功", + Data = null + }; + } + catch (Exception ex) + { + await DbHelp.db.RollbackTranAsync(); + var ErrList = new List + { + ex.Message + }; + return new ResponseCommon>() + { + Code = 200, + Message = "导入失败", + Data = ErrList + }; + } + #endregion + } + + public async Task> addOrUpdateMatBaseInfo(AddMatBaseInfoRequest request) + { + try + { + var matBaseInfo = await DbHelp.db.Queryable() + .Where(t => t.MatCode == request.MatBaseInfo.MatCode) + .FirstAsync(); + //修改物料基础数据 + if (request.AddOrUpdate == AddOrUpdate.Update) + { + if (matBaseInfo == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新物料基础数据失败:物料{request.MatBaseInfo}不存在!", + Data = null + }; + } + else + { + matBaseInfo.MatName = request.MatBaseInfo.MatName; + matBaseInfo.MatSpec = request.MatBaseInfo.MatSpec; + matBaseInfo.MatUnit = request.MatBaseInfo.MatUnit; + matBaseInfo.MatCustomer = request.MatBaseInfo.MatCustomer; + matBaseInfo.IsEnable = request.MatBaseInfo.IsEnable; + + + matBaseInfo.ModifyTime = request.MatBaseInfo.ModifyTime; + matBaseInfo.ModifyUser = request.MatBaseInfo.ModifyUser; + + var rowNum = await DbHelp.db.Updateable(matBaseInfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新物料基础数据失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新物料基础数据成功!", + Data = null + }; + } + } + } + + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (matBaseInfo != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"物料基础数据失败:物料{request.MatBaseInfo.MatCode}已存在", + Data = null + }; + } + else + { + var newMatBaseInfo = new MatBaseInfo() + { + MatCode = request.MatBaseInfo.MatCode, + MatName = request.MatBaseInfo.MatName, + MatSpec = request.MatBaseInfo.MatSpec, + MatUnit = request.MatBaseInfo.MatUnit, + MatCustomer = request.MatBaseInfo.MatCustomer, + IsEnable = request.MatBaseInfo.IsEnable, + + ModifyTime = request.MatBaseInfo.ModifyTime, + ModifyUser = request.MatBaseInfo.ModifyUser, + }; + var rowNum = await DbHelp.db.Insertable(newMatBaseInfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加物料基础数据失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加物料基础数据成功!", + Data = null + }; + } + } + } + //else if (request.AddOrUpdate == AddOrUpdate.Delete) + //{ + // if (matBaseInfo == null) + // { + // return new ResponseCommon + // { + // Code = 201, + // Message = $"删除物料基础数据失败:物料{request.MatBaseInfo}不存在!", + // Data = null + // }; + // } + // else + // { + // var rowNum = await AuthDbHelp.db.Deleteable(matBaseInfo).ExecuteCommandAsync(); + // if (rowNum == 0) + // { + // return new ResponseCommon + // { + // Code = 201, + // Message = $"删除物料基础数据失败:请重试!", + // Data = null + // }; + // } + // else + // { + // return new ResponseCommon + // { + // Code = 200, + // Message = $"删除物料基础数据成功!", + // Data = null + // }; + // } + // } + //} + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + + public async Task> deleteMatBaseInfo(DeleteMatBaseInfosRequest request) + { + //先查询出具体的Id + var matBaseInfos = await DbHelp.db.Queryable() + .Where(t => request.MatBaseInfoIds.Contains(t.Id)) + .ToListAsync(); + //执行删除 + try + { + var deleteRows = await DbHelp.db.Deleteable(matBaseInfos).ExecuteCommandAsync(); + return new ResponseCommon + { + Code = 200, + Message = $"已删除{deleteRows}条数据!", + Data = null + }; + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + + public async Task>> getMatCodeList(GetMatCodeListRequest request) + { + try + { + + + List matCodeList = null; + if (request.IsFromBaseData) + { + matCodeList = await DbHelp.db.Queryable() + .Select(t => t.MatCode) + .Distinct() + .ToListAsync(); + } + else + { + matCodeList = await DbHelp.db.Queryable() + .Select(t => t.MatCode) + .Distinct() + .ToListAsync(); + } + return new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = matCodeList + }; + } + catch (Exception e) + { + return new ResponseCommon>() + { + Code = 201, + Message = $"获取失败:{e.Message}", + Data = null + }; + } + } + } +} diff --git a/WCS.BLL/Services/Service/MatInventoryDetailService.cs b/WCS.BLL/Services/Service/MatInventoryDetailService.cs new file mode 100644 index 0000000..2c1ca14 --- /dev/null +++ b/WCS.BLL/Services/Service/MatInventoryDetailService.cs @@ -0,0 +1,126 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.DAL.DbModels; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class MatInventoryDetailService : IMatInventoryDetailService + { + public async Task> getMatInventoryDetail(GetMatInventoryDetailRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .LeftJoin((id, si) => id.StoreId == si.Id) + .WhereIF(!string.IsNullOrEmpty(request.MatSN), (id, si) => id.MatSN.Contains(request.MatSN)) + .WhereIF(!string.IsNullOrEmpty(request.MatCode), (id, si) => id.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), (id, si) => id.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatBatch), (id, si) => id.MatBatch.Contains(request.MatBatch)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), (id, si) => id.MatSpec.Contains(request.MatSpec)) + .WhereIF(!string.IsNullOrEmpty(request.MatSupplier), (id, si) => id.MatSpec.Contains(request.MatSupplier)) + .WhereIF(!string.IsNullOrEmpty(request.MatCustomer), (id, si) => id.MatSpec.Contains(request.MatCustomer)) + + + .WhereIF(request.StoreId != 0, (id, si) => id.StoreId == request.StoreId) + .WhereIF(!string.IsNullOrEmpty(request.StoreCode), (id, si) => id.StoreCode.Contains(request.StoreCode)) + ; + + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .Select() + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> exportMatInventoryDetail(GetMatInventoryDetailRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .LeftJoin((id, si) => id.StoreId == si.Id) + .WhereIF(!string.IsNullOrEmpty(request.MatSN), (id, si) => id.MatSN.Contains(request.MatSN)) + .WhereIF(!string.IsNullOrEmpty(request.MatCode), (id, si) => id.MatCode.Contains(request.MatCode)) + .WhereIF(!string.IsNullOrEmpty(request.MatName), (id, si) => id.MatName.Contains(request.MatName)) + .WhereIF(!string.IsNullOrEmpty(request.MatBatch), (id, si) => id.MatBatch.Contains(request.MatBatch)) + .WhereIF(!string.IsNullOrEmpty(request.MatSpec), (id, si) => id.MatSpec.Contains(request.MatSpec)) + .WhereIF(!string.IsNullOrEmpty(request.MatSupplier), (id, si) => id.MatSpec.Contains(request.MatSupplier)) + .WhereIF(!string.IsNullOrEmpty(request.MatCustomer), (id, si) => id.MatSpec.Contains(request.MatCustomer)) + + + .WhereIF(request.StoreId != 0, (id, si) => id.StoreId == request.StoreId) + .WhereIF(!string.IsNullOrEmpty(request.StoreCode), (id, si) => id.StoreCode.Contains(request.StoreCode)) + ; + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .Select() + .ToListAsync(); + //生成序号 + var index = 1; + records.ForEach(r => + { + r.RowNumber = index++; + }); + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + Lists = records + } + }; + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + } +} diff --git a/WCS.BLL/Services/Service/OutstoreService.cs b/WCS.BLL/Services/Service/OutstoreService.cs new file mode 100644 index 0000000..6258029 --- /dev/null +++ b/WCS.BLL/Services/Service/OutstoreService.cs @@ -0,0 +1,328 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.DAL.Db; +using WCS.Model; + +namespace WCS.BLL.Services.Service +{ + public class OutstoreService : IOutstoreService + { + public OutstoreService() + { + + } + public async Task SysOutOrderByMatCode(SysOutOrderByMatCodeRequest request) + { + //参数合法性校验 + if (request.ItemList == null || request.ItemList.Count == 0) + { + return new ResponseBase() + { + Code = 201, + Message = "单据同步失败:缺少需要出库的物料类型!" + }; + } + //判断是否有单据号 没有单据号系统自动生成一个 + if (string.IsNullOrEmpty(request.OrderNumber)) + { + request.OrderNumber = GetOrderNumber(); + } + Console.WriteLine(DateTime.Now); + //保存数据 + await DbHelp.db.BeginTranAsync(); + try + { + var order = new OutOrder() + { + OrderNumber = request.OrderNumber, + OrderSource = request.OrderSource, + OrderType = request.OrderType, + CreateUser = request.UserName, + }; + order.Id = await DbHelp.db.Insertable(order).ExecuteReturnIdentityAsync(); + request.ItemList.ForEach(async item => + { + var orderDetail = new OutOrderDetail() + { + OrderId = order.Id, + OrderNumber = order.OrderNumber, + MatCode = item.MatCode, + MatBatch = item.MatBatch, + ReqQty = item.ReqQty, + CreateUser = request.UserName + }; + await DbHelp.db.Insertable(orderDetail).ExecuteCommandAsync(); + }); + await DbHelp.db.CommitTranAsync(); + return new ResponseCommon() + { + Code = 200, + Message = "单据同步成功!" + }; ; + } + catch (Exception ex) + { + await DbHelp.db.RollbackTranAsync(); + Console.WriteLine(ex.Message); + return new ResponseBase() + { + Code = 200, + Message = $"单据同步失败:{ex.Message}" + }; + } + } + + public async Task SysOutOrderByMatSn(SysOutOrderByMatSnRequest request) + { + + //参数合法性校验 + if (request.SnList == null || request.SnList.Count == 0) + { + return new ResponseBase() + { + Code = 201, + Message = "单据同步失败:缺少物料明细!" + }; + } + //库存有无校验 & 库存已锁校验 + try + { + await DbHelp.db.BeginTranAsync(); + var inventoryDetails = await DbHelp.db.Queryable() + .Where(t => request.SnList.Contains(t.MatSN)) + .TranLock(DbLockType.Wait) + .ToListAsync(); + if (inventoryDetails.Count < request.SnList.Count)//库存的物料少于需求的物料数量 + { + var existsSns = inventoryDetails.Select(t => t.MatSN).ToList(); + request.SnList.RemoveAll(t => existsSns.Contains(t)); + await DbHelp.db.RollbackTranAsync(); + //返回提示哪些物料库存不存在 + return new ResponseCommon() + { + Code = 201, + Message = "单据同步失败:存在物料不在库存中!", + Data = request.SnList + + }; + } + else if (inventoryDetails.Where(t => t.IsLocked).Any()) + { + await DbHelp.db.RollbackTranAsync(); + //返回提示哪些物料库存已被锁定 + return new ResponseCommon() + { + Code = 201, + Message = "单据同步失败:存在物料被锁定!", + Data = inventoryDetails.Where(t => t.IsLocked).Select(t => t.MatSN).ToList() + }; + } + + //判断是否有单据号 没有单据号系统自动生成一个 + if (string.IsNullOrEmpty(request.OrderNumber)) + { + request.OrderNumber = GetOrderNumber(); + } + + #region 保存数据 + + //锁库存 + inventoryDetails.ForEach(t => + { + t.IsLocked = false; + }); + var lockTask = DbHelp.db.Updateable(inventoryDetails).ExecuteCommandAsync(); + + //保存数据 + var order = new OutOrder() + { + OrderNumber = request.OrderNumber, + OrderSource = request.OrderSource, + OrderType = request.OrderType, + CreateUser = request.UserName, + }; + order.Id = await DbHelp.db.Insertable(order).ExecuteReturnIdentityAsync(); + + //通过库存数据保存出库物料明细表 + var matDetailTasks = inventoryDetails.Select(async t => + { + var orderMatDetail = new OutOrderMatDetail() + { + OrderId = order.Id, + OrderNumber = order.OrderNumber, + InventoryDetailId = t.Id, + StoreId = t.StoreId, + StoreCode = t.StoreCode, + MatSN = t.MatSN, + MatCode = t.MatCode, + MatName = t.MatName, + MatSpec = t.MatSpec, + MatBatch = t.MatBatch, + MatQty = t.MatQty, + MatSupplier = t.MatSupplier, + MatCustomer = t.MatCustomer, + CreateUser = request.UserName + }; + await DbHelp.db.Insertable(orderMatDetail).ExecuteCommandAsync(); + }).ToList(); + + await lockTask; + await Task.WhenAll(matDetailTasks); + + await DbHelp.db.CommitTranAsync(); + return new ResponseCommon() + { + Code = 200, + Message = $"单据同步成功!", + Data = order.Id + }; + #endregion + } + catch (Exception ex) + { + await DbHelp.db.RollbackTranAsync(); + return new ResponseBase() + { + Code = 201, + Message = $"单据同步失败:{ex.Message}" + }; + } + + } + + public async Task GetOutOrderList(GetOutOrderListRequest request) + { + //直接查询 + var outOrderList = await DbHelp.db.Queryable() + .WhereIF(!string.IsNullOrEmpty(request.OrderNumber), t => t.OrderNumber.Contains(request.OrderNumber)) + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + return new PageQueryResponse() + { + Code = 200, + Message = "success", + Data = new PageQueryResponseData() + { + Lists = outOrderList, + Count = outOrderList.Count + } + }; + } + + public async Task GetOutOrderDetail(GetOutOrderDetailRequest request) + { + OutOrder outOrder = null; + + #region 查询出库单 + if (request.OrderId != 0) + { + outOrder = await DbHelp.db.Queryable().Where(t => t.Id == request.OrderId).FirstAsync(); + if (outOrder == null) + { + return new ResponseCommon() + { + Code = 201, + Message = $"查询失败:不存在Id为{request.OrderId}的出库单!", + }; + } + } + else if (string.IsNullOrEmpty(request.OrderNumber)) + { + outOrder = await DbHelp.db.Queryable().Where(t => t.OrderNumber == request.OrderNumber) + .FirstAsync(); + if (outOrder == null) + { + return new ResponseCommon() + { + Code = 201, + Message = $"查询失败:不存在单据号为{request.OrderNumber}的出库单!", + }; + } + } + else + { + return new ResponseCommon() + { + Code = 201, + Message = $"查询失败:缺少必要参数!", + }; + } + #endregion + + #region 查询出库单明细 + var orderDetailTask = DbHelp.db.Queryable() + .Where(t => t.OrderId == outOrder.Id) + .ToListAsync(); + #endregion + + #region 出库物料明细 + var orderMatDetailTask = DbHelp.db.Queryable() + .Where(t => t.OrderId == outOrder.Id) + .ToListAsync(); + #endregion + var orderDetail = await orderDetailTask; + var orderMatDetail = await orderMatDetailTask; + return new ResponseCommon() + { + Code = 200, + Message = "Success", + Data = new + { + OrderDetailLists = orderDetail, + OrderMatDetailLists = orderMatDetail, + } + }; + } + + + + private string GetOrderNumber() + { + var orderNumber = "PD" + DateTime.Now.ToString("yyyyMMddHHmmss"); + return orderNumber; + } + + public async Task GoInOutstore(GetOutOrderDetailRequest request) + { + //先找到所有物料 + + //分组 按物料找到对应得货架编码 + + //对应的货架进入出库模式 亮灯 + + //返回 + return new ResponseCommon() + { + Code = 200, + Message = "Success", + Data = null + }; + } + + public async Task GoOutOutstore(GetOutOrderDetailRequest request) + { + //找到出库单号一致的货架列表 + var shelves = ShelfManager.Shelves.Where(t => t.OutOrderNumber == request.OrderNumber) + .ToList(); + //退出出库模式 + shelves.ForEach(t => + { + t.GoOutOutstore(); + }); + + return new ResponseCommon() + { + Code = 200, + Message = "Success", + Data = null + }; + } + } +} diff --git a/WCS.BLL/Services/Service/StoreInfoService.cs b/WCS.BLL/Services/Service/StoreInfoService.cs new file mode 100644 index 0000000..4b02af6 --- /dev/null +++ b/WCS.BLL/Services/Service/StoreInfoService.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.DbModels; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.DAL.Db; +using WCS.DAL.DbModels; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.StoreInfo; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class StoreInfoService : IStoreInfoService + { + public StoreInfoService() { } + + public async Task> GetShelves(GetShelvesRequest request) + { + try + { + var recordsQueryable = DbHelp.db.Queryable() + .WhereIF(request.ShelfTypeId != 0, t => t.ShelfTypeId == request.ShelfTypeId) + .WhereIF(!string.IsNullOrEmpty(request.ShelfCode), t => t.ShelfCode.Contains(request.ShelfCode)); + + var totalCount = await recordsQueryable.CountAsync(); + var records = await recordsQueryable + .Skip((request.PageNumber - 1) * request.PageSize).Take(request.PageSize) + .ToListAsync(); + //生成序号 + for (int i = 0; i < records.Count; i++) + { + records[i].RowNumber = (request.PageNumber - 1) * 10 + i + 1; + } + return new PageQueryResponse() + { + Code = 200, + Message = $"success", + Data = new PageQueryResponseData() + { + TotalCount = totalCount, + MaxPage = request.PageSize == 0 ? 0 : (int)Math.Ceiling((decimal)totalCount / request.PageSize), + Count = records.Count, + Lists = records.ToList() + } + }; + + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"操作失败:{ex.Message}", + }; + } + } + + public async Task> addOrUpdateShelfInfo(AddShelfInfoRequest request) + { + try + { + var shelfnfo = await DbHelp.db.Queryable() + .Where(t => t.ShelfCode == request.ShelfInfo.ShelfCode) + .FirstAsync(); + //修改货架信息 + if (request.AddOrUpdate == AddOrUpdate.Update) + { + var existId = shelfnfo == null ? 0 : shelfnfo.Id; + + shelfnfo = await DbHelp.db.Queryable() + .Where(t => t.Id == request.ShelfInfo.Id) + .FirstAsync(); + if (shelfnfo == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新货架信息失败:货架{request.ShelfInfo.ShelfCode}不存在!", + Data = null + }; + } + else if (existId != shelfnfo.Id) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新货架信息失败:已存在货架编码{request.ShelfInfo.ShelfCode}!", + Data = null + }; + } + else + { + shelfnfo.ShelfCode = request.ShelfInfo.ShelfCode; + shelfnfo.ShelfTypeId = request.ShelfInfo.ShelfTypeId; + shelfnfo.ShelfTypeName = request.ShelfInfo.ShelfTypeName; + shelfnfo.Rowcounts = request.ShelfInfo.Rowcounts; + shelfnfo.Columncounts = request.ShelfInfo.Columncounts; + shelfnfo.LightId = request.ShelfInfo.LightId; + shelfnfo.ClientIp = request.ShelfInfo.ClientIp; + shelfnfo.GroupName = request.ShelfInfo.GroupName; + shelfnfo.IsBind = request.ShelfInfo.IsBind; + shelfnfo.BindShelfCode = request.ShelfInfo.BindShelfCode; + + var rowNum = await DbHelp.db.Updateable(shelfnfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新货架信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新货架信息成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (shelfnfo != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"货架信息失败:货架{request.ShelfInfo.ShelfCode}已存在!", + Data = null + }; + } + else + { + var newShelfInfo = new ShelfInfo() + { + ShelfCode = request.ShelfInfo.ShelfCode, + ShelfTypeId = request.ShelfInfo.ShelfTypeId, + ShelfTypeName = request.ShelfInfo.ShelfTypeName, + Rowcounts = request.ShelfInfo.Rowcounts, + Columncounts = request.ShelfInfo.Columncounts, + LightId = request.ShelfInfo.LightId, + ClientIp = request.ShelfInfo.ClientIp, + GroupName = request.ShelfInfo.GroupName, + IsBind = request.ShelfInfo.IsBind, + BindShelfCode = request.ShelfInfo.BindShelfCode, + }; + var rowNum = await DbHelp.db.Insertable(newShelfInfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加货架信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加货架信息成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Delete) + { + shelfnfo = await DbHelp.db.Queryable() + .Where(t => t.Id == request.ShelfInfo.Id) + .FirstAsync(); + if (shelfnfo == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除货架信息失败:货架{request.ShelfInfo}不存在!", + Data = null + }; + } + else + { + var rowNum = await DbHelp.db.Deleteable(shelfnfo).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除货架信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"删除货架信息成功!", + Data = null + }; + } + } + } + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + } +} diff --git a/WCS.BLL/Services/Service/UserService.cs b/WCS.BLL/Services/Service/UserService.cs new file mode 100644 index 0000000..66a4ae0 --- /dev/null +++ b/WCS.BLL/Services/Service/UserService.cs @@ -0,0 +1,464 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TouchSocket.Core; +using WCS.BLL.Services.IService; +using WCS.DAL; +using WCS.DAL.AuthDbModel; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.BLL.Services.Service +{ + public class UserService : IUserService + { + public UserService() { } + + public async Task>> GetUsers(GetUsersRequest request) + { + try + { + var users = await AuthDbHelp.db.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(request.Info), o => o.LoginName.Contains(request.Info.Trim())) + .OrderBy(o => o.Id) + .ToListAsync(); + //返回内容密码处理 + if (users != null && users.Count > 0) + { + users.ForEach(t => + { + t.Password = "******"; + }); + } + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = users + }; + return response; + } + catch (Exception ex) + { + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = null + }; + return response; + } + } + + public async Task> AddUser(AddUserRequest request) + { + try + { + var user = await AuthDbHelp.db.Queryable() + .Where(t => t.LoginName == request.User.LoginName) + .FirstAsync(); + if (request.AddOrUpdate == AddOrUpdate.Update) + { + if (user == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新用户信息失败:用户{user.LoginName}不存在!", + Data = null + }; + } + else + { + user.Password = request.User.Password; + user.LoginName = request.User.LoginName; + user.RoleIds = request.User.RoleIds; + var rowNum = await AuthDbHelp.db.Updateable(user).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新用户信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新用户信息成功!", + Data = null + }; + } + } + } + + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (user != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加用户失败:用户{request.User.LoginName}已存在", + Data = null + }; + } + else + { + var newUser = new UserBase() + { + LoginName = request.User.LoginName, + Password = request.User.Password, + RoleIds = request.User.RoleIds, + IsAdmin = request.User.IsAdmin, + Time = request.User.Time + }; + var rowNum = await AuthDbHelp.db.Insertable(newUser).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加用户失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加用户成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Delete) + { + if (user == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除用户失败:用户{request.User.LoginName}不存在", + Data = null + }; + } + else + { + var rowNum = await AuthDbHelp.db.Deleteable(user).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除用户失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"删除用户成功!", + Data = null + }; + } + } + } + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + public async Task>> GetRoles(GetUsersRequest request) + { + try + { + var users = await AuthDbHelp.db.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(request.Info), o => o.Name.Contains(request.Info.Trim())) + .OrderBy(o => o.Id) + .ToListAsync(); + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = users + }; + return response; + } + catch (Exception ex) + { + var response = new ResponseCommon>() + { + Code = 200, + Message = "success", + Data = null + }; + return response; + } + } + + public async Task> AddRole(AddRoleRequest request) + { + try + { + var Role = await AuthDbHelp.db.Queryable() + .Where(t => t.Name == request.Role.Name) + .FirstAsync(); + if (request.AddOrUpdate == AddOrUpdate.Update) + { + if (Role == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新角色信息失败:角色{Role.Name}不存在!", + Data = null + }; + } + else + { + Role.IsAdmin = request.Role.IsAdmin; + Role.Name = request.Role.Name; + Role.Auths = request.Role.Auths; + Role.Time = request.Role.Time; + var rowNum = await AuthDbHelp.db.Updateable(Role).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"更新角色信息失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"更新角色信息成功!", + Data = null + }; + } + } + } + + else if (request.AddOrUpdate == AddOrUpdate.Add) + { + if (Role != null) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加角色失败:角色{request.Role.Name}已存在", + Data = null + }; + } + else + { + var newRole = new RoleBase() + { + Name = request.Role.Name, + Auths = request.Role.Auths, + IsAdmin = request.Role.IsAdmin, + Time = request.Role.Time + }; + var rowNum = await AuthDbHelp.db.Insertable(newRole).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"添加角色失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"添加角色成功!", + Data = null + }; + } + } + } + else if (request.AddOrUpdate == AddOrUpdate.Delete) + { + if (Role == null) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除角色失败:角色{request.Role.Name}不存在", + Data = null + }; + } + else + { + var isContains = AuthDbHelp.db.Queryable().Select(o => o.RoleIds).ToList().SelectMany(o => o).Contains(Role.Id); + if (isContains) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除角色失败:角色{request.Role.Name}已被用户使用!", + Data = null + }; + } + var rowNum = await AuthDbHelp.db.Deleteable(Role).ExecuteCommandAsync(); + if (rowNum == 0) + { + return new ResponseCommon + { + Code = 201, + Message = $"删除角色失败:请重试!", + Data = null + }; + } + else + { + return new ResponseCommon + { + Code = 200, + Message = $"删除角色成功!", + Data = null + }; + } + } + } + else + { + var response = new ResponseCommon + { + Code = 300, + Message = "不支持的操作!", + Data = null + }; + return response; + } + } + catch (Exception ex) + { + var response = new ResponseCommon + { + Code = 300, + Message = $"操作失败:{ex.Message}", + Data = null + }; + return response; + } + } + + public async Task> UserLogin(UserLoginRequest request) + { + try + { + UserBase user = null; + + if (request.IsNoLogin)//不登录模式 不校验密码 + { + user = await AuthDbHelp.db.Queryable() + .Where(t => t.LoginName == "admin") + .FirstAsync(); + } + else//登录模式需要校验密码 + { + user = await AuthDbHelp.db.Queryable() + .Where(t => t.LoginName == request.UserName) + .FirstAsync(); + if (user == null) + { + return new ResponseCommon() + { + Code = 201, + Message = $"登录失败:用户名[{request.UserName}]不存在!", + Data = null + }; + } + else if (user.Password != request.PassWord) + { + return new ResponseCommon() + { + Code = 201, + Message = $"登录失败:密码错误!", + Data = null + }; + } + } + + //加载用户的权限 + if (user != null) + { + if (user.IsAdmin) + { + user.GetRoles = await AuthDbHelp.db.Queryable() + .OrderBy(o => o.Id) + .ToListAsync(); + } + else if (user.RoleIds == null || !user.RoleIds.Any()) + { + user.GetRoles = new List(); + } + else + { + user.GetRoles = await AuthDbHelp.db.Queryable() + .Where(t => user.RoleIds.Contains(t.Id)) + .OrderBy(o => o.Id) + .ToListAsync(); + } + } + + //返回字串不返回密码 + user.Password = "***"; + + var response = new ResponseCommon() + { + Code = 200, + Message = "success", + Data = user + }; + return response; + } + catch (Exception ex) + { + var response = new ResponseCommon() + { + Code = 300, + Message = $"登录失败:{ex.Message}", + Data = null + }; + return response; + } + } + } +} diff --git a/WCS.BLL/Tool/Api/ApiHelp.cs b/WCS.BLL/Tool/Api/ApiHelp.cs new file mode 100644 index 0000000..c8dfa92 --- /dev/null +++ b/WCS.BLL/Tool/Api/ApiHelp.cs @@ -0,0 +1,182 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; +using WCS.BLL.Tool.Api.Models; + +namespace WCS.BLL.Tool.Api +{ + public static class ApiHelp + { + public static HttpClient httpClient; + static ApiHelp() + { + httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromSeconds(5); + httpClient.DefaultRequestHeaders.Add("User-Agent", "Chrome/95.0.4638.69 Safari/537.36"); + //ServicePointManager.Expect100Continue = false; + } + + public static ApiResult Get(string uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Get(IEnumerable uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Get(string uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Get(IEnumerable uri, object? query = null, object? body = null) + { + return Send(HttpMethod.Get, uri, query, body); + } + + public static ApiResult Post(string uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Post(IEnumerable uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Post(string uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Post(IEnumerable uri, object? body = null, object? query = null) + { + return Send(HttpMethod.Post, uri, query, body); + } + + public static ApiResult Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return Send(method, new string[] { uri }, query, body); + } + + public static ApiResult Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query)); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = httpClient.SendAsync(httpRequestMessage).Result; + if (!re.IsSuccessStatusCode) + return new ApiResult() { Code = ((int)re.StatusCode).ToString() }; + + var con = re.Content.ReadAsStringAsync().Result; + return JsonConvert.DeserializeObject(con) ?? new ApiResult(); + } + + public static ApiResult Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return Send(method, new string[] { uri }, query, body); + } + + public static ApiResult Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query)); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = httpClient.SendAsync(httpRequestMessage).Result; + if (!re.IsSuccessStatusCode) + return new ApiResult() { Code = ((int)re.StatusCode).ToString() }; + + var con = re.Content.ReadAsStringAsync().Result; + return JsonConvert.DeserializeObject>(con) ?? new ApiResult(); + } + + /// + /// 追加路径片段(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com + /// 路径片段 + /// 地址 + public static string AppendPathSegments(this string url, IEnumerable segments) + { + string urlStr = url; + foreach (var segment in segments) + { + var val = segment?.ToString(); + if (string.IsNullOrWhiteSpace(val)) + continue; + + if (urlStr.EndsWith("/")) + urlStr = urlStr.Substring(0, urlStr.Length - 1); + + urlStr += val!.StartsWith("/") ? val : $"/{val}"; + } + return urlStr; + } + + /// + /// 设置Query参数(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com/s + /// 参数,支持字典和对象 + /// 地址 + public static string SetQueryParams(this string url, object? values) + { + string urlStr = url; + if (values == null) + return urlStr; + + List kv = new List(); + if (values is IEnumerable jh) + { + if (jh is IDictionary dict) + { + foreach (DictionaryEntry item in dict) + kv.Add($"{item.Key?.ToString()}={item.Value?.ToString()}"); + } + } + else + { + foreach (var item in values.GetType().GetProperties()) + { + if (item.CanRead) + kv.Add($"{item.Name}={item.GetValue(values)?.ToString()}"); + } + } + + if (kv.Any()) + { + if (!urlStr.Contains("?")) + urlStr += "?"; + else + { + if (!urlStr.EndsWith("&")) + urlStr += "&"; + } + + urlStr += string.Join("&", kv); + } + + return urlStr; + } + } +} diff --git a/WCS.BLL/Tool/Api/Models/ApiResult.cs b/WCS.BLL/Tool/Api/Models/ApiResult.cs new file mode 100644 index 0000000..4d2bf95 --- /dev/null +++ b/WCS.BLL/Tool/Api/Models/ApiResult.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.BLL.Tool.Api.Models +{ + public class ApiResult + { + public string Code { get; set; } + public string Message { get; set; } + } + + public class ApiResult : ApiResult + { + public T Data { get; set; } + } +} diff --git a/WCS.BLL/Tool/Logs.cs b/WCS.BLL/Tool/Logs.cs new file mode 100644 index 0000000..ce9b424 --- /dev/null +++ b/WCS.BLL/Tool/Logs.cs @@ -0,0 +1,161 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using WCS.BLL.Config; +using WCS.DAL; +using WCS.Model; + +namespace WCS.BLL +{ + /// + /// 日志类型 + /// + public enum LogsType + { + /// + /// 信息 + /// + Info, + /// + /// 警告 + /// + Warning, + /// + /// 错误 + /// + Err, + /// + /// 数据库错误 + /// + DbErr, + } + + /// + /// 日志 + /// + public static class Logs + { + static object obj = new object(); + const string logExtension = ".log"; + /// + /// 写入日志失败 + /// + public static Action, DateTime, LogsType, Exception> WriteErr = null; + + /// + /// 写入日志 + /// + /// 内容 + /// 类型 + /// 是否写入成功 + public static void Write(IEnumerable content, LogsType type = LogsType.Info) + { + if (content == null || !content.Any()) + return; + + var dt = DateTime.Now; + string hms = dt.ToString("HH:mm:ss.fff"); + List lines = new List(content.Count()); + + try + { + string path = Path.Combine(Config.LocalFile.LogDir, type.ToString(), $"{(dt.ToString("yyyyMMdd"))}{logExtension}"); + foreach (var item in content) + lines.AddRange($"[{hms}]{item}".Split(new string[] { Environment.NewLine }, StringSplitOptions.None)); + + lock (obj) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.AppendAllLines(path, lines, Encoding.UTF8); + } + } + catch (Exception ex) + { + WriteErr?.Invoke(content, dt, type, ex); + } + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(string content, LogsType type = LogsType.Info) + { + Write(new string[] { content }, type); + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(object content, LogsType type = LogsType.Info) + { + Write(JsonConvert.SerializeObject(content), type); + } + + /// + /// 写入日志 + /// + /// 内容 + /// 内容标题 + /// 类型 + /// 是否写入成功 + public static void Write(object content, string contentTitle, LogsType type = LogsType.Info) + { + Write($"{contentTitle} {JsonConvert.SerializeObject(content)}", type); + } + + /// + /// 写入日志 + /// + /// 错误 + /// 是否写入成功 + public static void Write(Exception ex, LogsType type = LogsType.Err) + { + Write(ex.ToString(), type); + } + + /// + /// 清除日志 + /// + /// 保留时间 + /// 清理的大小(字节) + public static long Clear(TimeSpan time) + { + long size = 0; + var rs = EnumHelps.GetEnumList(typeof(LogsType)); + foreach (var item in rs) + { + try + { + var path = Path.Combine(Config.LocalFile.LogDir, item); + DirectoryInfo directoryInfo = new DirectoryInfo(path); + if (!directoryInfo.Exists) + continue; + + var files = directoryInfo.GetFiles($"**{logExtension}", SearchOption.TopDirectoryOnly); + var fileDel = files.Where(o => o.CreationTime < (DateTime.Now - time)); + foreach (var item2 in fileDel) + { + size += item2.Length; + item2.Delete(); + } + } + catch (Exception) + { + + } + } + return size; + } + } +} \ No newline at end of file diff --git a/WCS.BLL/Tool/TCPClient.cs b/WCS.BLL/Tool/TCPClient.cs new file mode 100644 index 0000000..a83354c --- /dev/null +++ b/WCS.BLL/Tool/TCPClient.cs @@ -0,0 +1,223 @@ +using System.Collections.Concurrent; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + + +namespace WCS.BLL +{ + /// + /// 对TouchSocket的封装 主要完成TCP的连接 状态更新 发送接收通信 + /// + public class TCPClient + { + public string RemoteIPHost { get; set; } = "127.0.0.1:20002"; + + public string BindIPHost { get; set; } = "127.0.0.1:20003"; + + public bool IsOnline { get; set; } = false; + + //can模块协议前缀 + public readonly byte[] Prefix = new byte[] { 0x08, 0x00, 0x00 }; + //can模块协议前缀长度 + public readonly int PreFixLength = 3; + //协议数据部分长度 + public readonly int DataLength = 10; + + public ConcurrentDictionary MessageList { get; set; } = new ConcurrentDictionary(); + + public TcpClient tcpClient { get; set; } + + public object receivdLockObject = new object(); + public object sendLockObject = new object(); + + public bool Connect() + { + try + { + tcpClient.Connect();//调用连接,当连接不成功时,会抛出异常。 + return true; + } + catch (Exception e) + { + //连接失败 + return false; + } + } + + /// + /// 初始化配置连接 + /// + /// + public TCPClient(string remoteIPHost, string bindIPHost) + { + try + { + RemoteIPHost = remoteIPHost; + BindIPHost = bindIPHost; + + tcpClient = new TcpClient(); + //载入配置 + tcpClient.Setup(new TouchSocketConfig() + .SetRemoteIPHost(RemoteIPHost) + .SetBindIPHost(BindIPHost) + .ConfigurePlugins(a => + { + //配置断线重连 + a.UseReconnection(-1, true, 1000); + }) + .ConfigureContainer(a => + { + //添加控制台日志注入 + a.AddConsoleLogger(); + })); + + //添加接收事件 匹配已发送的指令 + tcpClient.Received += (client, e) => + { + var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); + e.ByteBlock.Clear(); + var len = data.Length; + for (int index = 0; index < data.Length - PreFixLength; index++) + { + //协议拆包 通过前缀校验是否为完整数据包 + var prefixInData = data.Skip(index).Take(PreFixLength); + var isEqual = prefixInData.SequenceEqual(Prefix); + if (isEqual) + { + var dataTemp = data.Skip(index).Take(PreFixLength + DataLength).ToArray(); + if (dataTemp.Length < PreFixLength + DataLength)//拆包后不满足一条指令的长度 + { + continue; + } + //获取返回指令的板子ID + var boardId = (data[PreFixLength + 0] << 8) + data[PreFixLength + 1]; + //查询当前板子是否有待验证的指令 + var message = new MessageDto(); + MessageList.TryGetValue(boardId, out message); + //功能位校验 功能位相同视为已响应指令 删除对应的指令 + if (message?.Message[PreFixLength + 2] == dataTemp[PreFixLength + 2]) + { + MessageList.TryRemove(boardId, out message); + } + index += (PreFixLength + DataLength - 1);//每次循环index会+1 所以这里-1 + } + } + return null; + }; + + tcpClient.Connected += (client, e) => + { + this.IsOnline = true; + return EasyTask.CompletedTask; + }; + + tcpClient.Disconnected += (client, e) => + { + this.IsOnline = false; + return EasyTask.CompletedTask; + }; + + //配置数据重发机制 + Task.Run(async () => + { + while (true) + { + try + { + //TO DO如果指令未回应n次 则取消重发 + Console.WriteLine(Thread.CurrentThread.ManagedThreadId); + await Task.Delay(3000); + if (MessageList.Count > 0) + { + Console.WriteLine(Thread.CurrentThread.ManagedThreadId); + foreach (var item in MessageList) + { + if (item.Value.LastSendTime < DateTime.Now.AddSeconds(3)) + { + tcpClient.Send(item.Value.Message); + item.Value.SendTimes++; + item.Value.LastSendTime = DateTime.Now; + await Task.Delay(10); + } + } + } + } + catch + { + + } + } + + }); + } + catch (Exception ex) + { + } + } + + public void Send(byte[] message) + { + var boardId = (message[3] << 8) + message[4]; + //记录发送指令 用于通信校验 同Id只校验最后一个指令 + ////MessageList.AddOrUpdate(boardId, new MessageDto() + ////{ + //// ID = boardId, + //// Message = message, + ////}, (key, oldValue) => oldValue = new MessageDto() + ////{ + //// ID = boardId, + //// Message = message, + ////}); + lock (sendLockObject) + { + tcpClient.Send(message); + //发送自带10ms间隔 + Thread.Sleep(10); + } + } + + //生成协议明细 + public byte[] GenerateMessage(int boardId, byte[] data) + { + var message = new byte[Prefix.Length + 2 + data.Length]; + var boardIdData = BitConverter.GetBytes(unchecked((short)boardId)); + // 检查是否需要交换字节 + if (BitConverter.IsLittleEndian) + { + // 如果是小端序系统,则交换字节 + byte temp = boardIdData[0]; + boardIdData[0] = boardIdData[1]; + boardIdData[1] = temp; + } + + Buffer.BlockCopy(Prefix, 0, message, 0, Prefix.Length); + Buffer.BlockCopy(boardIdData, 0, message, Prefix.Length, boardIdData.Length); + Buffer.BlockCopy(data, 0, message, Prefix.Length + boardIdData.Length, data.Length); + return message; + } + + } + + //发送指令的记录 + public class MessageDto + { + public int ID { get; set; } + + /// + /// 最后一次发送时间 + /// + public DateTime LastSendTime { get; set; } = DateTime.Now; + + /// + /// 发送内容 + /// + public byte[] Message { get; set; } + + /// + /// 发送次数 + /// + public int SendTimes { get; set; } = 0;//第几次发送 + } + +} diff --git a/WCS.BLL/WCS.BLL.csproj b/WCS.BLL/WCS.BLL.csproj new file mode 100644 index 0000000..6c0a955 --- /dev/null +++ b/WCS.BLL/WCS.BLL.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/WCS.DAL/AuthDbModel/AuthModels.cs b/WCS.DAL/AuthDbModel/AuthModels.cs new file mode 100644 index 0000000..6bab81f --- /dev/null +++ b/WCS.DAL/AuthDbModel/AuthModels.cs @@ -0,0 +1,83 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; +using WCS.DAL.Db; +using WCS.Model; + +namespace WCS.DAL.AuthDbModel +{ + /// + /// 用户 + /// + [SugarTable("User")] + public class UserBase + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + /// + /// 登录名 + /// + public string LoginName { get; set; } + /// + /// 密码 + /// + public string Password { get; set; } + /// + /// 角色id(json) + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsJson = true)] + public List RoleIds { get; set; } = new List(); + /// + /// 角色名称 + /// + [SugarColumn(IsIgnore = true)] + public List RoleNames { get => (RoleIds == null || !RoleIds.Any()) ? new List() : AuthDbHelp.db.Queryable().Where(o => RoleIds.Contains(o.Id)).Select(o => o.Name).ToList(); } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + + /// + /// 用户所属角色 + /// + [SugarColumn(IsIgnore = true)] + public List GetRoles { get; set; } + } + + /// + /// 角色 + /// + [SugarTable("Role")] + public class RoleBase + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + /// + /// 角色名 + /// + public string Name { get; set; } + /// + /// 认证模块(json) + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsJson = true)] + public List Auths { get; set; } = new List(); + /// + /// 认证模块名称 + /// + [SugarColumn(IsIgnore = true)] + public List AuthNames { get => (Auths == null || !Auths.Any()) ? new List() : EnumHelps.GetEnumDescriptionList(typeof(AuthEnum), true).Where(o => Auths.Contains(o.Item1)).Select(o => o.Item3).ToList(); } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + } +} diff --git a/WCS.DAL/Db/AuthEnum/AuthDbHelp.cs b/WCS.DAL/Db/AuthEnum/AuthDbHelp.cs new file mode 100644 index 0000000..1c3ed7c --- /dev/null +++ b/WCS.DAL/Db/AuthEnum/AuthDbHelp.cs @@ -0,0 +1,91 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.DAL.AuthDbModel; + +namespace WCS.DAL +{ + /// + /// 权限数据库 + /// + public static class AuthDbHelp + { + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={LocalFile.AuthDbPath};", + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite.Core]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + //Logs.Write($@"{nameof(AuthDbHelp)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + + /// + /// 初始化数据 + /// + public static void InitDb() + { + //不存在创建数据库,存在不会创建 + db.DbMaintenance.CreateDatabase(); + //创建表根据实体类 + db.CodeFirst.InitTables(typeof(UserBase), typeof(RoleBase)); + //初始化数据 + if (!db.Queryable().Any()) + { + var dt = db.GetDate(); + var userBases = new List() + { + new UserBase () + { + Id = 1, + LoginName = "admin", + Password = "", + RoleIds = new List () { 1 }, + IsAdmin = true, + Time = dt, + }, + new UserBase () + { + Id = 2, + LoginName = "czy", + Password = "", + RoleIds = new List () { 2 }, + IsAdmin = false, + Time = dt, + }, + }; + var roleBases = new List() + { + new RoleBase () + { + Id = 1, + Name = "管理员", + Auths = new List () { }, + IsAdmin = true, + Time = dt, + }, + new RoleBase () + { + Id = 2, + Name = "操作员", + Auths = new List () { }, + IsAdmin = false, + Time = dt, + }, + }; + + db.Insertable(userBases).ExecuteCommand(); + db.Insertable(roleBases).ExecuteCommand(); + } + } + + } +} diff --git a/WCS.DAL/Db/AuthEnum/AuthEnum.cs b/WCS.DAL/Db/AuthEnum/AuthEnum.cs new file mode 100644 index 0000000..504d2f4 --- /dev/null +++ b/WCS.DAL/Db/AuthEnum/AuthEnum.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL +{ + /// + /// 认证项 + /// + public enum AuthEnum + { + /* 注意:枚举的值必须大于0 */ + 查询 = 1000, + 权限 = 2000, + //[Description("用户")] + //[EnumTree(权限, new[] { 用户新增, 用户删除, 用户修改 })] + //用户管理 = 3100, 用户新增 = 3110, 用户删除, 用户修改, + //[Description("角色")] + //[EnumTree(权限, new[] { 角色新增, 角色删除, 角色修改 })] + //角色管理 = 3200, 角色新增 = 3210, 角色删除, 角色修改, + 设置 = 3000, + 调试 = 4000, + } + + public class EnumTreeAttribute : Attribute + { + public EnumTreeAttribute() { } + + public EnumTreeAttribute(AuthEnum parent) + { + Parent = parent; + } + + public EnumTreeAttribute(AuthEnum[] childs) + { + Childs = childs; + } + + public EnumTreeAttribute(AuthEnum parent, AuthEnum[] childs) + { + Parent = parent; + Childs = childs; + } + + /// + /// 父级 + /// + public AuthEnum? Parent { get; set; } = null; + /// + /// 子级 + /// + public AuthEnum[]? Childs { get; set; } = null; + } +} diff --git a/WCS.DAL/Db/AuthEnum/EnumHelps.cs b/WCS.DAL/Db/AuthEnum/EnumHelps.cs new file mode 100644 index 0000000..6944374 --- /dev/null +++ b/WCS.DAL/Db/AuthEnum/EnumHelps.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Text; + +namespace WCS.DAL +{ + public static class EnumHelps + { + public static List GetEnumList(Type type) + { + List strings = new List(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public) ?? new FieldInfo[] { }; + foreach (var field in fields) + { + strings.Add(field.Name); + } + } + else + { + + } + + return strings; + } + + /// + /// 得到枚举详情 + /// + /// 枚举 + /// 描述为空时,是否采用名称值 + /// 枚举值,名称,描述 + public static List> GetEnumDescriptionList(Type type, bool isDescriptionNullInName = false) + { + var strings = new List>(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); + if (fields == null) + return strings; + + foreach (var field in fields) + { + int enumValue = Convert.ToInt32(field.GetRawConstantValue()); + string enumName = field.Name; + string description = string.Empty; + + var descriptionAttribute = field.GetCustomAttribute(false); + if (descriptionAttribute != null) + description = descriptionAttribute.Description; + else if (isDescriptionNullInName) + description = enumName; + + strings.Add(new Tuple(enumValue, enumName, description)); + } + } + else + { + + } + + return strings; + } + } +} diff --git a/WCS.DAL/Db/DbHelp.cs b/WCS.DAL/Db/DbHelp.cs new file mode 100644 index 0000000..d47ba96 --- /dev/null +++ b/WCS.DAL/Db/DbHelp.cs @@ -0,0 +1,60 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL.Db +{ + public static class DbHelp + { + /// + /// 业务数据库 + /// + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={LocalFile.DataDbPath};", + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + //TO DO LOG + //Logs.Write($@"{nameof(db)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + /// + /// 日志数据库 + /// + public static SqlSugarScope dbLog = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={LocalFile.LogDbPath};", + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + //TO DO LOG + //Logs.Write($@"{nameof(dbAuth)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + public static void InitDb() + { + //#region 初始化业务数据库 + ////不存在创建数据库,存在不会创建 + //db.DbMaintenance.CreateDatabase(); + ////创建表根据实体类 + //db.CodeFirst.InitTables(typeof(ModuleInfo), typeof(ShelfInfo), typeof(StoreInfo)); + //#endregion + + //#region 初始化日志数据库 + //dbLog.DbMaintenance.CreateDatabase(); + //#endregion + } + } +} diff --git a/WCS.DAL/LocalFile.cs b/WCS.DAL/LocalFile.cs new file mode 100644 index 0000000..448c96d --- /dev/null +++ b/WCS.DAL/LocalFile.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.DAL +{ + public static class LocalFile + { + public static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory; + + public static readonly string LogDbPath = Path.Combine(AppDir, "data\\log.db3"); + + public static readonly string DataDbPath = Path.Combine(AppDir, "data\\data.db3"); + + public static readonly string AuthDbPath = Path.Combine(AppDir, "data\\auth.db3"); + } +} diff --git a/WCS.DAL/WCS.DAL.csproj b/WCS.DAL/WCS.DAL.csproj new file mode 100644 index 0000000..9e503a6 --- /dev/null +++ b/WCS.DAL/WCS.DAL.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs b/WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs new file mode 100644 index 0000000..6203bf4 --- /dev/null +++ b/WCS.Model/ApiModel/Home/GetShelfStatusRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetShelfStatusRequest : RequestBase + { + public int ShelfTypeId { get; set; } + public string? ShelfTypeName { get; set; } = string.Empty; + public List GroupNames { get; set; } + } +} diff --git a/WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs b/WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs new file mode 100644 index 0000000..afb0fd9 --- /dev/null +++ b/WCS.Model/ApiModel/Home/GetShelfStatusResponse.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetShelfStatusResponse : ResponseBase + { + public List Data { get; set; } + } + + public class Shelf + { + public int ShelfId { get; set; } + + /// + /// 货架编码 + /// + public string ShelfCode { get; set; } + + + /// + /// 货架当前模式 + /// + public int CurentMode { get; set; } + + + public string ModulesStr { get; set; } + + /// + /// 货架组别 + /// + public string GroupName { get; set; } + } +} diff --git a/WCS.Model/ApiModel/Home/ShelfTypeModel.cs b/WCS.Model/ApiModel/Home/ShelfTypeModel.cs new file mode 100644 index 0000000..ff453fa --- /dev/null +++ b/WCS.Model/ApiModel/Home/ShelfTypeModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.Home +{ + public class ShelfTypeModel() + { + public int Id { get; set; } + public string ShelfTypeName { get; set; } + + } +} diff --git a/WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs b/WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs new file mode 100644 index 0000000..4331687 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/QueryByMatSnRequest.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class QueryByMatSnRequest : RequestBase + { + public string MatSn { get; set; } = string.Empty; + public string ShelfCode { get; set; } = string.Empty; + + public string IpAddress { get; set; } = string.Empty; + } +} diff --git a/WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs b/WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs new file mode 100644 index 0000000..8f32c3f --- /dev/null +++ b/WCS.Model/ApiModel/InStore/QueryByMatSnResponse.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class QueryByMatSnResponse : ResponseBase + { + public MatInfoModel Data { get; set; } + } + + public class MatInfoModel + { + public string materialBar { get; set; } + + public string materialCode { get; set; } + + public string materialName { get; set; } + + public string materialSpec { get; set; } + + public double materialQty { get; set; } + + public string batchNo { get; set; } + + public string supplier { get; set; } + + public string customer { get; set; } + } +} diff --git a/WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs new file mode 100644 index 0000000..753d751 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreRequest.cs @@ -0,0 +1,9 @@ +namespace WCS.Model +{ + public class ShelfGoInInstoreRequest : RequestBase + { + public string ModuleCode { get; set; } + + public string? IpAdress { get; set; }//调用设备的Ip地址 + } +} diff --git a/WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs new file mode 100644 index 0000000..7bc55f8 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/ShelfGoInInstoreResponse.cs @@ -0,0 +1,13 @@ +namespace WCS.Model +{ + public class ShelfGoInInstoreResponse : ResponseBase + { + public ShelfGoInInstoreDto? Data { get; set; } + } + public class ShelfGoInInstoreDto + { + public string ShelfCode { get; set; } = string.Empty; + + public string ModulesStr { get; set;} = string.Empty; + } +} diff --git a/WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs b/WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs new file mode 100644 index 0000000..90b9c23 --- /dev/null +++ b/WCS.Model/ApiModel/InStore/ShelfGoOutInStoreRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class ShelfGoOutInStoreRequest : RequestBase + { + public string ShelfCode { get; set; } = string.Empty; + + public string IPAdress { get; set; } = string.Empty; + } +} diff --git a/WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs b/WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs new file mode 100644 index 0000000..d046a15 --- /dev/null +++ b/WCS.Model/ApiModel/InterfaceRecord/GetInterfaceRecordsRequest.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel +{ + public class GetInterfaceRecordsRequest : PageQueryRequestBase + { + public string RequestType { get; set; } + + public string RequestUrl { get; set; } + + public string RequestBody { get; set; } + + public TimeType TimeType { get; set; } + + public DateTime? StartTime { get; set; } + + public DateTime? EndTime { get; set; } + } + + public enum TimeType + { + 请求时间 = 0, + 响应时间 = 1 + } +} diff --git a/WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs b/WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs new file mode 100644 index 0000000..3bf55d0 --- /dev/null +++ b/WCS.Model/ApiModel/InterfaceRecord/SystemApiLogModel.cs @@ -0,0 +1,36 @@ +using System; + +namespace WCS.Model.ApiModel.InterfaceRecord +{ + public class SystemApiLogModel + { + public int Id { get; set; } + + public string Type { get; set; } + + public string UserName { get; set; } + + public string DeviceType { get; set; } + + public string DeviceIp { get; set; } + + public string RequestUrl { get; set; } + + public string RequestBody { get; set; } + + public string QueryString { get; set; } + + public bool IsResponse { get; set; } + + public string ResponseJson { get; set; } + + public DateTime RequestTime { get; set; } + + public DateTime ResponseTime { get; set; } + + public long ExecutionTime { get; set; } + + public int RowNumber { get; set; } + } +} + diff --git a/WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs new file mode 100644 index 0000000..fddcc78 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/AddMatBaseInfoRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WCS.Model.ApiModel.User; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class AddMatBaseInfoRequest : RequestBase + { + public T MatBaseInfo { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } + +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs new file mode 100644 index 0000000..4068572 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/DeleteMatBaseInfosRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WCS.Model.ApiModel.User; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class DeleteMatBaseInfosRequest : RequestBase + { + public List MatBaseInfoIds { get; set; } + } + +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs new file mode 100644 index 0000000..84b1ded --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/GetMatBaseInfoRequest.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class GetMatBaseInfoRequest : PageQueryRequestBase + { + public string MatCode { get; set; } + + public string MatName { get; set; } + + public string MatSpec { get; set; } + + public bool? IsEnable { get; set; } = null; + } +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs b/WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs new file mode 100644 index 0000000..eff3309 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/GetMatCodeListRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class GetMatCodeListRequest : RequestBase + { + //是否是从基础数据返回 如果为false 从库存数据返回 + public bool IsFromBaseData { get; set; } + } +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs new file mode 100644 index 0000000..3fe8a82 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoImportModel.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatBaseInfo +{ + public class MatBaseInfoImportModel + { + public string 物料编码 { get; set; } + public string 名称 { get; set; } + public string 规格 { get; set; } + public string 单位 { get; set; } + public string 客户 { get; set; } + public string 状态 { get; set; } + } +} diff --git a/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs new file mode 100644 index 0000000..409bdd6 --- /dev/null +++ b/WCS.Model/ApiModel/MatBaseInfo/MatBaseInfoModel.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel; + +namespace WCS.BLL.DbModels +{ + /// + ///物料基础信息 + /// + public partial class MatBaseInfoModel: INotifyPropertyChanged + { + + public int Id { get; set; } + + public string MatCode { get; set; } + + public string MatName { get; set; } + + public string MatSpec { get; set; } + + public string MatUnit { get; set; } + + public string MatBatch { get; set; } + + public string MatSupplier { get; set; } + + public string MatCustomer { get; set; } + + public string ModifyUser { get; set; } + + public DateTime? ModifyTime { get; set; } = DateTime.Now; + + public bool IsEnable { get; set; } = true; + + public string IsEnableStr + { + get + { + if (IsEnable) + return "启用"; + else + return "禁用"; + } + } + + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + OnPropertyChanged(nameof(IsSelected)); + } + } + public bool isSelected; + + public int RowNumber { get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs b/WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs new file mode 100644 index 0000000..eed4b9b --- /dev/null +++ b/WCS.Model/ApiModel/MatInventoryDetail/GetMatInventoryDetailRequest.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatInventoryDetail +{ + public class GetMatInventoryDetailRequest : PageQueryRequestBase + { + #region 物料属性 + public string MatSN { get; set; } + + public string MatCode { get; set; } + + public string MatName { get; set; } + + public string MatSpec { get; set; } + + public string MatBatch { get; set; } + + public string MatSupplier { get; set; } + + public string MatCustomer { get; set; } + #endregion + + #region 库位属性 + public List ShelfTypeId { get; set; } + public List ShelfId { get; set; } + public int StoreId { get; set; } + public string StoreCode { get; set; } + #endregion + } +} diff --git a/WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs b/WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs new file mode 100644 index 0000000..8c8c4e7 --- /dev/null +++ b/WCS.Model/ApiModel/MatInventoryDetail/MatInventoryDetailModel.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.MatInventoryDetail +{ + public class MatInventoryDetailModel + { + public int Id { get; set; } + + #region 库位属性 + public int StoreId { get; set; } + public string StoreCode { get; set; } + //public StoreInfo StoreInfo { get; set; } + #endregion + + #region 物料属性 + public string MatSN { get; set; } + public string MatCode { get; set; } + public string MatName { get; set; } + public string MatSpec { get; set; } + public string MatBatch { get; set; } + public int MatQty { get; set; } + public string? MatSupplier { get; set; } + public string? MatCustomer { get; set; } + #endregion + + public DateTime InstoreTime { get; set; } = DateTime.Now; + public string InstoreUser { get; set; } + public bool IsLocked { get; set; } = false; + public int RowNumber { get; set; } + public bool IsSelected { get; set; } + } +} diff --git a/WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs b/WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs new file mode 100644 index 0000000..0087be3 --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/GetOutOrderDetailRequest.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetOutOrderDetailRequest : ResponseBase + { + public int OrderId { get; set; } + public string OrderNumber { get; set; } + + } +} diff --git a/WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs b/WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs new file mode 100644 index 0000000..c55e967 --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/GetOutOrderListRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class GetOutOrderListRequest : PageQueryRequestBase + { + public string OrderNumber { get; set; } + + public int OrderStatus { get; set; } + + //public int PageNumber { get; set; } + + //public int PageSize { get; set; } + } +} diff --git a/WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs new file mode 100644 index 0000000..5d64e8a --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatCodeRequest.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace WCS.Model +{ + public class SysOutOrderByMatCodeRequest : RequestBase + { + /// + /// 单据编号 + /// + public string OrderNumber { get; set; } + /// + /// 单据来源 + /// + public string OrderSource { get; set; } + /// + /// 单据类型 + /// + public string OrderType { get; set; } + + public List ItemList { get; set; } + + } + public class MatCodeItemList + { + public string MatCode { get; set; } + public string MatBatch { get; set; } + public int ReqQty { get; set; } + + } +} diff --git a/WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs new file mode 100644 index 0000000..e60189d --- /dev/null +++ b/WCS.Model/ApiModel/OutStore/SysOutOrderByMatSnRequest.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace WCS.Model +{ + public class SysOutOrderByMatSnRequest : RequestBase + { + /// + /// 单据编号 + /// + public string OrderNumber { get; set; } + /// + /// 单据来源 + /// + public string OrderSource { get; set; } + /// + /// 单据类型 + /// + public string OrderType { get; set; } + + public List SnList { get; set; } + } +} diff --git a/WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs b/WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs new file mode 100644 index 0000000..0fc9d4d --- /dev/null +++ b/WCS.Model/ApiModel/PageQuery/PageQueryResponse.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class PageQueryResponse : ResponseCommon + { + public PageQueryResponseData Data { get; set; } + } + public class PageQueryResponseData + { + public int Count { get; set; } + public int MaxPage { get; set; } + public int TotalCount { get; set; } + public List Lists { get; set; } + } +} diff --git a/WCS.Model/ApiModel/RequestBase.cs b/WCS.Model/ApiModel/RequestBase.cs new file mode 100644 index 0000000..ad37b3e --- /dev/null +++ b/WCS.Model/ApiModel/RequestBase.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class RequestBase + { + public string UserName { get; set; } + + public string DeviceType { get; set; } + } + + public class PageQueryRequestBase: RequestBase + { + public int PageNumber { get; set; } + + public int PageSize { get; set; } + } +} diff --git a/WCS.Model/ApiModel/ResponseBase.cs b/WCS.Model/ApiModel/ResponseBase.cs new file mode 100644 index 0000000..c23ee40 --- /dev/null +++ b/WCS.Model/ApiModel/ResponseBase.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model +{ + public class ResponseBase + { + public int Code { get; set; } + + public string Message { get; set; } + } + + public class ResponseBase : ResponseBase + { + public T Data { get; set; } + } + + public class ResponseCommon : ResponseBase + { + public object Data { get; set; } + } + + public class ResponseCommon : ResponseBase + { + public T Data { get; set; } + } +} diff --git a/WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs b/WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs new file mode 100644 index 0000000..4ef2b48 --- /dev/null +++ b/WCS.Model/ApiModel/StoreInfo/AddShelfInfoRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using WCS.Model.ApiModel.User; + +namespace WCS.Model.ApiModel.StoreInfo +{ + public class AddShelfInfoRequest : RequestBase + { + public T ShelfInfo { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } +} diff --git a/WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs b/WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs new file mode 100644 index 0000000..1348929 --- /dev/null +++ b/WCS.Model/ApiModel/StoreInfo/GetShelvesRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.StoreInfo +{ + public class GetShelvesRequest : PageQueryRequestBase + { + public int ShelfTypeId { get; set; } + public string ShelfCode { get; set; } + } +} diff --git a/WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs b/WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs new file mode 100644 index 0000000..eb2a6af --- /dev/null +++ b/WCS.Model/ApiModel/StoreInfo/ShelfInfoModel.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace WCS.Model.ApiModel.StoreInfo +{ + public class ShelfInfoModel : INotifyPropertyChanged + { + public int Id { get; set; } + + public string ShelfCode { get; set; } + public int ShelfTypeId { get; set; } + + /// + /// 货架类型名称 + /// + public string ShelfTypeName { get; set; } + + /// + /// 货架当前状态 + /// + public int CurrentMode { get; set; } + + /// + /// 货架行数 + /// + public int Rowcounts { get; set; } + + /// + /// 货架列数 + /// + public int Columncounts { get; set; } + + /// + /// 货架对应警示灯的Id + /// + public int LightId { get; set; } + + /// + /// 货架对应Can模块的Ip + /// + public string ClientIp { get; set; } + + /// + /// 货架的组别、区域(区分单个软件管哪些货架的,前端的配置文件配置一个组别,查询时只显示当前组别的货架) + /// + public string GroupName { get; set; } + + public bool IsBind { get; set; } + + public string BindShelfCode { get; set; } = string.Empty; + + + public int RowNumber { get; set; } + + public bool IsSelected + { + get { return isSelected; } + set + { + isSelected = value; + OnPropertyChanged(nameof(IsSelected)); + } + } + public bool isSelected; + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/WCS.Model/ApiModel/User/AddRoleRequest.cs b/WCS.Model/ApiModel/User/AddRoleRequest.cs new file mode 100644 index 0000000..ef85238 --- /dev/null +++ b/WCS.Model/ApiModel/User/AddRoleRequest.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class AddRoleRequest : RequestBase + { + public T Role { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } +} diff --git a/WCS.Model/ApiModel/User/AddUserRequest.cs b/WCS.Model/ApiModel/User/AddUserRequest.cs new file mode 100644 index 0000000..4d93197 --- /dev/null +++ b/WCS.Model/ApiModel/User/AddUserRequest.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class AddUserRequest : RequestBase + { + public T User { get; set; } + public AddOrUpdate AddOrUpdate { get; set; } + } + + public enum AddOrUpdate + { + Add = 0, + Update = 1, + Delete = 2 + } +} diff --git a/WCS.Model/ApiModel/User/AuthEnum.cs b/WCS.Model/ApiModel/User/AuthEnum.cs new file mode 100644 index 0000000..1f99993 --- /dev/null +++ b/WCS.Model/ApiModel/User/AuthEnum.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace WCS.Model.ApiModel +{ + /// + /// 认证项 + /// + public enum AuthEnum + { + /* 注意:枚举的值必须大于0 */ + 查询 = 1000, + 权限 = 2000, + //[Description("用户")] + //[EnumTree(权限, new[] { 用户新增, 用户删除, 用户修改 })] + //用户管理 = 3100, 用户新增 = 3110, 用户删除, 用户修改, + //[Description("角色")] + //[EnumTree(权限, new[] { 角色新增, 角色删除, 角色修改 })] + //角色管理 = 3200, 角色新增 = 3210, 角色删除, 角色修改, + 设置 = 3000, + 调试 = 4000, + } + + public class EnumTreeAttribute : Attribute + { + public EnumTreeAttribute() { } + + public EnumTreeAttribute(AuthEnum parent) + { + Parent = parent; + } + + public EnumTreeAttribute(AuthEnum[] childs) + { + Childs = childs; + } + + public EnumTreeAttribute(AuthEnum parent, AuthEnum[] childs) + { + Parent = parent; + Childs = childs; + } + + /// + /// 父级 + /// + public AuthEnum? Parent { get; set; } = null; + /// + /// 子级 + /// + public AuthEnum[]? Childs { get; set; } = null; + } +} diff --git a/WCS.Model/ApiModel/User/AuthModels.cs b/WCS.Model/ApiModel/User/AuthModels.cs new file mode 100644 index 0000000..688a9e7 --- /dev/null +++ b/WCS.Model/ApiModel/User/AuthModels.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WCS.Model.ApiModel +{ + + public class UserModel + { + public int Id { get; set; } + /// + /// 登录名 + /// + public string LoginName { get; set; } + /// + /// 密码 + /// + public string Password { get; set; } + + public List RoleIds { get; set; } = new List(); + + public List RoleNames { get; set; } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + + /// + /// 用户拥有的权限 + /// + public List GetRoles { get; set; } + } + public class RoleModel + { + public int Id { get; set; } + /// + /// 角色名 + /// + public string Name { get; set; } + + public List Auths { get; set; } = new List(); + + public List AuthNames { get => (Auths == null || !Auths.Any()) ? new List() : EnumHelps.GetEnumDescriptionList(typeof(AuthEnum), true).Where(o => Auths.Contains(o.Item1)).Select(o => o.Item3).ToList(); } + /// + /// 是否最大权限 + /// + public bool IsAdmin { get; set; } + /// + /// 创建时间 + /// + public DateTime Time { get; set; } + } + +} diff --git a/WCS.Model/ApiModel/User/EnumHelps.cs b/WCS.Model/ApiModel/User/EnumHelps.cs new file mode 100644 index 0000000..4a972e3 --- /dev/null +++ b/WCS.Model/ApiModel/User/EnumHelps.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Text; + +namespace WCS.Model.ApiModel +{ + public static class EnumHelps + { + public static List GetEnumList(Type type) + { + List strings = new List(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public) ?? new FieldInfo[] { }; + foreach (var field in fields) + { + strings.Add(field.Name); + } + } + else + { + + } + + return strings; + } + + /// + /// 得到枚举详情 + /// + /// 枚举 + /// 描述为空时,是否采用名称值 + /// 枚举值,名称,描述 + public static List> GetEnumDescriptionList(Type type, bool isDescriptionNullInName = false) + { + var strings = new List>(); + if (type.IsEnum) + { + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); + if (fields == null) + return strings; + + foreach (var field in fields) + { + int enumValue = Convert.ToInt32(field.GetRawConstantValue()); + string enumName = field.Name; + string description = string.Empty; + + var descriptionAttribute = field.GetCustomAttribute(false); + if (descriptionAttribute != null) + description = descriptionAttribute.Description; + else if (isDescriptionNullInName) + description = enumName; + + strings.Add(new Tuple(enumValue, enumName, description)); + } + } + else + { + + } + + return strings; + } + } +} diff --git a/WCS.Model/ApiModel/User/GetUsersRequest.cs b/WCS.Model/ApiModel/User/GetUsersRequest.cs new file mode 100644 index 0000000..9d2ec2b --- /dev/null +++ b/WCS.Model/ApiModel/User/GetUsersRequest.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class GetUsersRequest : RequestBase + { + public string Info { get; set; } + } +} diff --git a/WCS.Model/ApiModel/User/UserLoginRequest.cs b/WCS.Model/ApiModel/User/UserLoginRequest.cs new file mode 100644 index 0000000..f1b9c28 --- /dev/null +++ b/WCS.Model/ApiModel/User/UserLoginRequest.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WCS.Model.ApiModel.User +{ + public class UserLoginRequest : RequestBase + { + /// + /// 密码 + /// + public string PassWord { get; set; } + /// + /// 是否配置为不登陆(如果不登陆 直接获取admin 且不验证密码了) + /// + public bool IsNoLogin { get; set; } = false; + } +} diff --git a/WCS.Model/WCS.Model.csproj b/WCS.Model/WCS.Model.csproj new file mode 100644 index 0000000..7bfca4f --- /dev/null +++ b/WCS.Model/WCS.Model.csproj @@ -0,0 +1,6 @@ + + + netstandard2.0 + latest + + diff --git a/WCS.WebApi/.config/dotnet-tools.json b/WCS.WebApi/.config/dotnet-tools.json new file mode 100644 index 0000000..9d58272 --- /dev/null +++ b/WCS.WebApi/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "8.0.2", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/WCS.WebApi/Controllers/HomeController.cs b/WCS.WebApi/Controllers/HomeController.cs new file mode 100644 index 0000000..ff9b24a --- /dev/null +++ b/WCS.WebApi/Controllers/HomeController.cs @@ -0,0 +1,93 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel.Home; + +namespace WCS.WebApi.Controllers +{ + /// + /// 主页面的接口 + /// + [ApiController] + [Route("[controller]")] + public class HomeController : ControllerBase + { + public IHomerService _homerService { get; set; } + + public HomeController(IHomerService homerService) + { + _homerService = homerService; + } + + [Route("getShelfTypes")] + [HttpPost(Name = "getShelfTypes")] + public async Task getShelfTypes(RequestBase request) + { + try + { + //直接获取当前所有货架类型并返回 + var shelfTypes = DbHelp.db.Queryable() + .Select(t => new ShelfTypeModel() + { + Id = t.Id, + ShelfTypeName = t.ShelfTypeName + }) + .ToList(); + return new PageQueryResponse() + { + Code = 200, + Message = "success", + Data = new PageQueryResponseData + { + Lists = shelfTypes, + Count = shelfTypes.Count + } + }; + } + catch (Exception ex) + { + return new PageQueryResponse() + { + Code = 300, + Message = $"查询失败:{ex.Message}", + }; + } + } + + [Route("getShelfStatus")] + [HttpPost(Name = "getShelfStatus")] + public async Task getShelfStatus(GetShelfStatusRequest request) + { + try + { + var shelfs = ShelfManager.Shelves + .WhereIF(request.GroupNames?.Count > 0, t => request.GroupNames!.Contains(t.GroupName)) + .ToList(); + //直接返回当前内存中缓存的货架和状态 + return new GetShelfStatusResponse() + { + Code = 200, + Message = "success", + Data = shelfs.Select(t => new Shelf + { + ShelfId = t.ShelfId, + ShelfCode = t.ShelfCode, + CurentMode = (int)t.CurentMode, + ModulesStr = t.ModulesStr, + GroupName = t.GroupName + }).ToList(), + }; + } + catch (Exception ex) + { + return null; + } + } + + } +} diff --git a/WCS.WebApi/Controllers/InstoreController.cs b/WCS.WebApi/Controllers/InstoreController.cs new file mode 100644 index 0000000..d0ea3ab --- /dev/null +++ b/WCS.WebApi/Controllers/InstoreController.cs @@ -0,0 +1,117 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.HardWare; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.Model; + +namespace WebApi.Controllers +{ + [ApiController] + [Route("[controller]")] + public class InstoreController : ControllerBase + { + + private readonly ILogger _logger; + private readonly IInstoreService _instoreService; + + public InstoreController(ILogger logger, IInstoreService instoreService) + { + _logger = logger; + _instoreService = instoreService; + } + + /// + /// ģʽ + /// + /// + /// + [Route("shelfGoInInStore")] + [HttpPost(Name = "shelfGoInInStore")] + public async Task shelfGoInInStore(ShelfGoInInstoreRequest request) + { + string content = string.Empty; + try + { + //ȡ豸IPַ + var IPAdress = HttpContext?.Connection?.RemoteIpAddress?.ToString(); + if (string.IsNullOrEmpty(IPAdress)) + { + //δȡ豸IPַ TO DO ¼־δȡIP + } + else + { + //ȡ豸Ipַ request + request.IpAdress = IPAdress; + } + return _instoreService.shelfGoInInStore(request); + + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ܽģʽʧܣ" + ex.Message, + }; + } + } + + /// + /// ˳ģʽ + /// + /// + /// + [Route("shelfGoOutInStore")] + [HttpPost(Name = "shelfGoOutInStore")] + public async Task shelfGoOutInStore(ShelfGoOutInStoreRequest request) + { + try + { + return _instoreService.shelfGoOutInStore(request); + } + catch (Exception ex) + { + return new ResponseCommon() + { + Code = 300, + Message = $"˳ģʽʧ:{ex.Message}", + }; + } + } + + /// + /// ɨ ȡϸ + /// + /// + /// + [Route("queryByMatSn")] + [HttpPost(Name = "queryByMatSn")] + public async Task queryByMatSn(QueryByMatSnRequest request) + { + return _instoreService.queryByMatSn(request); + } + + /// + /// ѯ״̬ + /// + /// + /// + [Route("queryInstoreStatus")] + [HttpPost(Name = "queryInstoreStatus")] + public async Task queryInstoreStatus(QueryByMatSnRequest request) + { + try + { + return await _instoreService.queryInstoreStatus(request); + } + catch (Exception ex) + { + return new ResponseCommon() + { + Code = 300, + Message = $"ʧ:{ex.Message}", + }; + } + } + } +} diff --git a/WCS.WebApi/Controllers/InterfaceRecordController.cs b/WCS.WebApi/Controllers/InterfaceRecordController.cs new file mode 100644 index 0000000..9823e3b --- /dev/null +++ b/WCS.WebApi/Controllers/InterfaceRecordController.cs @@ -0,0 +1,82 @@ +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using NPOI.SS.UserModel; +using SqlSugar; +using System.Xml.Linq; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.WebApi.Helper; + +namespace WCS.WebApi.Controllers +{ + /// + /// 接口记录 + /// + [ApiController] + [Route("[controller]")] + public class InterfaceRecordController : ControllerBase + { + public IInterfaceRecordService _interfaceRecordService { get; set; } + + public InterfaceRecordController(IInterfaceRecordService interfaceRecordService) + { + _interfaceRecordService = interfaceRecordService; + } + + [Route("getInterfaceRecord")] + [HttpPost(Name = "getInterfaceRecord")] + public async Task getInterfaceRecord(GetInterfaceRecordsRequest request) + { + return await _interfaceRecordService.getInterfaceRecord(request); + } + + [HttpPost("exportInterfaceRecord")] + public async Task exportInterfaceRecord([FromBody] GetInterfaceRecordsRequest request) + { + var result = await _interfaceRecordService.exportInterfaceRecord(request); + var data = result.Data?.Lists; + var columns = new[] + { + new ExportableColumn("序号","RowNumber"), + new ExportableColumn("接口地址","RequestUrl"), + new ExportableColumn("设备IP","DeviceIp"), + new ExportableColumn("请求参数","RequestBody"), + new ExportableColumn("QueryString","QueryString"), + new ExportableColumn("请求时间","RequestTime"), + new ExportableColumn("返回参数","ResponseJson"), + new ExportableColumn("返回时间","ResponseTime"), + new ExportableColumn("耗时(ms)", "ExecutionTime"), + }; + if (data == null) + { + return NotFound(); + } + else + return ExportExcelHelper.Export("导出数据", columns, data); + + // 导出到Excel + //using (var stream = new MemoryStream()) + //{ + // // 获取当前工作目录 + // string currentPath = Directory.GetCurrentDirectory(); + // // 创建文件路径 + // string filePath = Path.Combine(currentPath, "data.xlsx"); + // //MiniExcel.SaveAs(filePath, data); + // MiniExcel.SaveAs(stream, data); + // // 重置位置 + // //stream.Position = 0; + // //// 通过接口下载文件 + // //return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "data.xlsx"); + // var isXlsx = true; + // var saveAsFileName = string.Format("{0}-{1:d}.{2}", "测试", DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + // var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + // return new FileContentResult(stream.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + //} + } + } +} diff --git a/WCS.WebApi/Controllers/MatBaseInfoController.cs b/WCS.WebApi/Controllers/MatBaseInfoController.cs new file mode 100644 index 0000000..70834ad --- /dev/null +++ b/WCS.WebApi/Controllers/MatBaseInfoController.cs @@ -0,0 +1,104 @@ +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using NPOI.SS.UserModel; +using SqlSugar; +using System.Xml.Linq; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.WebApi.Helper; + +namespace WCS.WebApi.Controllers +{ + /// + /// 接口记录 + /// + [ApiController] + [Route("[controller]")] + public class MatBaseInfoController : ControllerBase + { + public IMatBaseInfoService _matBaseInfoService { get; set; } + + public MatBaseInfoController(IMatBaseInfoService matBaseInfoService) + { + _matBaseInfoService = matBaseInfoService; + } + + [Route("getMatBaseInfo")] + [HttpPost(Name = "getMatBaseInfo")] + public async Task getMatBaseInfo(GetMatBaseInfoRequest request) + { + return await _matBaseInfoService.getMatBaseInfo(request); + } + + [HttpPost("exportMatBaseInfo")] + public async Task exportMatBaseInfo(GetMatBaseInfoRequest request) + { + var result = await _matBaseInfoService.exportMatBaseInfo(request); + var data = result.Data?.Lists; + var columns = new[] + { + new ExportableColumn("序号","RowNumber"), + new ExportableColumn("物料编码","MatCode"), + new ExportableColumn("名称","MatName"), + new ExportableColumn("规格","MatSpec"), + new ExportableColumn("单位","MatUnit"), + new ExportableColumn("客户","MatCustomer"), + new ExportableColumn("状态","IsEnableStr"), + new ExportableColumn("更新人","ModifyUser"), + new ExportableColumn("更新时间", "ModifyTime"), + }; + if (data == null) + { + return NotFound(); + } + else + return ExportExcelHelper.Export("导出数据", columns, data); + } + + [HttpPost("importMatBaseInfo")] + public async Task importMatBaseInfo([FromForm] IFormFile excelFile, [FromForm] string userName, [FromForm] string deviceType) + { + //文件校验 + if (excelFile == null || excelFile.Length == 0) + { + return new ResponseCommon() + { + Code = 201, + Message = "导入失败:文件无有效内容!" + }; + } + // + using (var stream = new MemoryStream()) + { + await excelFile.CopyToAsync(stream); + stream.Position = 0; + var list = MiniExcelLibs.MiniExcel.Query(stream, "物料管理", ExcelType.XLSX).ToList(); + return await _matBaseInfoService.importMatBaseInfo(list, userName, deviceType); + } + } + + [HttpPost("addOrUpdateMatBaseInfo")] + public async Task> addOrUpdateMatBaseInfo(AddMatBaseInfoRequest request) + { + return await _matBaseInfoService.addOrUpdateMatBaseInfo(request); + } + + [HttpPost("deleteMatBaseInfo")] + public async Task> deleteMatBaseInfo(DeleteMatBaseInfosRequest request) + { + return await _matBaseInfoService.deleteMatBaseInfo(request); + } + + [HttpPost("getMatCodeList")] + public async Task>> getMatCodeList(GetMatCodeListRequest request) + { + return await _matBaseInfoService.getMatCodeList(request); + } + } +} diff --git a/WCS.WebApi/Controllers/MatInventoryDetailController.cs b/WCS.WebApi/Controllers/MatInventoryDetailController.cs new file mode 100644 index 0000000..5bb8e06 --- /dev/null +++ b/WCS.WebApi/Controllers/MatInventoryDetailController.cs @@ -0,0 +1,84 @@ +using Microsoft.AspNetCore.Mvc; +using MiniExcelLibs; +using NPOI.SS.UserModel; +using SqlSugar; +using System.Xml.Linq; +using WCS.BLL.DbModels; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL.Db; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.WebApi.Helper; + +namespace WCS.WebApi.Controllers +{ + /// + /// 接口记录 + /// + [ApiController] + [Route("[controller]")] + public class MatInventoryDetailController : ControllerBase + { + public IMatInventoryDetailService _matInventoryDetailService { get; set; } + + public MatInventoryDetailController(IMatInventoryDetailService matInventoryDetailService) + { + _matInventoryDetailService = matInventoryDetailService; + } + + [Route("getMatInventoryDetail")] + [HttpPost(Name = "getMatInventoryDetail")] + public async Task getMatInventoryDetail(GetMatInventoryDetailRequest request) + { + return await _matInventoryDetailService.getMatInventoryDetail(request); + } + + [HttpPost("exportMatInventoryDetail")] + public async Task exportMatInventoryDetail([FromBody] GetMatInventoryDetailRequest request) + { + var result = await _matInventoryDetailService.exportMatInventoryDetail(request); + var data = result.Data?.Lists; + var columns = new[] + { + new ExportableColumn("序号","RowNumber"), + new ExportableColumn("物料编码","MatCode"), + new ExportableColumn("物料名称","MatName"), + new ExportableColumn("规格","MatSpec"), + new ExportableColumn("批次","MatBatch"), + new ExportableColumn("数量","MatQty"), + new ExportableColumn("库位","StoreCode"), + new ExportableColumn("入库时间","InstoreTime"), + new ExportableColumn("物料SN", "MatSN"), + }; + if (data == null) + { + return NotFound(); + } + else + return ExportExcelHelper.Export("导出数据", columns, data); + + // 导出到Excel + //using (var stream = new MemoryStream()) + //{ + // // 获取当前工作目录 + // string currentPath = Directory.GetCurrentDirectory(); + // // 创建文件路径 + // string filePath = Path.Combine(currentPath, "data.xlsx"); + // //MiniExcel.SaveAs(filePath, data); + // MiniExcel.SaveAs(stream, data); + // // 重置位置 + // //stream.Position = 0; + // //// 通过接口下载文件 + // //return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "data.xlsx"); + // var isXlsx = true; + // var saveAsFileName = string.Format("{0}-{1:d}.{2}", "测试", DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + // var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + // return new FileContentResult(stream.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + //} + } + + } +} diff --git a/WCS.WebApi/Controllers/OutstoreController.cs b/WCS.WebApi/Controllers/OutstoreController.cs new file mode 100644 index 0000000..a2c5e8c --- /dev/null +++ b/WCS.WebApi/Controllers/OutstoreController.cs @@ -0,0 +1,162 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.HardWare; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.Model; + +namespace WebApi.Controllers +{ + //[ServiceFilter(typeof(LogActionFilter))] + [ApiController] + [Route("[controller]")] + public class OutstoreController : ControllerBase + { + private readonly IOutstoreService _outstoreService; + + public OutstoreController(IOutstoreService outstoreService) + { + _outstoreService = outstoreService; + } + + /// + /// ϱͬ + /// + /// + /// + [Route("sysOutOrderByMatCode")] + [HttpPost(Name = "sysOutOrderByMatCode")] + public async Task sysOutOrderByMatCode(SysOutOrderByMatCodeRequest request) + { + try + { + return await _outstoreService.SysOutOrderByMatCode(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ͬʧܣ" + ex.Message, + }; + } + } + + + /// + /// ϸͬ + /// + /// + /// + [Route("sysOutOrderByMatSn")] + [HttpPost(Name = "sysOutOrderByMatSn")] + public async Task sysOutOrderByMatSn(SysOutOrderByMatSnRequest request) + { + try + { + return await _outstoreService.SysOutOrderByMatSn(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ͬʧܣ" + ex.Message, + }; + } + } + + + /// + /// ѯصǰⵥб + /// + /// + /// + [Route("getOutOrderList")] + [HttpPost(Name = "getOutOrderList")] + public async Task getOutOrderList(GetOutOrderListRequest request) + { + try + { + return await _outstoreService.GetOutOrderList(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + + /// + /// ȡⵥijϸ + /// + /// + /// + [Route("getOutOrderDetail")] + [HttpPost(Name = "getOutOrderDetail")] + public async Task getOutOrderDetail(GetOutOrderDetailRequest request) + { + try + { + return await _outstoreService.GetOutOrderDetail(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + + /// + /// ͨⵥݺſʼ + /// + /// + /// + [Route("goInOutstore")] + [HttpPost(Name = "goInOutstore")] + public async Task goInOutstore(GetOutOrderDetailRequest request) + { + try + { + return await _outstoreService.GetOutOrderDetail(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + + /// + /// ͨⵥݺ˳/ + /// + /// + /// + [Route("goOutOutstore")] + [HttpPost(Name = "goOutOutstore")] + public async Task goOutOutstore(GetOutOrderDetailRequest request) + { + try + { + return await _outstoreService.GetOutOrderDetail(request); + } + catch (Exception ex) + { + return new ShelfGoInInstoreResponse() + { + Code = 300, + Message = "ѯʧܣ" + ex.Message, + }; + } + } + } +} diff --git a/WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs b/WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs new file mode 100644 index 0000000..8456dda --- /dev/null +++ b/WCS.WebApi/Controllers/RequestResponseLoggingMiddleware.cs @@ -0,0 +1,94 @@ +using System.Diagnostics; +using System.Text; +using WCS.BLL; +using WCS.BLL.DbModels; +using WCS.DAL.Db; + +namespace WCS.WebApi.Controllers +{ + public class RequestResponseLoggingMiddleware + { + private readonly RequestDelegate _next; + + public RequestResponseLoggingMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + var stopwatch = Stopwatch.StartNew(); + + var requestBody = string.Empty; + var responseBody = string.Empty; + var originalRequestBody = context.Request.Body; + var requestTime = DateTime.Now; + + // 可以选择只记录特定的Content-RequestType //只记录json类型的请求 + if (context.Request.ContentType != null && !context.Request.ContentType.Contains("application/json", StringComparison.OrdinalIgnoreCase)) + { + ; + } + try + { + ////读取Request Body + //// 保存原始的Request Body + var requestBodyStream = new MemoryStream(); + await originalRequestBody.CopyToAsync(requestBodyStream); + originalRequestBody.Dispose(); + requestBodyStream.Position = 0; // 将流的位置重置回开始处 + requestBody = await new StreamReader(requestBodyStream).ReadToEndAsync(); + // 替换Request.Body以便后续中间件可以读取 + requestBodyStream.Position = 0;// 将流的位置重置回开始处 + context.Request.Body = requestBodyStream; + + + // 保存原始的Response Body + var originalResponseBodyStream = context.Response.Body; + using (var memStream = new MemoryStream()) + { + context.Response.Body = memStream; + + // 继续处理请求 + await _next(context); + + memStream.Seek(0, SeekOrigin.Begin); + responseBody = await new StreamReader(memStream).ReadToEndAsync(); + + memStream.Seek(0, SeekOrigin.Begin); + await memStream.CopyToAsync(originalResponseBodyStream); + } + } + catch (Exception e) + { + //Logs.Write(e.Message); + } + + finally + { + //TO DO如何将记日志的 和不记日志的分开 解耦 + if (!context.Request.Path.ToString().Contains("getInterfaceRecord")) + try + { + var logRecord = new SystemApiLogRecord() + { + DeviceIp = context?.Connection?.RemoteIpAddress?.ToString(), + RequestUrl = context.Request.Path, + RequestBody = requestBody, + QueryString = context.Request.QueryString.ToString(), + IsResponse = true, + ResponseJson = responseBody, + RequestTime = requestTime, + ResponseTime = DateTime.Now, + ExecutionTime = stopwatch.ElapsedMilliseconds + }; + await DbHelp.dbLog.Insertable(logRecord).ExecuteCommandAsync(); + } + catch (Exception e) + { + //TO DO txt记录失败的日志和响应实体 + } + } + } + } +} diff --git a/WCS.WebApi/Controllers/StoreInfoController.cs b/WCS.WebApi/Controllers/StoreInfoController.cs new file mode 100644 index 0000000..d70b609 --- /dev/null +++ b/WCS.WebApi/Controllers/StoreInfoController.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.Model.ApiModel.MatInventoryDetail; +using WCS.Model; +using WCS.Model.ApiModel.StoreInfo; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.DAL.DbModels; + +namespace WCS.WebApi.Controllers +{ + /// + /// 货架\、库位管理的页面 + /// + [ApiController] + [Route("[controller]")] + public class StoreInfoController : ControllerBase + { + public IStoreInfoService _storeInfoService { get; set; } + public StoreInfoController(IStoreInfoService storeInfoService) + { + _storeInfoService = storeInfoService; + } + + [Route("getShelves")] + [HttpPost(Name = "getShelves")] + public async Task getShelves(GetShelvesRequest request) + { + return await _storeInfoService.GetShelves(request); + } + + [HttpPost("addOrUpdateShelfInfo")] + public async Task> addOrUpdateShelfInfo(AddShelfInfoRequest request) + { + return await _storeInfoService.addOrUpdateShelfInfo(request); + } + } +} diff --git a/WCS.WebApi/Controllers/UserController.cs b/WCS.WebApi/Controllers/UserController.cs new file mode 100644 index 0000000..bc70c55 --- /dev/null +++ b/WCS.WebApi/Controllers/UserController.cs @@ -0,0 +1,58 @@ +using Microsoft.AspNetCore.Mvc; +using WCS.BLL.Services.IService; +using WCS.Model; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; + +namespace WCS.WebApi.Controllers +{ + /// + /// 权限/用户界面的接口 + /// + [ApiController] + [Route("[controller]")] + public class UserController : ControllerBase + { + public IUserService _userService { get; set; } + + public UserController(IUserService userService) + { + _userService = userService; + } + + [Route("getUsers")] + [HttpPost(Name = "getUsers")] + public async Task getUsers(GetUsersRequest request) + { + return await _userService.GetUsers(request); + } + + [Route("addUser")] + [HttpPost(Name = "addUser")] + public async Task addUser(AddUserRequest request) + { + return await _userService.AddUser(request); + } + + [Route("getRoles")] + [HttpPost(Name = "getRoles")] + public async Task getRoles(GetUsersRequest request) + { + return await _userService.GetRoles(request); + } + + [Route("addRole")] + [HttpPost(Name = "addRole")] + public async Task addRole(AddRoleRequest request) + { + return await _userService.AddRole(request); + } + + [Route("userLogin")] + [HttpPost(Name = "userLogin")] + public async Task userLogin(UserLoginRequest request) + { + return await _userService.UserLogin(request); + } + } +} diff --git a/WCS.WebApi/Helper/ExportExcelHelper.cs b/WCS.WebApi/Helper/ExportExcelHelper.cs new file mode 100644 index 0000000..01bac09 --- /dev/null +++ b/WCS.WebApi/Helper/ExportExcelHelper.cs @@ -0,0 +1,249 @@ +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using System.Data; +using System.Dynamic; + +namespace WCS.WebApi.Helper +{ + public class ExportExcelHelper + { + /// + /// + /// 文件名 + /// 标题行 + /// 数据源 + /// + public static ActionResult ExportExcel(string sheetName, List columns, IList results) + { + var isXlsx = false; + IWorkbook workbook = new HSSFWorkbook(); + if (results.Count + 1 > 65536)// 包括一行标题行 .xls文件最大行数 + { + workbook = new XSSFWorkbook(); + isXlsx = true; + } + workbook.CreateSheet(sheetName); + + var rowIndex = 0; + AddHeader(workbook, rowIndex, columns); + + rowIndex++; + workbook = AddData(workbook, rowIndex, columns, results); + + // Save the Excel spreadsheet to a MemoryStream and return it to the client + using (var exportData = new MemoryStream()) + { + workbook.Write(exportData); + var saveAsFileName = string.Format("{0}-{1:d}.{2}", sheetName, DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + return new FileContentResult(exportData.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + } + } + + public static ActionResult Export(string sheetName, IList columns, IEnumerable results) + { + var isXlsx = false; + IWorkbook workbook = new HSSFWorkbook(); + if (results.Count() + 1 > 65536)// 包括一行标题行 .xls文件最大行数 + { + workbook = new XSSFWorkbook(); + isXlsx = true; + } + workbook.CreateSheet(sheetName); + var rowIndex = 0; + + AddHeader(workbook, rowIndex, columns); + + rowIndex++; + workbook = AddData(workbook, rowIndex, columns, results); + + // Save the Excel spreadsheet to a MemoryStream and return it to the client + using (var exportData = new MemoryStream()) + { + workbook.Write(exportData); + var saveAsFileName = string.Format("{0}-{1:d}.{2}", sheetName, DateTime.Now, (isXlsx ? "xlsx" : "xls")).Replace("/", "-"); + var contentType = isXlsx ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"; + return new FileContentResult(exportData.ToArray(), contentType) { FileDownloadName = saveAsFileName }; + } + } + + public static ActionResult Export( + string sheetName, + string firstData, + IList columns, + IEnumerable results + ) + { + IWorkbook workbook = new HSSFWorkbook(); + var sheet = workbook.CreateSheet(sheetName); + var rowIndex = 0; + + // first row data + var firstRow = sheet.CreateRow(rowIndex); + firstRow.CreateCell(0).SetCellValue(firstData); + rowIndex++; + + AddHeader(workbook, rowIndex, columns); + + rowIndex++; + workbook = AddData(workbook, rowIndex, columns, results); + + // Save the Excel spreadsheet to a MemoryStream and return it to the client + using (var exportData = new MemoryStream()) + { + workbook.Write(exportData); + string saveAsFileName = string.Format("{0}-{1:d}.xls", sheetName, DateTime.Now).Replace("/", "-"); + return new FileContentResult(exportData.ToArray(), "application/vnd.ms-excel") { FileDownloadName = saveAsFileName }; + } + } + + #region 数据操作 + public static IWorkbook AddData(IWorkbook workbook, int rowIndex, List columns, IList results) + { + const int MaxRowCount = 1048575; //.xlsx文件最大行数1048576 + var sheet = workbook.GetSheetAt(0); + + // Add data rows + foreach (var viewModel in results) + { + var row = sheet.CreateRow(rowIndex); + if (rowIndex >= MaxRowCount) + { + row.CreateCell(0).SetCellValue("数据行数已超出Excel文件支持的最大行数!"); + break; + } + + for (var index = 0; index < columns.Count; index++) + { + var propertyName = columns[index].Name.Trim(); + var cell = row.CreateCell(index); + var propertyDictionary = (IDictionary)viewModel; + if (propertyDictionary.ContainsKey(propertyName)) + { + var value = propertyDictionary[propertyName]; + cell.SetCellValue(value == null ? "" : value.ToString()); + } + } + + rowIndex++; + } + + return workbook; + } + + public static IWorkbook AddData(IWorkbook workbook, int rowIndex, IList columns, IEnumerable results) + { + const int MaxRowCount = 1048575; //.xlsx文件最大行数1048576 + var sheet = workbook.GetSheetAt(0); + + // Add data rows + foreach (var viewModel in results) + { + var row = sheet.CreateRow(rowIndex); + if (rowIndex >= MaxRowCount) + { + row.CreateCell(0).SetCellValue("数据行数已超出Excel文件支持的最大行数!"); + break; + } + + for (int index = 0; index < columns.Count; index++) + { + var cell = row.CreateCell(index); + var dr = viewModel as DataRow; + var value = (dr != null) ? dr[columns[index].Name] + : viewModel.GetType().GetProperty(columns[index].Name)?.GetValue(viewModel, null); + + if (value == null) + { + var item = viewModel as ExpandoObject; + if (item != null) + { + if (item.Any(w => w.Key == columns[index].Name)) + { + var keyValue = item.FirstOrDefault(w => w.Key == columns[index].Name); + value = keyValue.Value; + } + } + } + if (value == null) + { + var item = viewModel as JObject; + if (item != null) + { + value = item[columns[index].Name]; + } + } + + cell.SetCellValue(value == null ? "" : value.ToString()); + } + + rowIndex++; + } + + return workbook; + } + + public static void AddHeader(IWorkbook workbook, int rowIndex, IList columns) + { + var sheet = workbook.GetSheetAt(0); + var format = workbook.CreateDataFormat(); + + // Add header labels + var headerRow = sheet.CreateRow(rowIndex); + for (int index = 0; index < columns.Count; index++) + { + headerRow.CreateCell(index).SetCellValue(columns[index].Caption); + if (!string.IsNullOrEmpty(columns[index].Format)) + { + var columnStyle = workbook.CreateCellStyle(); + columnStyle.DataFormat = format.GetFormat(columns[index].Format); + sheet.SetDefaultColumnStyle(index, columnStyle); + } + if (columns[index].ColumnWidth.HasValue && columns[index].ColumnWidth.Value > 0) + { + var columnWidth = columns[index].ColumnWidth.Value; + sheet.SetColumnWidth(index, columnWidth * 256 / 7); + } + } + } + #endregion + } + + public class ExportableColumn + { + public ExportableColumn(string caption, string name) : this(caption, name, null) + { + } + + public ExportableColumn(string caption, string name, string format) + { + Format = format; + Caption = caption; + Name = name; + } + + public ExportableColumn(string caption, string name, string format, int? width) + : this(caption, name, format) + { + ColumnWidth = width; + } + + public string Name { get; } + public string Caption { get; } + public string Format { get; } + + /// + /// 单位:像素,为空时使用默认值 + /// + public int? ColumnWidth { get; private set; } + + public ExportableColumn Width(int? width) + { + ColumnWidth = width; + return this; + } + } +} diff --git a/WCS.WebApi/LocalStatic.cs b/WCS.WebApi/LocalStatic.cs new file mode 100644 index 0000000..5bfa45d --- /dev/null +++ b/WCS.WebApi/LocalStatic.cs @@ -0,0 +1,9 @@ +using WCS.BLL; + +namespace WCS.WebApi +{ + public static class LocalStatic + { + + } +} diff --git a/WCS.WebApi/Program.cs b/WCS.WebApi/Program.cs new file mode 100644 index 0000000..e531e97 --- /dev/null +++ b/WCS.WebApi/Program.cs @@ -0,0 +1,81 @@ + +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using System.Net; +using System.Net.Http; +using System.Net.Sockets; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; +using WCS.BLL.Manager; +using WCS.BLL.Services.IService; +using WCS.BLL.Services.Service; +using WCS.DAL; +using WCS.DAL.Db; +using WCS.WebApi; +using WCS.WebApi.Controllers; +using TcpClient = TouchSocket.Sockets.TcpClient; + +namespace WebApi +{ + public class Program + { + public static void Main(string[] args) + { + + + //LocalStatic.wCSTcpCleint = new WCS.BLL.TCPClient("127.0.0.1:20002"); + //LocalStatic.wCSTcpCleint.Send(new byte[] { 0x08, 0x00, 0x00, 0x11, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + + DbHelp.InitDb(); + AuthDbHelp.InitDb(); + + ShelfManager.InitShelves(); + + + var builder = WebApplication.CreateBuilder(args); + //// Kestrel + //builder.WebHost.ConfigureKestrel((context, options) => + //{ + // // ü˿ + // options.Listen(IPAddress.Any, 8888); // IPַ5001˿ + + // // + // options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // СΪ10MB + // options.Limits.MaxConcurrentConnections = 1000; // 󲢷 + // options.Limits.MinRequestBodyDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10)); // Сݴ + + // // ҪSSL/TLSӴ + // // : options.Listen(IPAddress.Any, 5000, listenOptions => { listenOptions.UseHttps("path_to_certificate.pfx", "certificate_password"); }); + //}); + // Add services to the container. + builder.Services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + var app = builder.Build(); + + app.UseMiddleware(); + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseAuthorization(); + app.MapControllers(); + app.Run("http://+:8888"); + } + } +} diff --git a/WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml b/WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..55a44a5 --- /dev/null +++ b/WCS.WebApi/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,22 @@ + + + + + false + false + true + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + <_TargetId>Folder + + net6.0 + win-x64 + 118d453b-1693-4c00-8378-20ecbfcf2700 + false + + \ No newline at end of file diff --git a/WCS.WebApi/Properties/launchSettings.json b/WCS.WebApi/Properties/launchSettings.json new file mode 100644 index 0000000..9ca601d --- /dev/null +++ b/WCS.WebApi/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:60772", + "sslPort": 0 + } + }, + "profiles": { + "WCS.WebApi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5055", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WCS.WebApi/WCS.WebApi.csproj b/WCS.WebApi/WCS.WebApi.csproj new file mode 100644 index 0000000..adda62f --- /dev/null +++ b/WCS.WebApi/WCS.WebApi.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/WCS.WebApi/WCS后端.sln b/WCS.WebApi/WCS后端.sln new file mode 100644 index 0000000..3f36bb4 --- /dev/null +++ b/WCS.WebApi/WCS后端.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.WebApi", "WCS.WebApi.csproj", "{118D453B-1693-4C00-8378-20ECBFCF2700}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.DAL", "..\WCS.DAL\WCS.DAL.csproj", "{DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.BLL", "..\WCS.BLL\WCS.BLL.csproj", "{A6B0DB70-BE92-487C-BA6B-56441B676C85}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "货架标准上位机", "..\货架标准上位机\货架标准上位机.csproj", "{A24FAA0F-8483-4741-BFE7-EC2C56C811A6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WCS.Model", "..\WCS.Model\WCS.Model.csproj", "{7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {118D453B-1693-4C00-8378-20ECBFCF2700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {118D453B-1693-4C00-8378-20ECBFCF2700}.Debug|Any CPU.Build.0 = Debug|Any CPU + {118D453B-1693-4C00-8378-20ECBFCF2700}.Release|Any CPU.ActiveCfg = Release|Any CPU + {118D453B-1693-4C00-8378-20ECBFCF2700}.Release|Any CPU.Build.0 = Release|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DBA12DF9-F9E7-444C-B02D-A6A1D1F7C19A}.Release|Any CPU.Build.0 = Release|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6B0DB70-BE92-487C-BA6B-56441B676C85}.Release|Any CPU.Build.0 = Release|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A24FAA0F-8483-4741-BFE7-EC2C56C811A6}.Release|Any CPU.Build.0 = Release|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CE9AF07-3538-46C3-BBF0-A039BDE15AAF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6760D971-76D6-4E00-8F93-37164B9CA696} + EndGlobalSection +EndGlobal diff --git a/WCS.WebApi/appsettings.Development.json b/WCS.WebApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/WCS.WebApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/WCS.WebApi/appsettings.json b/WCS.WebApi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/WCS.WebApi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/WCS.WebApi/data.xlsx b/WCS.WebApi/data.xlsx new file mode 100644 index 0000000..4217c68 Binary files /dev/null and b/WCS.WebApi/data.xlsx differ diff --git a/货架标准上位机/Api/ApiHelp.cs b/货架标准上位机/Api/ApiHelp.cs new file mode 100644 index 0000000..625d944 --- /dev/null +++ b/货架标准上位机/Api/ApiHelp.cs @@ -0,0 +1,316 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; +using WCS.Model; + +namespace 货架标准上位机.Api +{ + public static class ApiHelp + { + public static HttpClient httpClient; + static ApiHelp() + { + httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromSeconds(10); + httpClient.DefaultRequestHeaders.Add("UserModel-Agent", "Chrome/95.0.4638.69 Safari/537.36"); + ServicePointManager.Expect100Continue = false; + } + + public static async Task Get(string uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Get(IEnumerable uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Get(string uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Get(IEnumerable uri, object? query = null, object? body = null) + { + return await Send(HttpMethod.Get, uri, query, body); + } + + public static async Task Post(string uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Post(IEnumerable uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Post(string uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Post(IEnumerable uri, object? body = null, object? query = null) + { + return await Send(HttpMethod.Post, uri, query, body); + } + + public static async Task Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return await Send(method, new string[] { uri }, query, body); + } + + public static async Task Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query)); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = await httpClient.SendAsync(httpRequestMessage); + if (!re.IsSuccessStatusCode) + return new ResponseBase() { Code = (int)re.StatusCode }; + + var con = await re.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(con) ?? new ResponseBase(); + } + + public static async Task Send(HttpMethod method, string uri, object? query = null, object? body = null) + { + return await Send(method, new string[] { uri }, query, body); + } + + public static async Task Send(HttpMethod method, IEnumerable uri, object? query = null, object? body = null) + { + try + { + var url = "".AppendPathSegments(uri).SetQueryParams(query); + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, url); + + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + + var re = await httpClient.SendAsync(httpRequestMessage); + if (!re.IsSuccessStatusCode) + return default(T); + + var con = await re.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(con) ?? default(T); ; + } + catch (Exception ex) + { + return default(T); + } + + } + + /// + /// 追加路径片段(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com + /// 路径片段 + /// 地址 + public static string AppendPathSegments(this string url, IEnumerable segments) + { + string urlStr = url.Trim(); + foreach (var segment in segments) + { + var val = segment?.ToString()?.Trim() ?? ""; + if (string.IsNullOrWhiteSpace(val)) + continue; + + if (urlStr.EndsWith("/")) + urlStr = urlStr.Substring(0, urlStr.Length - 1); + + if (val.Length > 0) + urlStr += string.IsNullOrEmpty(urlStr) || val.StartsWith("/") ? val : $"/{val}"; + } + return urlStr; + } + + /// + /// 设置Query参数(有更高要求可以使用Flurl库) + /// + /// 地址,如 https://www.baidu.com/s + /// 参数,支持字典和对象 + /// 地址 + public static string SetQueryParams(this string url, object? values) + { + string urlStr = url; + if (values == null) + return urlStr; + + List kv = new List(); + if (values is IEnumerable jh) + { + if (jh is IDictionary dict) + { + foreach (DictionaryEntry item in dict) + kv.Add($"{item.Key?.ToString()}={item.Value?.ToString()}"); + } + } + else + { + foreach (var item in values.GetType().GetProperties()) + { + if (item.CanRead) + kv.Add($"{item.Name}={item.GetValue(values)?.ToString()}"); + } + } + + if (kv.Any()) + { + if (!urlStr.Contains("?")) + urlStr += "?"; + else + { + if (!urlStr.EndsWith("&")) + urlStr += "&"; + } + + urlStr += string.Join("&", kv); + } + + return urlStr; + } + + /// + /// Post方式下载Excel文件 + /// + /// 文件保存的路径 + /// + /// + /// + /// + public static async Task PostDownloadFileAsync(string localFilePath, HttpMethod method, string requestUrl, object? body = null) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, requestUrl); + if (body != null) + { + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + httpRequestMessage.Content = content; + } + using (var response = await httpClient.SendAsync(httpRequestMessage)) + { + response.EnsureSuccessStatusCode(); // 确保请求成功 + + // 获取内容头中的文件名(如果需要的话) + //var contentDisposition = ContentDispositionHeaderValue.Parse(response.Content.Headers.ContentDisposition.ToString()); + //string filename = contentDisposition.FileName.Trim('"'); // 去除引号 + var filename = string.Empty; + // 如果提供的本地文件路径没有文件名,则使用从响应头中获取的文件名 + if (Path.GetFileName(localFilePath) == string.Empty) + { + localFilePath = Path.Combine(Path.GetDirectoryName(localFilePath), filename); + } + // 写入文件 + using (var fileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) + { + await response.Content.CopyToAsync(fileStream); + } + } + } + + /// + /// Post方式导入Excel文件 + /// + /// 文件保存的路径 + /// + /// + /// + /// + public static async Task PostImportFileAsync(string localFilePath, HttpMethod method, string requestUrl, string userName, string deviceType) + { + HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, requestUrl); + + using (var content = new MultipartFormDataContent()) + { + var fileContent = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read)); + fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); + content.Add(fileContent, "excelFile", Path.GetFileName(localFilePath)); + + var userNameContent = new StringContent(userName); + userNameContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); + content.Add(userNameContent, "userName"); + + var deviceTypeContent = new StringContent(deviceType); + deviceTypeContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); + content.Add(deviceTypeContent, "deviceType"); + + httpRequestMessage.Content = content; + using (var response = await httpClient.SendAsync(httpRequestMessage)) + { + response.EnsureSuccessStatusCode(); // 确保请求成功 + var filename = string.Empty; + + if (!response.IsSuccessStatusCode) + return default(T); + + var con = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(con) ?? default(T); ; + } + } + } + + + public static T GetDataFromHttp(string url, object dataObj, string httpMethod, bool isSaveLog = false) + { + Guid guid = Guid.NewGuid(); + var data = JsonConvert.SerializeObject(dataObj); + try + { + if (isSaveLog) + Logs.Write($"【{guid}】开始请求调用接口 url:{url} 请求方式:{httpMethod} 数据:{data}"); + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = httpMethod; + request.ContentType = "application/json"; + request.Timeout = 100000; + + if (!string.IsNullOrEmpty(data)) + { + string strContent = data; //参数data + using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream())) + { + dataStream.Write(strContent); + dataStream.Close(); + } + } + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + string encoding = response.ContentEncoding; + if (encoding == null || encoding.Length < 1) + { + encoding = "UTF-8"; //默认编码 + } + StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); + string retString = reader.ReadToEnd(); + if (isSaveLog) + Logs.Write($"【{guid}】请求调用接口结束 返回数据为{retString}"); + return JsonConvert.DeserializeObject(retString); + } + catch (Exception ex) + { + Logs.Write($"【{guid}】请求调用遇到异常 异常信息为{ex.Message}"); + return default(T); + } + } + } +} diff --git a/货架标准上位机/App.xaml b/货架标准上位机/App.xaml new file mode 100644 index 0000000..1640844 --- /dev/null +++ b/货架标准上位机/App.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + pack://application,,,/货架标准上位机;component/Fonts/#iconfont + + 卓越盟讯 + 智造未来 + + + \ No newline at end of file diff --git a/货架标准上位机/App.xaml.cs b/货架标准上位机/App.xaml.cs new file mode 100644 index 0000000..e7a4e99 --- /dev/null +++ b/货架标准上位机/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace 货架标准上位机 +{ + /// + /// App.xaml 的交互逻辑 + /// + public partial class App : Application + { + } +} diff --git a/货架标准上位机/Converters/AuthConverter.cs b/货架标准上位机/Converters/AuthConverter.cs new file mode 100644 index 0000000..bad6d36 --- /dev/null +++ b/货架标准上位机/Converters/AuthConverter.cs @@ -0,0 +1,54 @@ +using HandyControl.Tools; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; + +namespace 货架标准上位机 +{ + /// + /// 权限转换器(转为bool) + /// + public class AuthConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (DesignerHelper.IsInDesignMode) + return true; + + return AuthConverter.IsAuth(parameter); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + /// + /// 是否有权限 + /// + /// 认证项 + /// + public static bool IsAuth(object value) + { + if (UserInfoView.viewModel.User == null || UserInfoView.viewModel.Roles == null || !UserInfoView.viewModel.Roles.Any()) + return false; + if (UserInfoView.viewModel.User.IsAdmin || UserInfoView.viewModel.Roles.Any(o => o.IsAdmin)) + return true; + if (value == null) + return false; + + if (UserInfoView.viewModel.Roles.Any(o => o.Auths.Contains((int)value))) + return true; + else + return false; + } + } +} diff --git a/货架标准上位机/Converters/AuthVisConverter.cs b/货架标准上位机/Converters/AuthVisConverter.cs new file mode 100644 index 0000000..1ebcece --- /dev/null +++ b/货架标准上位机/Converters/AuthVisConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows; +using HandyControl.Tools; + +namespace 货架标准上位机 +{ + /// + /// 权限转换器 + /// + public class AuthVisConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (DesignerHelper.IsInDesignMode) + return Visibility.Visible; + + return AuthConverter.IsAuth(parameter) ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/货架标准上位机/Converters/AuthVisHidConverter.cs b/货架标准上位机/Converters/AuthVisHidConverter.cs new file mode 100644 index 0000000..6806129 --- /dev/null +++ b/货架标准上位机/Converters/AuthVisHidConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows; +using HandyControl.Tools; + +namespace 货架标准上位机 +{ + /// + /// 权限转换器 + /// + public class AuthVisHidConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (DesignerHelper.IsInDesignMode) + return Visibility.Visible; + + return AuthConverter.IsAuth(parameter) ? Visibility.Visible : Visibility.Hidden; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/货架标准上位机/Db/DataDb.cs b/货架标准上位机/Db/DataDb.cs new file mode 100644 index 0000000..d13fbb5 --- /dev/null +++ b/货架标准上位机/Db/DataDb.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 默认数据库 + /// + public static class DataDb + { + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = LocalFile.Config.MySql, + DbType = DbType.MySqlConnector, + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + Logs.Write($@"{nameof(DataDb)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + } +} diff --git a/货架标准上位机/Db/Models/DataModels.cs b/货架标准上位机/Db/Models/DataModels.cs new file mode 100644 index 0000000..05a4e00 --- /dev/null +++ b/货架标准上位机/Db/Models/DataModels.cs @@ -0,0 +1,20 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + [SugarTable("test_table")] + public class MyTestTable + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]//主键、自增 + public long Id { get; set; } + public string Info1 { get; set; } + public string Info2 { get; set; } + public string Status { get; set; } + public DateTime Time { get; set; } + } +} diff --git a/货架标准上位机/Db/WarnInfoDb.cs b/货架标准上位机/Db/WarnInfoDb.cs new file mode 100644 index 0000000..bd40944 --- /dev/null +++ b/货架标准上位机/Db/WarnInfoDb.cs @@ -0,0 +1,130 @@ +using HandyControl.Tools.Extension; +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 警告信息数据库 + /// + public static class WarnInfoDb + { + /// + /// 是否启用 + /// + public static bool IsEnabled = false; + + public static SqlSugarScope db = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = $"Data Source={Path.Combine(LocalFile.DataDir, "WarnInfo.db3")};Version=3;journal_mode=WAL;",//并发写加入:journal_mode=WAL; + DbType = DbType.Sqlite,//[Sqlite]安装[System.Data.SQLite.Core]; + IsAutoCloseConnection = true + }, db => + { + db.Aop.OnError = ex => + { + Logs.Write($@"{nameof(WarnInfoDb)}{Environment.NewLine}SQL:{ex?.Sql}{Environment.NewLine}Parametres:{JsonConvert.SerializeObject(ex?.Parametres)}{Environment.NewLine}InnerException:{ex?.InnerException?.ToString()}{Environment.NewLine}Exception:{ex?.ToString()}{Environment.NewLine}", LogsType.DbErr); + }; + }); + + /// + /// 初始化数据 + /// + public static void Ini() + { + //不存在创建数据库,存在不会创建 + db.DbMaintenance.CreateDatabase(); + //创建表根据实体类 + db.CodeFirst.InitTables(typeof(WarnInfoItemDb)); + IsEnabled = true; + } + + /// + /// 清除数据 + /// + /// 保留时间 + /// 清理的数量 + public static int Clear(TimeSpan time) + { + try + { + var dt = DateTime.Now.Date.AddDays(1) - time; + return WarnInfoDb.db.Deleteable().Where(o => o.TimeGo < dt).ExecuteCommand(); + } + catch (Exception) + { + return 0; + } + } + } + + /// + /// 警告信息 + /// + [SugarTable("WarnInfoItem")] + [SugarIndex("index_TimeGo", nameof(WarnInfoItemDb.TimeGo), OrderByType.Desc)] + public class WarnInfoItemDb + { + [SugarColumn(IsPrimaryKey = true, IsIdentity = false)] + public string Id { get; set; } + /// + /// 来源 + /// + [SugarColumn(IsNullable = true)] + public string Source { get; set; } + /// + /// 文本信息 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string Text { get; set; } + /// + /// 级别(提示、警告、错误、致命) + /// + [SugarColumn(IsNullable = true)] + public string Level { get; set; } + /// + /// 解决方案 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string Solution { get; set; } + /// + /// 警告类型 + /// + public string WarnType { get; set; } + /// + /// 开始时间 + /// + public DateTime TimeGo { get; set; } + /// + /// 结束时间 + /// + [SugarColumn(IsNullable = true)] + public DateTime? TimeTo { get; set; } + /// + /// 持续时间 + /// + [SugarColumn(IsIgnore = true)] + public string DuraTime { get => TimeTo.HasValue ? $"{((int)(TimeTo.Value - TimeGo).TotalHours).ToString().PadLeft(2, '0')}:{(TimeTo.Value - TimeGo).Minutes.ToString().PadLeft(2, '0')}:{(TimeTo.Value - TimeGo).Seconds.ToString().PadLeft(2, '0')}" : ""; } + + public static List GetList(IEnumerable warnInfos) + { + return warnInfos.Select(o => new WarnInfoItemDb() + { + Id = o.Id, + Source = o.Source, + Text = o.Text, + Level = o.Level, + Solution = o.Solution, + WarnType = o.WarnType == WarnInfoType.AlwayWarn ? "常驻错误" : "循环错误", + TimeGo = o.TimeGo, + TimeTo = o.TimeTo, + }).ToList(); + } + } +} diff --git a/货架标准上位机/Excel/物料管理导入模板.xlsx b/货架标准上位机/Excel/物料管理导入模板.xlsx new file mode 100644 index 0000000..b05fdc5 Binary files /dev/null and b/货架标准上位机/Excel/物料管理导入模板.xlsx differ diff --git a/货架标准上位机/Fonts/demo/demo.css b/货架标准上位机/Fonts/demo/demo.css new file mode 100644 index 0000000..a67054a --- /dev/null +++ b/货架标准上位机/Fonts/demo/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/货架标准上位机/Fonts/demo/demo_index.html b/货架标准上位机/Fonts/demo/demo_index.html new file mode 100644 index 0000000..62f1837 --- /dev/null +++ b/货架标准上位机/Fonts/demo/demo_index.html @@ -0,0 +1,1658 @@ + + + + + iconfont Demo + + + + + + + + + + + + + +
+

+ + +

+ +
+
+
    + +
  • + +
    COM004
    +
    &#xe62d;
    +
  • + +
  • + +
    网络2
    +
    &#xe630;
    +
  • + +
  • + +
    蓝牙
    +
    &#xe63f;
    +
  • + +
  • + +
    wifi无线网
    +
    &#xe6f1;
    +
  • + +
  • + +
    自动执行
    +
    &#xe6e3;
    +
  • + +
  • + +
    手动
    +
    &#xe729;
    +
  • + +
  • + +
    126-编程
    +
    &#xe678;
    +
  • + +
  • + +
    二维码
    +
    &#xe60c;
    +
  • + +
  • + +
    3.1-扫码
    +
    &#xe60e;
    +
  • + +
  • + +
    气缸
    +
    &#xe638;
    +
  • + +
  • + +
    权限
    +
    &#xe612;
    +
  • + +
  • + +
    点位
    +
    &#xe6dd;
    +
  • + +
  • + +
    流程
    +
    &#xe63a;
    +
  • + +
  • + +
    KHCFDC_流程
    +
    &#xe6d3;
    +
  • + +
  • + +
    主流程
    +
    &#xe63e;
    +
  • + +
  • + +
    伺服马达
    +
    &#xe607;
    +
  • + +
  • + +
    编辑流程
    +
    &#xe60a;
    +
  • + +
  • + +
    救命啊_help16
    +
    &#xe940;
    +
  • + +
  • + +
    添加
    +
    &#xe657;
    +
  • + +
  • + +
    修改
    +
    &#xe8cf;
    +
  • + +
  • + +
    重命名
    +
    &#xe606;
    +
  • + +
  • + +
    清除
    +
    &#xe62c;
    +
  • + +
  • + +
    24gl-trash2
    +
    &#xeb45;
    +
  • + +
  • + +
    电子制造业
    +
    &#xe618;
    +
  • + +
  • + +
    生产制造
    +
    &#xe633;
    +
  • + +
  • + +
    包装
    +
    &#xe61b;
    +
  • + +
  • + +
    传送带
    +
    &#xe639;
    +
  • + +
  • + +
    列表2
    +
    &#xe605;
    +
  • + +
  • + +
    +
    &#xe62f;
    +
  • + +
  • + +
    单图排列
    +
    &#xe604;
    +
  • + +
  • + +
    全屏_o
    +
    &#xeb99;
    +
  • + +
  • + +
    皮肤
    +
    &#xe62b;
    +
  • + +
  • + +
    颜色库
    +
    &#xee22;
    +
  • + +
  • + +
    照明
    +
    &#xe65a;
    +
  • + +
  • + +
    时间
    +
    &#xe64d;
    +
  • + +
  • + +
    取消
    +
    &#xe601;
    +
  • + +
  • + +
    启动
    +
    &#xe67d;
    +
  • + +
  • + +
    24gl-pauseCircle
    +
    &#xea6d;
    +
  • + +
  • + +
    照明
    +
    &#xe62e;
    +
  • + +
  • + +
    货品类型-01
    +
    &#xe632;
    +
  • + +
  • + +
    复位
    +
    &#xe61f;
    +
  • + +
  • + +
    不合格
    +
    &#xe602;
    +
  • + +
  • + +
    合格
    +
    &#xe603;
    +
  • + +
  • + +
    对勾
    +
    &#xe65d;
    +
  • + +
  • + +
    机器人
    +
    &#xe60d;
    +
  • + +
  • + +
    机器人_o
    +
    &#xeb62;
    +
  • + +
  • + +
    帮助
    +
    &#xe60b;
    +
  • + +
  • + +
    关于
    +
    &#xe608;
    +
  • + +
  • + +
    主页
    +
    &#xe625;
    +
  • + +
  • + +
    icon_使用文档
    +
    &#xeb91;
    +
  • + +
  • + +
    日志管理
    +
    &#xe61d;
    +
  • + +
  • + +
    皮肤
    +
    &#xe743;
    +
  • + +
  • + +
    工作
    +
    &#xe609;
    +
  • + +
  • + +
    工作流—工作流管理
    +
    &#xe64c;
    +
  • + +
  • + +
    查询
    +
    &#xec4c;
    +
  • + +
  • + +
    流计算
    +
    &#xec56;
    +
  • + +
  • + +
    手,手掌,巴掌
    +
    &#xe91a;
    +
  • + +
  • + +
    更多
    +
    &#xe600;
    +
  • + +
  • + +
    设置
    +
    &#xe64b;
    +
  • + +
  • + +
    用户
    +
    &#xe649;
    +
  • + +
  • + +
    调试
    +
    &#xeb61;
    +
  • + +
  • + +
    用户群体-业务查询
    +
    &#xe616;
    +
  • + +
  • + +
    折线图
    +
    &#xec66;
    +
  • + +
  • + +
    查询
    +
    &#xe63b;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • +
+
+

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.ttf?t=1699499055878') format('truetype');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + COM004 +
    +
    .icon-com004 +
    +
  • + +
  • + +
    + 网络2 +
    +
    .icon-wangluo +
    +
  • + +
  • + +
    + 蓝牙 +
    +
    .icon-lanya +
    +
  • + +
  • + +
    + wifi无线网 +
    +
    .icon-wifiwuxianwang +
    +
  • + +
  • + +
    + 自动执行 +
    +
    .icon-zidongzhihang +
    +
  • + +
  • + +
    + 手动 +
    +
    .icon-shoudong +
    +
  • + +
  • + +
    + 126-编程 +
    +
    .icon-biancheng-01 +
    +
  • + +
  • + +
    + 二维码 +
    +
    .icon-erweima +
    +
  • + +
  • + +
    + 3.1-扫码 +
    +
    .icon-31saoma +
    +
  • + +
  • + +
    + 气缸 +
    +
    .icon-qigang +
    +
  • + +
  • + +
    + 权限 +
    +
    .icon-quanxian +
    +
  • + +
  • + +
    + 点位 +
    +
    .icon-dianwei +
    +
  • + +
  • + +
    + 流程 +
    +
    .icon-liucheng +
    +
  • + +
  • + +
    + KHCFDC_流程 +
    +
    .icon-liucheng1 +
    +
  • + +
  • + +
    + 主流程 +
    +
    .icon-zhuliucheng +
    +
  • + +
  • + +
    + 伺服马达 +
    +
    .icon-sifumada +
    +
  • + +
  • + +
    + 编辑流程 +
    +
    .icon-p1-3-1 +
    +
  • + +
  • + +
    + 救命啊_help16 +
    +
    .icon-jiumingahelp16 +
    +
  • + +
  • + +
    + 添加 +
    +
    .icon-tianjia +
    +
  • + +
  • + +
    + 修改 +
    +
    .icon-xiugai +
    +
  • + +
  • + +
    + 重命名 +
    +
    .icon-zhongmingming +
    +
  • + +
  • + +
    + 清除 +
    +
    .icon-qingchu +
    +
  • + +
  • + +
    + 24gl-trash2 +
    +
    .icon-24gl-trash2 +
    +
  • + +
  • + +
    + 电子制造业 +
    +
    .icon-yunliankeji_gongyinglianfuben +
    +
  • + +
  • + +
    + 生产制造 +
    +
    .icon-tubiaozhizuomoban-116 +
    +
  • + +
  • + +
    + 包装 +
    +
    .icon-baozhuang +
    +
  • + +
  • + +
    + 传送带 +
    +
    .icon-45kejichuangxin-chuansongdai +
    +
  • + +
  • + +
    + 列表2 +
    +
    .icon-liebiao2 +
    +
  • + +
  • + +
    + 圆 +
    +
    .icon-yuan +
    +
  • + +
  • + +
    + 单图排列 +
    +
    .icon-dantupailie +
    +
  • + +
  • + +
    + 全屏_o +
    +
    .icon-quanping_o +
    +
  • + +
  • + +
    + 皮肤 +
    +
    .icon-pifu1 +
    +
  • + +
  • + +
    + 颜色库 +
    +
    .icon-yanseku +
    +
  • + +
  • + +
    + 照明 +
    +
    .icon-zhaoming2 +
    +
  • + +
  • + +
    + 时间 +
    +
    .icon-shijian +
    +
  • + +
  • + +
    + 取消 +
    +
    .icon-quxiao +
    +
  • + +
  • + +
    + 启动 +
    +
    .icon-qidong +
    +
  • + +
  • + +
    + 24gl-pauseCircle +
    +
    .icon-24gl-pauseCircle +
    +
  • + +
  • + +
    + 照明 +
    +
    .icon-zhaoming +
    +
  • + +
  • + +
    + 货品类型-01 +
    +
    .icon-huopinleixing- +
    +
  • + +
  • + +
    + 复位 +
    +
    .icon-fuwei +
    +
  • + +
  • + +
    + 不合格 +
    +
    .icon-buhege +
    +
  • + +
  • + +
    + 合格 +
    +
    .icon-hege +
    +
  • + +
  • + +
    + 对勾 +
    +
    .icon-duigou +
    +
  • + +
  • + +
    + 机器人 +
    +
    .icon-jiqiren +
    +
  • + +
  • + +
    + 机器人_o +
    +
    .icon-jiqiren_o +
    +
  • + +
  • + +
    + 帮助 +
    +
    .icon-help +
    +
  • + +
  • + +
    + 关于 +
    +
    .icon-guanyu +
    +
  • + +
  • + +
    + 主页 +
    +
    .icon-zhuye1 +
    +
  • + +
  • + +
    + icon_使用文档 +
    +
    .icon-icon_shiyongwendang +
    +
  • + +
  • + +
    + 日志管理 +
    +
    .icon-rizhiguanli +
    +
  • + +
  • + +
    + 皮肤 +
    +
    .icon-pifu +
    +
  • + +
  • + +
    + 工作 +
    +
    .icon-gongzuo +
    +
  • + +
  • + +
    + 工作流—工作流管理 +
    +
    .icon-gongzuoliugongzuoliuguanli +
    +
  • + +
  • + +
    + 查询 +
    +
    .icon-chaxun1 +
    +
  • + +
  • + +
    + 流计算 +
    +
    .icon-liujisuan +
    +
  • + +
  • + +
    + 手,手掌,巴掌 +
    +
    .icon-hand +
    +
  • + +
  • + +
    + 更多 +
    +
    .icon-gengduo +
    +
  • + +
  • + +
    + 设置 +
    +
    .icon-shezhi +
    +
  • + +
  • + +
    + 用户 +
    +
    .icon-yonghu +
    +
  • + +
  • + +
    + 调试 +
    +
    .icon-tiaoshi +
    +
  • + +
  • + +
    + 用户群体-业务查询 +
    +
    .icon-yonghu1 +
    +
  • + +
  • + +
    + 折线图 +
    +
    .icon-zhexiantu +
    +
  • + +
  • + +
    + 查询 +
    +
    .icon-chaxun +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont icon-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    COM004
    +
    #icon-com004
    +
  • + +
  • + +
    网络2
    +
    #icon-wangluo
    +
  • + +
  • + +
    蓝牙
    +
    #icon-lanya
    +
  • + +
  • + +
    wifi无线网
    +
    #icon-wifiwuxianwang
    +
  • + +
  • + +
    自动执行
    +
    #icon-zidongzhihang
    +
  • + +
  • + +
    手动
    +
    #icon-shoudong
    +
  • + +
  • + +
    126-编程
    +
    #icon-biancheng-01
    +
  • + +
  • + +
    二维码
    +
    #icon-erweima
    +
  • + +
  • + +
    3.1-扫码
    +
    #icon-31saoma
    +
  • + +
  • + +
    气缸
    +
    #icon-qigang
    +
  • + +
  • + +
    权限
    +
    #icon-quanxian
    +
  • + +
  • + +
    点位
    +
    #icon-dianwei
    +
  • + +
  • + +
    流程
    +
    #icon-liucheng
    +
  • + +
  • + +
    KHCFDC_流程
    +
    #icon-liucheng1
    +
  • + +
  • + +
    主流程
    +
    #icon-zhuliucheng
    +
  • + +
  • + +
    伺服马达
    +
    #icon-sifumada
    +
  • + +
  • + +
    编辑流程
    +
    #icon-p1-3-1
    +
  • + +
  • + +
    救命啊_help16
    +
    #icon-jiumingahelp16
    +
  • + +
  • + +
    添加
    +
    #icon-tianjia
    +
  • + +
  • + +
    修改
    +
    #icon-xiugai
    +
  • + +
  • + +
    重命名
    +
    #icon-zhongmingming
    +
  • + +
  • + +
    清除
    +
    #icon-qingchu
    +
  • + +
  • + +
    24gl-trash2
    +
    #icon-24gl-trash2
    +
  • + +
  • + +
    电子制造业
    +
    #icon-yunliankeji_gongyinglianfuben
    +
  • + +
  • + +
    生产制造
    +
    #icon-tubiaozhizuomoban-116
    +
  • + +
  • + +
    包装
    +
    #icon-baozhuang
    +
  • + +
  • + +
    传送带
    +
    #icon-45kejichuangxin-chuansongdai
    +
  • + +
  • + +
    列表2
    +
    #icon-liebiao2
    +
  • + +
  • + +
    +
    #icon-yuan
    +
  • + +
  • + +
    单图排列
    +
    #icon-dantupailie
    +
  • + +
  • + +
    全屏_o
    +
    #icon-quanping_o
    +
  • + +
  • + +
    皮肤
    +
    #icon-pifu1
    +
  • + +
  • + +
    颜色库
    +
    #icon-yanseku
    +
  • + +
  • + +
    照明
    +
    #icon-zhaoming2
    +
  • + +
  • + +
    时间
    +
    #icon-shijian
    +
  • + +
  • + +
    取消
    +
    #icon-quxiao
    +
  • + +
  • + +
    启动
    +
    #icon-qidong
    +
  • + +
  • + +
    24gl-pauseCircle
    +
    #icon-24gl-pauseCircle
    +
  • + +
  • + +
    照明
    +
    #icon-zhaoming
    +
  • + +
  • + +
    货品类型-01
    +
    #icon-huopinleixing-
    +
  • + +
  • + +
    复位
    +
    #icon-fuwei
    +
  • + +
  • + +
    不合格
    +
    #icon-buhege
    +
  • + +
  • + +
    合格
    +
    #icon-hege
    +
  • + +
  • + +
    对勾
    +
    #icon-duigou
    +
  • + +
  • + +
    机器人
    +
    #icon-jiqiren
    +
  • + +
  • + +
    机器人_o
    +
    #icon-jiqiren_o
    +
  • + +
  • + +
    帮助
    +
    #icon-help
    +
  • + +
  • + +
    关于
    +
    #icon-guanyu
    +
  • + +
  • + +
    主页
    +
    #icon-zhuye1
    +
  • + +
  • + +
    icon_使用文档
    +
    #icon-icon_shiyongwendang
    +
  • + +
  • + +
    日志管理
    +
    #icon-rizhiguanli
    +
  • + +
  • + +
    皮肤
    +
    #icon-pifu
    +
  • + +
  • + +
    工作
    +
    #icon-gongzuo
    +
  • + +
  • + +
    工作流—工作流管理
    +
    #icon-gongzuoliugongzuoliuguanli
    +
  • + +
  • + +
    查询
    +
    #icon-chaxun1
    +
  • + +
  • + +
    流计算
    +
    #icon-liujisuan
    +
  • + +
  • + +
    手,手掌,巴掌
    +
    #icon-hand
    +
  • + +
  • + +
    更多
    +
    #icon-gengduo
    +
  • + +
  • + +
    设置
    +
    #icon-shezhi
    +
  • + +
  • + +
    用户
    +
    #icon-yonghu
    +
  • + +
  • + +
    调试
    +
    #icon-tiaoshi
    +
  • + +
  • + +
    用户群体-业务查询
    +
    #icon-yonghu1
    +
  • + +
  • + +
    折线图
    +
    #icon-zhexiantu
    +
  • + +
  • + +
    查询
    +
    #icon-chaxun
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/货架标准上位机/Fonts/demo/iconfont.css b/货架标准上位机/Fonts/demo/iconfont.css new file mode 100644 index 0000000..c97f52d --- /dev/null +++ b/货架标准上位机/Fonts/demo/iconfont.css @@ -0,0 +1,269 @@ +@font-face { + font-family: "iconfont"; /* Project id 3809552 */ + src: url('iconfont.ttf?t=1699499055878') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-com004:before { + content: "\e62d"; +} + +.icon-wangluo:before { + content: "\e630"; +} + +.icon-lanya:before { + content: "\e63f"; +} + +.icon-wifiwuxianwang:before { + content: "\e6f1"; +} + +.icon-zidongzhihang:before { + content: "\e6e3"; +} + +.icon-shoudong:before { + content: "\e729"; +} + +.icon-biancheng-01:before { + content: "\e678"; +} + +.icon-erweima:before { + content: "\e60c"; +} + +.icon-31saoma:before { + content: "\e60e"; +} + +.icon-qigang:before { + content: "\e638"; +} + +.icon-quanxian:before { + content: "\e612"; +} + +.icon-dianwei:before { + content: "\e6dd"; +} + +.icon-liucheng:before { + content: "\e63a"; +} + +.icon-liucheng1:before { + content: "\e6d3"; +} + +.icon-zhuliucheng:before { + content: "\e63e"; +} + +.icon-sifumada:before { + content: "\e607"; +} + +.icon-p1-3-1:before { + content: "\e60a"; +} + +.icon-jiumingahelp16:before { + content: "\e940"; +} + +.icon-tianjia:before { + content: "\e657"; +} + +.icon-xiugai:before { + content: "\e8cf"; +} + +.icon-zhongmingming:before { + content: "\e606"; +} + +.icon-qingchu:before { + content: "\e62c"; +} + +.icon-24gl-trash2:before { + content: "\eb45"; +} + +.icon-yunliankeji_gongyinglianfuben:before { + content: "\e618"; +} + +.icon-tubiaozhizuomoban-116:before { + content: "\e633"; +} + +.icon-baozhuang:before { + content: "\e61b"; +} + +.icon-45kejichuangxin-chuansongdai:before { + content: "\e639"; +} + +.icon-liebiao2:before { + content: "\e605"; +} + +.icon-yuan:before { + content: "\e62f"; +} + +.icon-dantupailie:before { + content: "\e604"; +} + +.icon-quanping_o:before { + content: "\eb99"; +} + +.icon-pifu1:before { + content: "\e62b"; +} + +.icon-yanseku:before { + content: "\ee22"; +} + +.icon-zhaoming2:before { + content: "\e65a"; +} + +.icon-shijian:before { + content: "\e64d"; +} + +.icon-quxiao:before { + content: "\e601"; +} + +.icon-qidong:before { + content: "\e67d"; +} + +.icon-24gl-pauseCircle:before { + content: "\ea6d"; +} + +.icon-zhaoming:before { + content: "\e62e"; +} + +.icon-huopinleixing-:before { + content: "\e632"; +} + +.icon-fuwei:before { + content: "\e61f"; +} + +.icon-buhege:before { + content: "\e602"; +} + +.icon-hege:before { + content: "\e603"; +} + +.icon-duigou:before { + content: "\e65d"; +} + +.icon-jiqiren:before { + content: "\e60d"; +} + +.icon-jiqiren_o:before { + content: "\eb62"; +} + +.icon-help:before { + content: "\e60b"; +} + +.icon-guanyu:before { + content: "\e608"; +} + +.icon-zhuye1:before { + content: "\e625"; +} + +.icon-icon_shiyongwendang:before { + content: "\eb91"; +} + +.icon-rizhiguanli:before { + content: "\e61d"; +} + +.icon-pifu:before { + content: "\e743"; +} + +.icon-gongzuo:before { + content: "\e609"; +} + +.icon-gongzuoliugongzuoliuguanli:before { + content: "\e64c"; +} + +.icon-chaxun1:before { + content: "\ec4c"; +} + +.icon-liujisuan:before { + content: "\ec56"; +} + +.icon-hand:before { + content: "\e91a"; +} + +.icon-gengduo:before { + content: "\e600"; +} + +.icon-shezhi:before { + content: "\e64b"; +} + +.icon-yonghu:before { + content: "\e649"; +} + +.icon-tiaoshi:before { + content: "\eb61"; +} + +.icon-yonghu1:before { + content: "\e616"; +} + +.icon-zhexiantu:before { + content: "\ec66"; +} + +.icon-chaxun:before { + content: "\e63b"; +} + diff --git a/货架标准上位机/Fonts/demo/iconfont.js b/货架标准上位机/Fonts/demo/iconfont.js new file mode 100644 index 0000000..213b113 --- /dev/null +++ b/货架标准上位机/Fonts/demo/iconfont.js @@ -0,0 +1 @@ +window._iconfont_svg_string_3809552='',function(a){var c=(c=document.getElementsByTagName("script"))[c.length-1],l=c.getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var s,h,z,i,o,t=function(c,l){l.parentNode.insertBefore(c,l)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}s=function(){var c,l=document.createElement("div");l.innerHTML=a._iconfont_svg_string_3809552,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(c=document.body).firstChild?t(l,c.firstChild):c.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(s,0):(h=function(){document.removeEventListener("DOMContentLoaded",h,!1),s()},document.addEventListener("DOMContentLoaded",h,!1)):document.attachEvent&&(z=s,i=a.document,o=!1,m(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,v())})}function v(){o||(o=!0,z())}function m(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(m,50)}v()}}(window); \ No newline at end of file diff --git a/货架标准上位机/Fonts/demo/iconfont.json b/货架标准上位机/Fonts/demo/iconfont.json new file mode 100644 index 0000000..19823cc --- /dev/null +++ b/货架标准上位机/Fonts/demo/iconfont.json @@ -0,0 +1,457 @@ +{ + "id": "3809552", + "name": "font1", + "font_family": "iconfont", + "css_prefix_text": "icon-", + "description": "", + "glyphs": [ + { + "icon_id": "1286979", + "name": "COM004", + "font_class": "com004", + "unicode": "e62d", + "unicode_decimal": 58925 + }, + { + "icon_id": "6582325", + "name": "网络2", + "font_class": "wangluo", + "unicode": "e630", + "unicode_decimal": 58928 + }, + { + "icon_id": "6582355", + "name": "蓝牙", + "font_class": "lanya", + "unicode": "e63f", + "unicode_decimal": 58943 + }, + { + "icon_id": "20009354", + "name": "wifi无线网", + "font_class": "wifiwuxianwang", + "unicode": "e6f1", + "unicode_decimal": 59121 + }, + { + "icon_id": "1790443", + "name": "自动执行", + "font_class": "zidongzhihang", + "unicode": "e6e3", + "unicode_decimal": 59107 + }, + { + "icon_id": "8791338", + "name": "手动", + "font_class": "shoudong", + "unicode": "e729", + "unicode_decimal": 59177 + }, + { + "icon_id": "27100643", + "name": "126-编程", + "font_class": "biancheng-01", + "unicode": "e678", + "unicode_decimal": 59000 + }, + { + "icon_id": "77191", + "name": "二维码", + "font_class": "erweima", + "unicode": "e60c", + "unicode_decimal": 58892 + }, + { + "icon_id": "201568", + "name": "3.1-扫码", + "font_class": "31saoma", + "unicode": "e60e", + "unicode_decimal": 58894 + }, + { + "icon_id": "35634503", + "name": "气缸", + "font_class": "qigang", + "unicode": "e638", + "unicode_decimal": 58936 + }, + { + "icon_id": "736503", + "name": "权限", + "font_class": "quanxian", + "unicode": "e612", + "unicode_decimal": 58898 + }, + { + "icon_id": "26992661", + "name": "点位", + "font_class": "dianwei", + "unicode": "e6dd", + "unicode_decimal": 59101 + }, + { + "icon_id": "6193798", + "name": "流程", + "font_class": "liucheng", + "unicode": "e63a", + "unicode_decimal": 58938 + }, + { + "icon_id": "9874504", + "name": "KHCFDC_流程 ", + "font_class": "liucheng1", + "unicode": "e6d3", + "unicode_decimal": 59091 + }, + { + "icon_id": "11121496", + "name": "主流程", + "font_class": "zhuliucheng", + "unicode": "e63e", + "unicode_decimal": 58942 + }, + { + "icon_id": "12844268", + "name": "伺服马达", + "font_class": "sifumada", + "unicode": "e607", + "unicode_decimal": 58887 + }, + { + "icon_id": "22615372", + "name": "编辑流程", + "font_class": "p1-3-1", + "unicode": "e60a", + "unicode_decimal": 58890 + }, + { + "icon_id": "866275", + "name": "救命啊_help16", + "font_class": "jiumingahelp16", + "unicode": "e940", + "unicode_decimal": 59712 + }, + { + "icon_id": "145479", + "name": "添加", + "font_class": "tianjia", + "unicode": "e657", + "unicode_decimal": 58967 + }, + { + "icon_id": "2076418", + "name": "修改", + "font_class": "xiugai", + "unicode": "e8cf", + "unicode_decimal": 59599 + }, + { + "icon_id": "5923116", + "name": "重命名", + "font_class": "zhongmingming", + "unicode": "e606", + "unicode_decimal": 58886 + }, + { + "icon_id": "1130641", + "name": "清除", + "font_class": "qingchu", + "unicode": "e62c", + "unicode_decimal": 58924 + }, + { + "icon_id": "7596941", + "name": "24gl-trash2", + "font_class": "24gl-trash2", + "unicode": "eb45", + "unicode_decimal": 60229 + }, + { + "icon_id": "5800277", + "name": "电子制造业", + "font_class": "yunliankeji_gongyinglianfuben", + "unicode": "e618", + "unicode_decimal": 58904 + }, + { + "icon_id": "17619289", + "name": "生产制造", + "font_class": "tubiaozhizuomoban-116", + "unicode": "e633", + "unicode_decimal": 58931 + }, + { + "icon_id": "5652692", + "name": "包装", + "font_class": "baozhuang", + "unicode": "e61b", + "unicode_decimal": 58907 + }, + { + "icon_id": "20531556", + "name": "传送带", + "font_class": "45kejichuangxin-chuansongdai", + "unicode": "e639", + "unicode_decimal": 58937 + }, + { + "icon_id": "162727", + "name": "列表2", + "font_class": "liebiao2", + "unicode": "e605", + "unicode_decimal": 58885 + }, + { + "icon_id": "1028153", + "name": "圆", + "font_class": "yuan", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "icon_id": "1278", + "name": "单图排列", + "font_class": "dantupailie", + "unicode": "e604", + "unicode_decimal": 58884 + }, + { + "icon_id": "5387948", + "name": "全屏_o", + "font_class": "quanping_o", + "unicode": "eb99", + "unicode_decimal": 60313 + }, + { + "icon_id": "8765149", + "name": "皮肤", + "font_class": "pifu1", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "22385724", + "name": "颜色库", + "font_class": "yanseku", + "unicode": "ee22", + "unicode_decimal": 60962 + }, + { + "icon_id": "13638717", + "name": "照明", + "font_class": "zhaoming2", + "unicode": "e65a", + "unicode_decimal": 58970 + }, + { + "icon_id": "629339", + "name": "时间", + "font_class": "shijian", + "unicode": "e64d", + "unicode_decimal": 58957 + }, + { + "icon_id": "5645008", + "name": "取消", + "font_class": "quxiao", + "unicode": "e601", + "unicode_decimal": 58881 + }, + { + "icon_id": "7435512", + "name": "启动", + "font_class": "qidong", + "unicode": "e67d", + "unicode_decimal": 59005 + }, + { + "icon_id": "7594046", + "name": "24gl-pauseCircle", + "font_class": "24gl-pauseCircle", + "unicode": "ea6d", + "unicode_decimal": 60013 + }, + { + "icon_id": "8400546", + "name": "照明", + "font_class": "zhaoming", + "unicode": "e62e", + "unicode_decimal": 58926 + }, + { + "icon_id": "11673858", + "name": "货品类型-01", + "font_class": "huopinleixing-", + "unicode": "e632", + "unicode_decimal": 58930 + }, + { + "icon_id": "20599684", + "name": "复位", + "font_class": "fuwei", + "unicode": "e61f", + "unicode_decimal": 58911 + }, + { + "icon_id": "24008052", + "name": "不合格", + "font_class": "buhege", + "unicode": "e602", + "unicode_decimal": 58882 + }, + { + "icon_id": "24008053", + "name": "合格", + "font_class": "hege", + "unicode": "e603", + "unicode_decimal": 58883 + }, + { + "icon_id": "145486", + "name": "对勾", + "font_class": "duigou", + "unicode": "e65d", + "unicode_decimal": 58973 + }, + { + "icon_id": "2614301", + "name": "机器人", + "font_class": "jiqiren", + "unicode": "e60d", + "unicode_decimal": 58893 + }, + { + "icon_id": "5387814", + "name": "机器人_o", + "font_class": "jiqiren_o", + "unicode": "eb62", + "unicode_decimal": 60258 + }, + { + "icon_id": "376340", + "name": "帮助", + "font_class": "help", + "unicode": "e60b", + "unicode_decimal": 58891 + }, + { + "icon_id": "508243", + "name": "关于", + "font_class": "guanyu", + "unicode": "e608", + "unicode_decimal": 58888 + }, + { + "icon_id": "595407", + "name": "主页", + "font_class": "zhuye1", + "unicode": "e625", + "unicode_decimal": 58917 + }, + { + "icon_id": "4347599", + "name": "icon_使用文档", + "font_class": "icon_shiyongwendang", + "unicode": "eb91", + "unicode_decimal": 60305 + }, + { + "icon_id": "12316649", + "name": "日志管理", + "font_class": "rizhiguanli", + "unicode": "e61d", + "unicode_decimal": 58909 + }, + { + "icon_id": "4933365", + "name": "皮肤", + "font_class": "pifu", + "unicode": "e743", + "unicode_decimal": 59203 + }, + { + "icon_id": "1116004", + "name": "工作", + "font_class": "gongzuo", + "unicode": "e609", + "unicode_decimal": 58889 + }, + { + "icon_id": "4772822", + "name": "工作流—工作流管理", + "font_class": "gongzuoliugongzuoliuguanli", + "unicode": "e64c", + "unicode_decimal": 58956 + }, + { + "icon_id": "5961297", + "name": "查询", + "font_class": "chaxun1", + "unicode": "ec4c", + "unicode_decimal": 60492 + }, + { + "icon_id": "5961310", + "name": "流计算", + "font_class": "liujisuan", + "unicode": "ec56", + "unicode_decimal": 60502 + }, + { + "icon_id": "18169504", + "name": "手,手掌,巴掌", + "font_class": "hand", + "unicode": "e91a", + "unicode_decimal": 59674 + }, + { + "icon_id": "77822", + "name": "更多", + "font_class": "gengduo", + "unicode": "e600", + "unicode_decimal": 58880 + }, + { + "icon_id": "629333", + "name": "设置", + "font_class": "shezhi", + "unicode": "e64b", + "unicode_decimal": 58955 + }, + { + "icon_id": "1010173", + "name": "用户", + "font_class": "yonghu", + "unicode": "e649", + "unicode_decimal": 58953 + }, + { + "icon_id": "3868257", + "name": "调试", + "font_class": "tiaoshi", + "unicode": "eb61", + "unicode_decimal": 60257 + }, + { + "icon_id": "5270862", + "name": "用户群体-业务查询", + "font_class": "yonghu1", + "unicode": "e616", + "unicode_decimal": 58902 + }, + { + "icon_id": "5961328", + "name": "折线图", + "font_class": "zhexiantu", + "unicode": "ec66", + "unicode_decimal": 60518 + }, + { + "icon_id": "17228485", + "name": "查询", + "font_class": "chaxun", + "unicode": "e63b", + "unicode_decimal": 58939 + } + ] +} diff --git a/货架标准上位机/Fonts/demo/iconfont.ttf b/货架标准上位机/Fonts/demo/iconfont.ttf new file mode 100644 index 0000000..9b4651b Binary files /dev/null and b/货架标准上位机/Fonts/demo/iconfont.ttf differ diff --git a/货架标准上位机/Fonts/iconfont.ttf b/货架标准上位机/Fonts/iconfont.ttf new file mode 100644 index 0000000..c07f703 Binary files /dev/null and b/货架标准上位机/Fonts/iconfont.ttf differ diff --git a/货架标准上位机/LocalFile.cs b/货架标准上位机/LocalFile.cs new file mode 100644 index 0000000..a2f1774 --- /dev/null +++ b/货架标准上位机/LocalFile.cs @@ -0,0 +1,105 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 本地文件 + /// + public class LocalFile + { + /// + /// 程序运行名称(货架标准上位机.exe) + /// + public static readonly string AppName = AppDomain.CurrentDomain.FriendlyName.Contains('.') ? AppDomain.CurrentDomain.FriendlyName : $"{AppDomain.CurrentDomain.FriendlyName}.exe";//多环境兼容性 + /// + /// 程序运行目录 + /// + public static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory; + /// + /// 数据目录 + /// + public static readonly string DataDir = Path.Combine(AppDir, "data"); + /// + /// 日志目录 + /// + public static readonly string LogDir = Path.Combine(AppDir, "logs"); + + /// + /// 运行主程序 + /// + public static readonly string AppPath = Path.Combine(AppDir, AppName); + /// + /// 配置文件路径 + /// + public static readonly string ConfigPath = Path.Combine(DataDir, "jsconfig.json"); + /// + /// 设备手动点位文档路径 + /// + public static readonly string PlcDotPath = Path.Combine(DataDir, "设备手动点位.xlsx"); + /// + /// 帮助文档路径 + /// + public static readonly string DocPath = Path.Combine(DataDir, "操作说明书.docx"); + + static object lockConfig = new object(); + static JsConfig config; + /// + /// 配置信息 + /// + public static JsConfig Config + { + get + { + if (config != null) + return config; + else + { + try + { + UpdateConfig(); + } + catch (Exception) + { + config = null; + } + } + return config ?? new JsConfig(); + } + } + + /// + /// 刷新配置信息。将本地的配置信息重新加载到内存中 + /// + public static void UpdateConfig() + { + if (File.Exists(ConfigPath)) + lock (lockConfig) + config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigPath, Encoding.UTF8)); + else + config = null; + } + + /// + /// 保存配置信息。将内存中的配置信息保存到本地 + /// + public static void SaveConfig() + { + try + { + lock (lockConfig) + File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(Config, Formatting.Indented), Encoding.UTF8); + } + catch (Exception ex) + { + UpdateConfig(); + throw ex; + } + } + } +} diff --git a/货架标准上位机/LocalStatic.cs b/货架标准上位机/LocalStatic.cs new file mode 100644 index 0000000..d511f71 --- /dev/null +++ b/货架标准上位机/LocalStatic.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 本地全局静态 + /// + public static class LocalStatic + { + /// + /// 前端当前登录的用户名 + /// + public static string CurrentUser { get; set; } = "未登录"; + } +} diff --git a/货架标准上位机/Models/AuthEnum.cs b/货架标准上位机/Models/AuthEnum.cs new file mode 100644 index 0000000..52093c0 --- /dev/null +++ b/货架标准上位机/Models/AuthEnum.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 认证项 + /// + public enum AuthEnum + { + 查询 = 1000, + 权限 = 2000, + 设置 = 3000, + 调试 = 4000, + } + + public class EnumTreeAttribute : Attribute + { + public EnumTreeAttribute() { } + + public EnumTreeAttribute(AuthEnum parent) + { + Parent = parent; + } + + public EnumTreeAttribute(AuthEnum[] childs) + { + Childs = childs; + } + + public EnumTreeAttribute(AuthEnum parent, AuthEnum[] childs) + { + Parent = parent; + Childs = childs; + } + + /// + /// 父级 + /// + public AuthEnum? Parent { get; set; } = null; + /// + /// 子级 + /// + public AuthEnum[]? Childs { get; set; } = null; + } +} diff --git a/货架标准上位机/Models/CrudEnum.cs b/货架标准上位机/Models/CrudEnum.cs new file mode 100644 index 0000000..dd3fe1b --- /dev/null +++ b/货架标准上位机/Models/CrudEnum.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 增删改查(CRUD)枚举 + /// + public enum CrudEnum + { + Create, Read, Update, Delete + } +} diff --git a/货架标准上位机/Models/ExcelDevice.cs b/货架标准上位机/Models/ExcelDevice.cs new file mode 100644 index 0000000..36d2244 --- /dev/null +++ b/货架标准上位机/Models/ExcelDevice.cs @@ -0,0 +1,213 @@ +using 货架标准上位机.ViewModel; +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 设备监控 + /// + public class ExcelDeviceReadModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 类型 { get; set; } + public string 地址 { get; set; } + public string 单位 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备监控") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceReadModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备控制 + /// + public class ExcelDeviceWriteModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 类型 { get; set; } + public string 读地址 { get; set; } + public string 写地址 { get; set; } + public string 点动切换 { get; set; } + public string 单位 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备控制") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceWriteModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备气缸 + /// + public class ExcelDeviceUrnModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 推地址 { get; set; } + public string 回地址 { get; set; } + public string 推到位地址 { get; set; } + public string 回到位地址 { get; set; } + public string 点动切换 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备气缸") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceUrnModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备伺服 + /// + public class ExcelDeviceServoModel + { + public string 名称 { get; set; } + public string 组名 { get; set; } + public string 手动速度获取 { get; set; } + public string 手动速度设置 { get; set; } + public string 自动速度获取 { get; set; } + public string 自动速度设置 { get; set; } + public string 当前位置获取 { get; set; } + public string 位置点动加 { get; set; } + public string 位置点动减 { get; set; } + public string 位置移动 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备伺服") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName) + .Where(o => !string.IsNullOrWhiteSpace(o.名称)) + .Select(o => new DeviceServoModel() + { + Name = o.名称, + ExcelTag = o, + }).ToList(); + } + } + + /// + /// 设备报警 + /// + public class ExcelDeviceAlarmModel + { + public string 名称 { get; set; } + public string 地址 { get; set; } + public string 类型 { get; set; } + public string 触发 { get; set; } + public string 级别 { get; set; } + public string 解决方式 { get; set; } + + public static List GetDatas(string excelPath = null, string sheetName = "设备报警") + { + if (string.IsNullOrEmpty(excelPath)) + excelPath = LocalFile.PlcDotPath; + + return MiniExcelLibs.MiniExcel.Query(excelPath, sheetName).Where(o => !string.IsNullOrWhiteSpace(o.名称)).ToList(); + } + + /// + /// 是否触发警报 + /// + public bool IsOnAlarm(object? val) + { + try + { + if (val == null) + return false; + + string vs = val.ToString().ToLower(); + if (类型.Trim().ToLower().Contains("bool")) + { + if (vs == 触发.Trim().ToLower()) + return true; + else + return false; + } + else if (类型.Trim().ToLower().Contains("int")) + { + if (string.IsNullOrWhiteSpace(触发)) + return false; + if (!触发.Contains(vs)) + return false; + + foreach (var item in 触发.Split(';')) + { + var kv = item.Split(':'); + if (kv.Length != 2) + continue; + + if (kv[0] == vs) + return true; + } + } + return false; + } + catch (Exception) + { + return false; + } + } + } + + public class IotDevice + { + public static Action UserChange; + + /// + /// 控件名称 + /// + public string Name { get; set; } + /// + /// 控件类型 + /// + public string Type { get; set; } + /// + /// 控件值 + /// + public object Val { get; set; } + /// + /// 功能 + /// + public string Funct { get; set; } + /// + /// 操作方式(点动、切换) + /// + public string Mode { get; set; } + } +} diff --git a/货架标准上位机/Models/ITreeNode.cs b/货架标准上位机/Models/ITreeNode.cs new file mode 100644 index 0000000..1b5626a --- /dev/null +++ b/货架标准上位机/Models/ITreeNode.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 树节点 + /// + public interface ITreeNode + { + /// + /// 主键Id + /// + public object Id { get; set; } + /// + /// 父Id + /// + public object Pid { get; set; } + /// + /// 子节点 + /// + public List Children { get; set; } + } + + /// + /// 树节点扩展 + /// + public static class TreeNodeEx + { + /// + /// 转为树结构 + /// + /// 树节点 + /// 树节点带子节点(Children) + public static List ToTree(this List treeNodes) where T : ITreeNode + { + if (treeNodes == null || !treeNodes.Any()) + return treeNodes ?? new List(); + if (treeNodes.Any(o => o.Id == o.Pid)) + throw new Exception("存在id和pid相同的数据,无限循环引用"); + + var group = treeNodes.GroupBy(x => x.Pid).ToDictionary(x => x.Key, s => s.ToList()); + + foreach (var item in treeNodes) + { + if (group.ContainsKey(item.Id)) + { + var treeNode = group[item.Id]; + if (treeNode.Any(o => o.Id == item.Pid && o.Pid == item.Id)) + throw new Exception("存在id和pid交叉引用(如:{Id='我是你',Pid='你是我'} 和 {Id='你是我',Pid='我是你'})"); + + if (item.Children == null) + item.Children = new List(); + + item.Children.AddRange(treeNode); + } + } + + //查找顶级节点 + var ids = treeNodes.Select(o => o.Id).Distinct(); + var pids = treeNodes.Select(o => o.Pid).Distinct(); + var c = pids.Except(ids); + return group.Where(o => c.Contains(o.Key)).SelectMany(o => o.Value).ToList(); + } + + /// + /// 将指定的id节点转为树结构 + /// + /// 树节点 + /// id节点 + /// 树节点带子节点(Children) + public static T? ToTree(this List treeNodes, object id) where T : ITreeNode + { + if (treeNodes == null || !treeNodes.Any()) + return default(T); + if (treeNodes.Any(o => o.Id == o.Pid)) + throw new Exception("存在id和pid相同的数据,无限循环引用"); + + var group = treeNodes.GroupBy(x => x.Pid).ToDictionary(x => x.Key, s => s.ToList()); + + foreach (var item in treeNodes) + { + if (group.ContainsKey(item.Id)) + { + var treeNode = group[item.Id]; + if (treeNode.Any(o => o.Id == item.Pid && o.Pid == item.Id)) + throw new Exception("存在id和pid交叉引用(如:{Id='我是你',Pid='你是我'} 和 {Id='你是我',Pid='我是你'})"); + + if (item.Children == null) + item.Children = new List(); + + item.Children.AddRange(treeNode); + } + } + + return treeNodes.FirstOrDefault(o => o.Id == id); + } + + /// + /// 转为树节点 + /// + /// 树节点 + /// 树节点带子节点(Children) + public static List ToTreeNode(this List treeNodes) where T : ITreeNode + { + if (treeNodes == null || !treeNodes.Any()) + return treeNodes ?? new List(); + + List trees = new List(); + foreach (var item in treeNodes) + { + trees.Add(item); + + if (item.Children != null && item.Children.Any()) + { + var aaa = ToTreeNode(item.Children); + trees.AddRange(aaa); + } + } + return trees; + } + } +} diff --git a/货架标准上位机/Models/IpPort.cs b/货架标准上位机/Models/IpPort.cs new file mode 100644 index 0000000..e3b6b3a --- /dev/null +++ b/货架标准上位机/Models/IpPort.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// Ip和端口 + /// + public class IpPort + { + /// + /// Ip地址 + /// + public string Address { get; set; } + /// + /// 端口 + /// + public int Port { get; set; } + + [Newtonsoft.Json.JsonIgnore] + public IPEndPoint IPEndPoint { get => new IPEndPoint(IPAddress.Parse(Address), Port); } + + public override string ToString() + { + return Port <= 0 ? Address : $"{Address}:{Port}"; + } + } + + /// + /// Ip和端口扩展 + /// + public static class IpPortEx + { + /// + /// 将字符串转为Ip和端口 + /// + /// Ip和端口字符串 + /// Ip和端口 + public static IpPort ToIpPort(this string IpPortStr) + { + IpPortStr = IpPortStr?.Trim() ?? ""; + + if (string.IsNullOrEmpty(IpPortStr)) + return new IpPort(); + + var aaa = IpPortStr.Split(new char[] { ':', ':' }, StringSplitOptions.RemoveEmptyEntries); + if (!aaa.Any()) + return new IpPort(); + else if (aaa.Length == 2) + return new IpPort() { Address = aaa[0], Port = Convert.ToInt32(aaa[1]) }; + else if (aaa.Length == 1) + if (aaa[0].Contains(".")) + return new IpPort() { Address = aaa[0] }; + else + return new IpPort() { Address = "", Port = Convert.ToInt32(aaa[0]) }; + else + return new IpPort(); + } + } +} diff --git a/货架标准上位机/Models/JsConfig.cs b/货架标准上位机/Models/JsConfig.cs new file mode 100644 index 0000000..ace3ee6 --- /dev/null +++ b/货架标准上位机/Models/JsConfig.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// json配置文件 + /// + public class JsConfig + { + /// + /// mysql链接字符串 + /// + public string MySql { get; set; } + /// + /// 货架服务器的Ip和端口号 + /// + public string ApiIpHost { get; set; } + + public List GroupName { get; set; } + + public string DeviceType { get; set; } + /// + /// 系统配置 + /// + public JsSysConfig Sys { get; set; } + + /// + /// 货架类的是否软件启动后自检 + /// + public bool IsBootSelfTest { get; set; } + + /// + /// 扫码枪Com口列表 + /// + public List ScannerComList { get; set; } + /// + /// 串口扫码枪延时 + /// + public int ScannerTimeOut { get; set; } + } + + public class JsSysConfig + { + /// + /// 是否保存登录历史 + /// + public bool IsSaveLogin { get; set; } + /// + /// 登录历史 + /// + public List SaveLogin { get; set; } + /// + /// 登录历史数量 + /// + public int SaveLoginCount { get; set; } + /// + /// 开机启动 + /// + public bool Powerboot { get; set; } + /// + /// 启动全屏 + /// + public bool StartupFull { get; set; } + /// + /// 日志保存天数 + /// + public int SaveLogDay { get; set; } + } + +} diff --git a/货架标准上位机/Properties/AssemblyInfo.cs b/货架标准上位机/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4be06ef --- /dev/null +++ b/货架标准上位机/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //ضԴʵλ + //(δҳҵԴʱʹã + //ӦóԴֵҵʱʹ) + ResourceDictionaryLocation.SourceAssembly //Դʵλ + //(δҳҵԴʱʹã + //ӦóκרԴֵҵʱʹ) +)] diff --git a/货架标准上位机/Resources/Logo.ico b/货架标准上位机/Resources/Logo.ico new file mode 100644 index 0000000..95cadfa Binary files /dev/null and b/货架标准上位机/Resources/Logo.ico differ diff --git a/货架标准上位机/Resources/Logo.png b/货架标准上位机/Resources/Logo.png new file mode 100644 index 0000000..9e62c7c Binary files /dev/null and b/货架标准上位机/Resources/Logo.png differ diff --git a/货架标准上位机/Resources/LogoAll.zip b/货架标准上位机/Resources/LogoAll.zip new file mode 100644 index 0000000..331d155 Binary files /dev/null and b/货架标准上位机/Resources/LogoAll.zip differ diff --git a/货架标准上位机/Resources/cloud.png b/货架标准上位机/Resources/cloud.png new file mode 100644 index 0000000..f8b36fb Binary files /dev/null and b/货架标准上位机/Resources/cloud.png differ diff --git a/货架标准上位机/Resources/主页.png b/货架标准上位机/Resources/主页.png new file mode 100644 index 0000000..e5b75de Binary files /dev/null and b/货架标准上位机/Resources/主页.png differ diff --git a/货架标准上位机/Resources/数据.png b/货架标准上位机/Resources/数据.png new file mode 100644 index 0000000..68fc991 Binary files /dev/null and b/货架标准上位机/Resources/数据.png differ diff --git a/货架标准上位机/Resources/权限.png b/货架标准上位机/Resources/权限.png new file mode 100644 index 0000000..723e7fa Binary files /dev/null and b/货架标准上位机/Resources/权限.png differ diff --git a/货架标准上位机/Resources/模式.png b/货架标准上位机/Resources/模式.png new file mode 100644 index 0000000..27b51ce Binary files /dev/null and b/货架标准上位机/Resources/模式.png differ diff --git a/货架标准上位机/Resources/物料条码.btw b/货架标准上位机/Resources/物料条码.btw new file mode 100644 index 0000000..0e5676f Binary files /dev/null and b/货架标准上位机/Resources/物料条码.btw differ diff --git a/货架标准上位机/Resources/设置.png b/货架标准上位机/Resources/设置.png new file mode 100644 index 0000000..3e87d66 Binary files /dev/null and b/货架标准上位机/Resources/设置.png differ diff --git a/货架标准上位机/ScannerManager.cs b/货架标准上位机/ScannerManager.cs new file mode 100644 index 0000000..37d712e --- /dev/null +++ b/货架标准上位机/ScannerManager.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.SerialPorts; +using TouchSocket.Sockets; +using 货架标准上位机.Views.Controls; + +namespace 货架标准上位机 +{ + public static class ScannerManager + { + public static List Scanners = new List(); + public static void InitScanners() + { + + //获取当前配置文件的串口号 + var ScannerComList = LocalFile.Config.ScannerComList; + //通过配置的串口号生成对象 + ScannerComList.ForEach(COM => + { + try + { + var client = new SerialPortClient(); + //成功连接到端口 + client.Connected = (client, e) => + { + Logs.Write($"扫码枪{client.MainSerialPort.PortName},已成功连接!", LogsType.Scanner); + //初始化扫码枪对象 + var Scanner = new Scanner() + { + SerialPortClient = (SerialPortClient)client, + //ScannerDisplayControl = new ScannerDisplayControl(client.MainSerialPort.PortName), + COM = client.MainSerialPort.PortName, + TempCode = string.Empty, + }; + Scanners.Add(Scanner); + return EasyTask.CompletedTask; + }; + client.Received = async (c, e) => + { + ; + }; + client.Setup(new TouchSocket.Core.TouchSocketConfig() + .SetSerialPortOption(new SerialPortOption() + { + BaudRate = 9600,//波特率 + DataBits = 8,//数据位 + Parity = System.IO.Ports.Parity.None,//校验位 + PortName = COM, + StopBits = System.IO.Ports.StopBits.One//停止位 + })); + + client.Connect(LocalFile.Config.ScannerTimeOut, new CancellationToken()); + } + catch (Exception ex) + { + Logs.Write($"初始化扫码枪异常!{ex.Message}", LogsType.Scanner); + } + }); + + } + } + + public class Scanner() + { + public SerialPortClient SerialPortClient { get; set; } + + public ScannerDisplayControl ScannerDisplayControl { get; set; } + + /// + /// 是否在入库模式中 + /// + public bool IsInstoreMode { get; set; } + /// + /// 串口号 + /// + public string COM { get; set; } + /// + /// 暂存的码 + /// + public string TempCode { get; set; } = string.Empty; + + public string ShelfCode { get; set; } = string.Empty; + + public string ModulesStr { get; set; } = string.Empty; + + public string MatSn { get; set; } = string.Empty; + } +} diff --git a/货架标准上位机/Tool/Folder.cs b/货架标准上位机/Tool/Folder.cs new file mode 100644 index 0000000..303305d --- /dev/null +++ b/货架标准上位机/Tool/Folder.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 文件夹操作 + /// + public static class Folder + { + /// + /// 打开目录 + /// + /// 目录路径(比如:C:\Users\Administrator\) + public static void OpenFolder(string folderPath) + { + if (string.IsNullOrEmpty(folderPath)) + return; + + Process process = new Process(); + ProcessStartInfo psi = new ProcessStartInfo("Explorer.exe"); + psi.Arguments = folderPath; + process.StartInfo = psi; + + try + { + process.Start(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + process?.Close(); + + } + } + + /// + /// 打开目录且选中文件 + /// + /// 文件的路径和名称(比如:C:\Users\Administrator\test.txt) + public static void OpenFolderAndSelectedFile(string filePathAndName) + { + if (string.IsNullOrEmpty(filePathAndName)) + return; + + Process process = new Process(); + ProcessStartInfo psi = new ProcessStartInfo("Explorer.exe"); + psi.Arguments = "/e,/select," + filePathAndName; + process.StartInfo = psi; + + //process.StartInfo.UseShellExecute = true; + try + { + process.Start(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + process?.Close(); + } + } + } +} diff --git a/货架标准上位机/Tool/GetBaseData.cs b/货架标准上位机/Tool/GetBaseData.cs new file mode 100644 index 0000000..2f5b7ab --- /dev/null +++ b/货架标准上位机/Tool/GetBaseData.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Documents; +using WCS.Model; +using WCS.Model.ApiModel.Home; +using 货架标准上位机.Api; + +namespace 货架标准上位机.Tool +{ + public static class GetBaseData + { + public static List GetShelfType() + { + var body = new RequestBase() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + }; + + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "home/getShelfTypes", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists.Count() > 0) + { + return Result.Data.Lists; + } + else { return new List(); } + } + } +} diff --git a/货架标准上位机/Tool/JsonConverter.cs b/货架标准上位机/Tool/JsonConverter.cs new file mode 100644 index 0000000..b38d3eb --- /dev/null +++ b/货架标准上位机/Tool/JsonConverter.cs @@ -0,0 +1,38 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// json时间转换器 + /// + public class JsonDateTimeConverter : JsonConverter + { + public override DateTime? ReadJson(JsonReader reader, Type objectType, DateTime? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var dateTimeString = reader.Value?.ToString(); + if (!string.IsNullOrEmpty(dateTimeString)) + { + try + { + return DateTime.ParseExact(dateTimeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + } + catch (FormatException) + { + throw new JsonSerializationException("Invalid date time format."); + } + } + return null; + } + + public override void WriteJson(JsonWriter writer, DateTime? value, JsonSerializer serializer) + { + writer.WriteValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } + } +} diff --git a/货架标准上位机/Tool/Logs.cs b/货架标准上位机/Tool/Logs.cs new file mode 100644 index 0000000..d9f23b1 --- /dev/null +++ b/货架标准上位机/Tool/Logs.cs @@ -0,0 +1,164 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 日志类型 + /// + public enum LogsType + { + /// + /// 信息 + /// + Info, + /// + /// 警告 + /// + Warning, + /// + /// 错误 + /// + Err, + /// + /// 数据库错误 + /// + DbErr, + /// + /// 扫码枪 + /// + Scanner + } + + /// + /// 日志 + /// + public static class Logs + { + static object obj = new object(); + const string logExtension = ".log"; + /// + /// 写入日志失败 + /// + public static Action, DateTime, LogsType, Exception> WriteErr = null; + + /// + /// 写入日志 + /// + /// 内容 + /// 类型 + /// 是否写入成功 + public static void Write(IEnumerable content, LogsType type = LogsType.Info, DateTime? dt = null) + { + if (content == null || !content.Any()) + return; + + dt ??= DateTime.Now; + string hms = dt.Value.ToString("HH:mm:ss.fff"); + List lines = new List(content.Count()); + + try + { + string path = Path.Combine(LocalFile.LogDir, type.ToString(), $"{(dt.Value.ToString("yyyyMMdd"))}{logExtension}"); + foreach (var item in content) + lines.AddRange($"[{hms}]{item}".Split(new string[] { Environment.NewLine }, StringSplitOptions.None)); + + lock (obj) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.AppendAllLines(path, lines, Encoding.UTF8); + } + } + catch (Exception ex) + { + WriteErr?.Invoke(content, dt.Value, type, ex); + } + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(string content, LogsType type = LogsType.Info, DateTime? dt = null) + { + Write(new string[] { content }, type, dt); + } + + /// + /// 写入日志 + /// + /// 内容对象 + /// 类型 + /// 是否写入成功 + public static void Write(object content, LogsType type = LogsType.Info, DateTime? dt = null) + { + Write(JsonConvert.SerializeObject(content), type, dt); + } + + /// + /// 写入日志 + /// + /// 内容 + /// 内容标题 + /// 类型 + /// 是否写入成功 + public static void Write(object content, string contentTitle, LogsType type = LogsType.Info, DateTime? dt = null) + { + Write($"{contentTitle} {JsonConvert.SerializeObject(content)}", type, dt); + } + + /// + /// 写入日志 + /// + /// 错误 + /// 是否写入成功 + public static void Write(Exception ex, LogsType type = LogsType.Err, DateTime? dt = null) + { + Write(ex.ToString(), type, dt); + } + + /// + /// 清除日志 + /// + /// 保留时间 + /// 清理的大小(字节) + public static long Clear(TimeSpan time) + { + long size = 0; + var rs = EnumHelps.GetEnumList(typeof(LogsType)); + foreach (var item in rs) + { + try + { + var path = Path.Combine(LocalFile.LogDir, item); + DirectoryInfo directoryInfo = new DirectoryInfo(path); + if (!directoryInfo.Exists) + continue; + + var files = directoryInfo.GetFiles($"**{logExtension}", SearchOption.TopDirectoryOnly); + var fileDel = files.Where(o => o.CreationTime < (DateTime.Now - time)); + foreach (var item2 in fileDel) + { + size += item2.Length; + item2.Delete(); + } + } + catch (Exception) + { + + } + } + return size; + } + } +} \ No newline at end of file diff --git a/货架标准上位机/Tool/PrintTender.cs b/货架标准上位机/Tool/PrintTender.cs new file mode 100644 index 0000000..07b65f1 --- /dev/null +++ b/货架标准上位机/Tool/PrintTender.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace 货架标准上位机.Tool +{ + public static class PrintTender + { + public static BarTender.Application Inbtapp; + static BarTender.Format InbtFormat; + + //TO DO 打印机型号需要可配置 + static string PKNmae = "TSC TTP-244 Pro"; + + static object lockll = new object(); + static object lockPrint = new object(); + + //记录日志 + public static void WriteOneLine(string msg)//写到本地记录 + { + lock (lockPrint) + { + try + { + Logs.Write($"{msg}"); + } + catch (Exception ex) + { + ; + } + } + } + + /// + /// 打印外箱条码 + /// PKGip 打印机地址 + /// PKNmae 打印机名字 + /// + /// + /// + public static bool PrintTag(PrintClass printtext) + { + lock (lockll) + { + try + { + if (Inbtapp == null) + { + Inbtapp = new BarTender.Application(); + } + WriteOneLine($"标签开始打印"); + InbtFormat = Inbtapp.Formats.Open(System.Environment.CurrentDirectory + "\\Resources\\物料条码.btw", false, ""); + InbtFormat.PrintSetup.Printer = PKNmae; + InbtFormat.PrintSetup.IdenticalCopiesOfLabel = 1; //设置同序列打印的份数 + InbtFormat.SetNamedSubStringValue("MatCode", printtext.MatCode); + InbtFormat.SetNamedSubStringValue("MatName", printtext.MatName); + InbtFormat.SetNamedSubStringValue("MatBatch", "批次:" + printtext.MatBatch); + InbtFormat.SetNamedSubStringValue("MatQty", "数量:" + printtext.MatQty); + InbtFormat.SetNamedSubStringValue("MatSn", printtext.MatSn); + InbtFormat.SetNamedSubStringValue("MatSpec", "规格:" + printtext.MatSpec); + InbtFormat.SetNamedSubStringValue("DateTime", DateTime.Now.ToString()); + + Thread.Sleep(20); + int result = InbtFormat.PrintOut(true, false); //第二个false设置打印时是否跳出打印属性 + InbtFormat.Close(BarTender.BtSaveOptions.btSaveChanges); //退出时是否保存标签 + DateTime datenow = DateTime.Now; + Thread.Sleep(200); + return true; + } + catch (Exception ex) + { + WriteOneLine("打标签失败" + ex.ToString()); + return false; + } + } + } + + } + + public class PrintClass + { + public string MatQty { get; set; } + public string MatBatch { get; set; } + public string MatCode { get; set; } + public string MatName { get; set; } + public string MatSn { get; set; } + public string MatSpec { get; set; } + } + +} diff --git a/货架标准上位机/Tool/RichTextBoxTool.cs b/货架标准上位机/Tool/RichTextBoxTool.cs new file mode 100644 index 0000000..fb153b1 --- /dev/null +++ b/货架标准上位机/Tool/RichTextBoxTool.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace 货架标准上位机 +{ + /// + /// 富文本框扩展类 + /// + public static class RichTextBoxTool + { + /// + /// 清空内容 + /// + public static void ClearText(this RichTextBox richTextBox) + { + try + { + richTextBox.Dispatcher.Invoke((Action)delegate + { + //清空文本 + richTextBox.Document.Blocks.Clear(); + //滚动到开头 + richTextBox.ScrollToVerticalOffset(0); + }); + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// 插入文本 + /// + /// + /// 颜色 + /// 内容 + private static void AppendText(this RichTextBox richTextBox, Brush brush, string txt) + { + try + { + richTextBox.Dispatcher.Invoke((Action)delegate + { + var p = new Paragraph(); //Paragraph 类似于 html 的 P 标签 + var r = new Run(txt); //Run 是一个 Inline 的标签 + p.Inlines.Add(r); + p.LineHeight = 8; + p.Foreground = brush;//设置字体颜色 + richTextBox.Document.Blocks.Add(p); + if (richTextBox.Document.Blocks.Count > 1000) + { + richTextBox.Document.Blocks.Remove(richTextBox.Document.Blocks.FirstBlock); + } + //滚动到末尾 + richTextBox.ScrollToVerticalOffset(richTextBox.Document.Blocks.Count * 200); + }); + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// 插入Title(棕色),为:######Title###### + /// + public static void AppendTile(this RichTextBox richTextBox, string txt) + { + AppendText(richTextBox, Brushes.Brown, "#####" + txt + "#####"); + } + + /// + /// 插入信息(蓝色) + /// + /// 是否在开头追加时间信息,如:HH:mm:ss.fff=>txt + public static void AppendInfo(this RichTextBox richTextBox, string txt, bool addTime = false) + { + if (string.IsNullOrEmpty(txt)) + return; + + if (addTime) + AppendText(richTextBox, Brushes.Blue, $"{DateTime.Now.ToString("HH:mm:ss.fff")}=>{txt.Replace("\r", "\\r").Replace("\n", "\\n")}"); + else + AppendText(richTextBox, Brushes.Blue, txt.Replace("\r", "\\r").Replace("\n", "\\n")); + } + + /// + /// 插入信息(深绿色) + /// + /// 是否在开头追加时间信息,如:HH:mm:ss.fff=>txt + public static void AppendResult(this RichTextBox richTextBox, string txt, bool addTime = false) + { + if (string.IsNullOrEmpty(txt)) + return; + + if (addTime) + AppendText(richTextBox, Brushes.Blue, $"{DateTime.Now.ToString("HH:mm:ss.fff")}=>{txt}"); + else + AppendText(richTextBox, Brushes.ForestGreen, txt); + } + + /// + /// 插入错误(鲜红色) + /// + /// 是否在开头追加时间信息,如:HH:mm:ss.fff=>txt + public static void AppendErr(this RichTextBox richTextBox, string txt, bool addTime = false) + { + if (string.IsNullOrEmpty(txt)) + return; + + if (addTime) + AppendText(richTextBox, Brushes.Blue, $"{DateTime.Now.ToString("HH:mm:ss.fff")}=>{txt}"); + else + AppendText(richTextBox, Brushes.Tomato, txt); + } + } + +} diff --git a/货架标准上位机/Tool/WarnInfoContainer.cs b/货架标准上位机/Tool/WarnInfoContainer.cs new file mode 100644 index 0000000..f9a8021 --- /dev/null +++ b/货架标准上位机/Tool/WarnInfoContainer.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 警告信息容器 + /// + public class WarnInfoContainer + { + ConcurrentDictionary InfoAll = new ConcurrentDictionary(); + + /// + /// 有新的日志加入或移除时,1,当前全部,2,加入的,3移除的 + /// + public Action, IEnumerable, IEnumerable> WarnInfoChanged; + + /// + /// 添加或者更新信息 + /// + public void AddOrUpdate(IEnumerable warnInfos) + { + if (warnInfos == null || !warnInfos.Any()) + return; + + List adds = new List(); + List cles = new List(); + var info1 = warnInfos.Where(o => o.WarnType == WarnInfoType.WhileWarn).GroupBy(o => o.Source); + var info2 = warnInfos.Where(o => o.WarnType == WarnInfoType.AlwayWarn); + DateTime dt = DateTime.Now; + + foreach (var addText in info1) + { + var yuan = InfoAll.Keys.Where(o => o.WarnType == WarnInfoType.WhileWarn && o.Source == addText.Key); + var uni = yuan.Intersect(addText); + var add = addText.Except(yuan).Except(uni); + var cle = yuan.Except(addText).Except(uni); + adds.AddRange(add); + cles.AddRange(cle); + + foreach (var item in cle) + { + item.TimeTo = item.TimeTo.HasValue ? item.TimeTo : dt; + if (!InfoAll.TryRemove(item, out string val)) + InfoAll.TryRemove(item, out string val1); + } + foreach (var item in add) + { + item.Id = Guid.NewGuid().ToString("N"); + item.TimeGo = item.TimeGo == new DateTime() ? dt : item.TimeGo; + if (!InfoAll.TryAdd(item, null)) + InfoAll.TryAdd(item, null); + } + } + + { + var exc = info2.Except(InfoAll.Keys); + foreach (var item in exc) + { + item.Id = Guid.NewGuid().ToString("N"); + item.TimeGo = item.TimeGo == new DateTime() ? dt : item.TimeGo; + if (!InfoAll.TryAdd(item, null)) + InfoAll.TryAdd(item, null); + adds.Add(item); + } + } + + if (adds.Any() || cles.Any()) + WarnInfoChanged?.BeginInvoke(InfoAll.Keys.ToArray(), adds, cles, null, null); + } + + /// + /// 更新循环警告 + /// + public void UpdateWhileWarn(IEnumerable texts) + { + UpdateWhileWarn(string.Empty, texts); + } + + /// + /// 更新循环警告 + /// + public void UpdateWhileWarn(string source, IEnumerable texts) + { + DateTime dt = DateTime.Now; + AddOrUpdate(texts.Select(o => new WarnInfoItem() + { + Source = source, + Text = o, + WarnType = WarnInfoType.WhileWarn, + TimeGo = dt, + TimeTo = null + })); + } + + /// + /// 添加常驻警告 + /// + public void AddAlwayWarn(string text) + { + AddAlwayWarn(string.Empty, new string[] { text }); + } + + /// + /// 添加常驻警告 + /// + public void AddAlwayWarn(IEnumerable texts) + { + AddAlwayWarn(string.Empty, texts); + } + + /// + /// 添加常驻警告 + /// > + public void AddAlwayWarn(string source, string text) + { + AddAlwayWarn(source, new string[] { text }); + } + + /// + /// 添加常驻警告 + /// > + public void AddAlwayWarn(string source, IEnumerable texts) + { + DateTime dt = DateTime.Now; + AddOrUpdate(texts.Select(o => new WarnInfoItem() + { + Source = source, + Text = o, + WarnType = WarnInfoType.AlwayWarn, + TimeGo = dt, + TimeTo = null + })); + } + + /// + /// 移除警告信息 + /// + public void RemoveAll() + { + RemoveAll(null); + } + + /// + /// 移除警告信息 + /// + public void RemoveAll(WarnInfoType errType) + { + RemoveAll(null, errType); + } + + /// + /// 移除警告信息 + /// + public void RemoveAll(string source, WarnInfoType? errType = null) + { + if (InfoAll.IsEmpty) + return; + + var clear = InfoAll.Keys + .Where(o => (source == null ? true : o.Source == source) && (errType.HasValue ? o.WarnType == errType.Value : true)); + + if (clear == null || !clear.Any()) + return; + + var dt = DateTime.Now; + foreach (var item in clear) + { + item.TimeTo = item.TimeTo.HasValue ? item.TimeTo : dt; + if (!InfoAll.TryRemove(item, out string val)) + InfoAll.TryRemove(item, out string val1); + } + + WarnInfoChanged?.BeginInvoke(InfoAll.Keys, new List(), clear, null, null); + } + } + + /// + /// 警告信息 + /// + public class WarnInfoItem + { + /// + /// 唯一编码 + /// + public string Id { get; set; } + /// + /// 来源 + /// + public string Source { get; set; } + /// + /// 文本信息 + /// + public string Text { get; set; } + /// + /// 级别(提示、警告、错误、致命) + /// + public string Level { get; set; } + /// + /// 解决方案 + /// + public string Solution { get; set; } + /// + /// 警告类型 + /// + public WarnInfoType WarnType { get; set; } + /// + /// 开始时间 + /// + public DateTime TimeGo { get; set; } + /// + /// 结束时间 + /// + public DateTime? TimeTo { get; set; } + /// + /// 自定义信息 + /// + public object Tag { get; set; } + + public override bool Equals(object obj) + { + if (obj is WarnInfoItem b) + return (Source == b.Source && Text == b.Text && Level == b.Level && Solution == b.Solution && WarnType == b.WarnType); + else + return false; + } + + public override int GetHashCode() + { + return (Source + Text + Level + Solution + WarnType.ToString()).GetHashCode(); + } + + public override string ToString() + { + return $"{(string.IsNullOrEmpty(Source) ? "" : $"[{Source}]")}{(string.IsNullOrEmpty(Level) ? "" : $"[{Level}]")}{Text}{(string.IsNullOrEmpty(Solution) ? "" : $"({Solution})")}{(TimeTo.HasValue ? $"({(TimeTo.Value - TimeGo).TotalSeconds.ToString("0.00")}s)" : "")}"; + } + + public static bool operator ==(WarnInfoItem a, WarnInfoItem b) + { + return a.Equals(b); + } + + public static bool operator !=(WarnInfoItem a, WarnInfoItem b) + { + return !a.Equals(b); + } + } + + /// + /// 警告信息类型 + /// + public enum WarnInfoType + { + /// + /// 常驻错误。加入一次需要手动清除 + /// + AlwayWarn = 10, + /// + /// 循环错误。每次需要把全部的错误参入进来 + /// + WhileWarn = 20, + } +} diff --git a/货架标准上位机/Tool/While.cs b/货架标准上位机/Tool/While.cs new file mode 100644 index 0000000..3172d2c --- /dev/null +++ b/货架标准上位机/Tool/While.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace 货架标准上位机 +{ + /// + /// 循环、暂停、继续、停止扩展 + /// + public static class While + { + /// + /// 带条件等待并检测停止、暂停 + /// + /// 不停的执行的任务,返回为true就跳出循环 + public static async Task Wait(Func func, CancellationToken token = default, ManualResetEvent manualReset = default) + { + while (true) + { + token.ThrowIfCancellationRequested(); + manualReset?.WaitOne(); + token.ThrowIfCancellationRequested(); + + if (func.Invoke()) + break; + + await Task.Delay(200, token); + } + } + + /// + /// 等待并检测停止、暂停 + /// + public static void Wait(CancellationToken token = default, ManualResetEvent manualReset = default) + { + token.ThrowIfCancellationRequested(); + manualReset?.WaitOne(); + token.ThrowIfCancellationRequested(); + } + } +} diff --git a/货架标准上位机/ViewModels/AboutViewModel.cs b/货架标准上位机/ViewModels/AboutViewModel.cs new file mode 100644 index 0000000..fdd6d17 --- /dev/null +++ b/货架标准上位机/ViewModels/AboutViewModel.cs @@ -0,0 +1,34 @@ +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机.ViewModel +{ + public class AboutViewModel : BindableBase + { + public AboutViewModel() + { + var versionInfo = FileVersionInfo.GetVersionInfo(LocalFile.AppPath); + Name = versionInfo.ProductName; + Company = $"{versionInfo.CompanyName} {versionInfo.LegalCopyright}"; + Ver = $"v {new string(versionInfo.FileVersion.Take(5).ToArray())}"; + } + + /// + /// 程序名 + /// + public string Name { get; set; } + /// + /// 公司名 + /// + public string Company { get; set; } + /// + /// 版本 + /// + public string Ver { get; set; } + } +} diff --git a/货架标准上位机/ViewModels/DataChartViewModel.cs b/货架标准上位机/ViewModels/DataChartViewModel.cs new file mode 100644 index 0000000..d796ef7 --- /dev/null +++ b/货架标准上位机/ViewModels/DataChartViewModel.cs @@ -0,0 +1,199 @@ +using HandyControl.Controls; +using LiveCharts; +using Ping9719.WpfEx.Mvvm; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace 货架标准上位机.ViewModel +{ + public class DataChartViewModel : BindableBase + { + #region 加载 + private bool isLoad; + public bool IsLoad { get => isLoad; set { SetProperty(ref isLoad, value); } } + #endregion + + #region 日期 + private List year = new List(); + /// + /// 年 + /// + public List Year { get => year; set { SetProperty(ref year, value); } } + + private List month = new List(); + /// + /// 月 + /// + public List Month { get => month; set { SetProperty(ref month, value); } } + + private int yearIndex; + /// + /// 年索引 + /// + public int YearIndex { get => yearIndex; set { SetProperty(ref yearIndex, value); UpdataMonth(); } } + + private int monthIndex; + /// + /// 月索引 + /// + public int MonthIndex { get => monthIndex; set { SetProperty(ref monthIndex, value); StatChart(); } } + #endregion + + #region 图表 + public ChartValues ChartValues1 { get; set; } = new ChartValues(); + public ChartValues ChartValues2 { get; set; } = new ChartValues(); + public ChartValues ChartValues3 { get; set; } = new ChartValues(); + public Func LabelFormatterX { get; set; } = value => $"{value}号"; + public Func LabelFormatterY { get; set; } = value => $"{value}个"; + + private IList chartLabelsX; + /// + /// X轴轴信息 + /// + public IList ChartLabelsX { get => chartLabelsX; set { SetProperty(ref chartLabelsX, value); } } + + #endregion + + #region 方法 + /// + /// 更新年 + /// + public async void UpdataYear() + { + try + { + IsLoad = true; + Year = await DataDb.db.Queryable() + .GroupBy(o => o.Time.Year) + .OrderByDescending(o => o.Time.Year) + .Select(o => o.Time.Year) + .ToListAsync(); + } + catch (Exception ex) + { + Year = new List(); + Growl.Error("刷新数据失败:" + ex.Message); + } + finally + { + YearIndex = Year.Any() ? 0 : -1; + } + } + + /// + /// 更新月 + /// + public async void UpdataMonth() + { + try + { + IsLoad = true; + if (!Year.Any() || YearIndex < 0) + return; + + var dt1 = new DateTime(Year[YearIndex], 1, 1); + var dt2 = dt1.AddYears(1); + Month = await DataDb.db.Queryable() + .Where(o => o.Time > dt1 && o.Time < dt2) + .GroupBy(o => o.Time.Month) + .OrderBy(o => o.Time.Month) + .Select(o => o.Time.Month) + .ToListAsync(); + } + catch (Exception ex) + { + Month = new List(); + Growl.Error("刷新数据失败:" + ex.Message); + } + finally + { + MonthIndex = Month.Any() ? Month.Count - 1 : -1; + } + } + + public ICommand ButStatChartCommand { get => new DelegateCommand(ButStatChart); } + /// + /// 点击刷新 + /// + public void ButStatChart() + { + if (IsLoad) + { + Growl.Info("有任务正在进行"); + return; + } + + if (!Year.Any() || !Month.Any() || YearIndex < 0 || MonthIndex < 0) + { + Growl.Info("没有选择年份或月份"); + return; + } + + StatChart(); + } + + /// + /// 刷新统计信息 + /// + public async void StatChart() + { + try + { + if (!Year.Any() || !Month.Any() || YearIndex < 0 || MonthIndex < 0) + { + ChartValues1.Clear(); + ChartValues2.Clear(); + ChartValues3.Clear(); + return; + } + + IsLoad = true; + await Task.Delay(200); + + var year = Year[YearIndex]; + var month = Month[MonthIndex]; + + var dt1 = new DateTime(year, month, 1); + var dt2 = dt1.AddMonths(1); + + //从数据库中查询、统计数量 + var dbdata = await DataDb.db.Queryable() + .Where(o => o.Time > dt1 && o.Time < dt2) + .GroupBy(o => o.Time.Day) + .Select(o => new + { + day = o.Time.Day, + count = SqlFunc.AggregateCount(o.Id), + okCount = SqlFunc.AggregateCount(o.Status == "合格" ? "" : null), + notCount = SqlFunc.AggregateCount(o.Status != "合格" ? "" : null), + }) + .OrderBy(o => o.day) + .ToListAsync(); + + ChartLabelsX = dbdata.Select(o => o.day.ToString()).ToList(); + + ChartValues1.Clear(); + ChartValues2.Clear(); + ChartValues3.Clear(); + + ChartValues1.AddRange(dbdata.Select(o => o.count)); + ChartValues2.AddRange(dbdata.Select(o => o.okCount)); + ChartValues3.AddRange(dbdata.Select(o => o.notCount)); + } + catch (Exception ex) + { + Growl.Error("刷新数据失败:" + ex.Message); + } + finally + { + IsLoad = false; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/DataListViewModel.cs b/货架标准上位机/ViewModels/DataListViewModel.cs new file mode 100644 index 0000000..aa569d3 --- /dev/null +++ b/货架标准上位机/ViewModels/DataListViewModel.cs @@ -0,0 +1,201 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; + +namespace 货架标准上位机.ViewModel +{ + public class DataListViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 进度 + private bool IsLoad_; + public bool IsLoad { get => IsLoad_; set { SetProperty(ref IsLoad_, value); } } + #endregion + + #region 筛选 + private DateTime? timeGo = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); + /// + /// 开始时间(默认只显示今天开始的数据) + /// + public DateTime? TimeGo { get => timeGo; set { SetProperty(ref timeGo, value); } } + + private DateTime? timeTo; + /// + /// 结束时间 + /// + public DateTime? TimeTo { get => timeTo; set { SetProperty(ref timeTo, value); } } + + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + + private string info2; + public string Info2 { get => info2; set { SetProperty(ref info2, value); } } + + #endregion + + #region 页码 + private int maxPageCount; + /// + /// 最大页数 + /// + public int MaxPageCount { get => maxPageCount; set { SetProperty(ref maxPageCount, value); } } + + private int pageIndex = 1; + /// + /// 当前页 + /// + public int PageIndex { get => pageIndex; set { SetProperty(ref pageIndex, value); } } + + private int dataCountPerPage = 20; + /// + /// 每页的数据量 + /// + public int DataCountPerPage { get => dataCountPerPage; set { SetProperty(ref dataCountPerPage, value); } } + + public ICommand PageUpdateCommand { get => new DelegateCommand>(PageUpdate); } + /// + /// 页码更新 + /// + public void PageUpdate(FunctionEventArgs page) + { + PageIndex = page.Info; + UpdateList(); + } + #endregion + + public ICommand ExportExcelCommand { get => new DelegateCommand(ExportExcel); } + /// + /// 导出为excel + /// + public async void ExportExcel() + { + if (IsLoad) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + IsLoad = true; + + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "XXXX记录信息"; + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + IsLoad = false; + return; + } + + string path = sfd.FileName; + + try + { + //1.查询数据库,加入筛选条件,并按照时间倒序排序,并导出指定列 + var dbData = DataDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.Time > TimeGo) + .WhereIF(TimeTo != null, o => o.Time < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Info1.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Info2.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.Id) + .Select(o => new + { + 产品信息1 = o.Info1, + 产品信息2 = o.Info2, + 状态结果 = o.Status, + 创建时间 = o.Time.ToString("yyyy-MM-dd HH:mm:ss"), + }); + + //2.导出为Excel,使用内存缓存的方式,防止数据量过大导致内存泄露 + var sqlkv = dbData.ToSql(); + var dataReader = await DataDb.db.Ado.GetDataReaderAsync(sqlkv.Key, sqlkv.Value); + await MiniExcel.SaveAsAsync(path, dataReader, overwriteFile: true); + dataReader.Close(); + + Growl.Success("导出成功。"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + finally + { + IsLoad = false; + } + + } + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public async void UpdateList() + { + if (IsLoad) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + IsLoad = true; + + try + { + await Task.Delay(200); + + //1.查询数据库,加入筛选条件,并按照时间倒序排序 + var dbData = DataDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.Time > TimeGo) + .WhereIF(TimeTo != null, o => o.Time < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Info1.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Info2.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.Id); + + //2.开始分页(如模型不一样使用‘.Select()’来转换) + RefAsync totalNumber = 0; + RefAsync totalPage = 0; + DataList = await dbData.ToPageListAsync(PageIndex, DataCountPerPage, totalNumber, totalPage); + MaxPageCount = totalPage.Value; + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + IsLoad = false; + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + /// + /// 查看详情 + /// + public void See(MyTestTable obj) + { + if (IsLoad) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + Growl.Info("信息:" + Newtonsoft.Json.JsonConvert.SerializeObject(obj)); + } + + } +} diff --git a/货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs b/货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs new file mode 100644 index 0000000..67183a9 --- /dev/null +++ b/货架标准上位机/ViewModels/DataListWarnInfoViewModel.cs @@ -0,0 +1,206 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; + +namespace 货架标准上位机.ViewModel +{ + public class DataListWarnInfoViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 进度 + private bool isLoad1 = false; + public bool IsLoad1 { get => isLoad1; set { SetProperty(ref isLoad1, value); } } + + private bool isLoad2 = false; + public bool IsLoad2 { get => isLoad2; set { SetProperty(ref isLoad2, value); } } + #endregion + + #region 筛选 + private DateTime? timeGo = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day); + /// + /// 开始时间(默认只显示今天开始的数据) + /// + public DateTime? TimeGo { get => timeGo; set { SetProperty(ref timeGo, value); } } + + private DateTime? timeTo; + /// + /// 结束时间 + /// + public DateTime? TimeTo { get => timeTo; set { SetProperty(ref timeTo, value); } } + + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + + private string info2; + public string Info2 { get => info2; set { SetProperty(ref info2, value); } } + + #endregion + + #region 页码 + private int maxPageCount; + /// + /// 最大页数 + /// + public int MaxPageCount { get => maxPageCount; set { SetProperty(ref maxPageCount, value); } } + + private int pageIndex = 1; + /// + /// 当前页 + /// + public int PageIndex { get => pageIndex; set { SetProperty(ref pageIndex, value); } } + + private int dataCountPerPage = 20; + /// + /// 每页的数据量 + /// + public int DataCountPerPage { get => dataCountPerPage; set { SetProperty(ref dataCountPerPage, value); } } + + public ICommand PageUpdateCommand { get => new DelegateCommand>(PageUpdate); } + /// + /// 页码更新 + /// + public void PageUpdate(FunctionEventArgs page) + { + PageIndex = page.Info; + UpdateList(); + } + #endregion + + public ICommand ExportExcelCommand { get => new DelegateCommand(ExportExcel); } + /// + /// 导出为excel + /// + public async void ExportExcel() + { + if (IsLoad2) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "警告信息记录信息"; + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + IsLoad1 = false; + return; + } + + string path = sfd.FileName; + + try + { + //1.查询数据库,加入筛选条件,并按照时间倒序排序,并导出指定列 + var dbData = WarnInfoDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.TimeGo > TimeGo) + .WhereIF(TimeTo != null, o => o.TimeGo < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Source.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Level.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.TimeGo) + .Select(o => new + { + 来源 = o.Source, + 文本信息 = o.Text, + 级别 = o.Level, + 解决方案 = o.Solution, + 警告类型 = o.WarnType, + 开始时间 = o.TimeGo.ToString("yyyy-MM-dd HH:mm:ss"), + 结束时间 = o.TimeTo.HasValue ? o.TimeTo.Value.ToString("yyyy-MM-dd HH:mm:ss") : "", + 持续时间 = o.DuraTime, + }); + + //2.导出为Excel,使用内存缓存的方式,防止数据量过大导致内存泄露 + var sqlkv = dbData.ToSql(); + var dataReader = await DataDb.db.Ado.GetDataReaderAsync(sqlkv.Key, sqlkv.Value); + await MiniExcel.SaveAsAsync(path, dataReader, overwriteFile: true); + dataReader.Close(); + + Growl.Success("导出成功。"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + finally + { + IsLoad1 = false; + } + + } + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public async void UpdateList() + { + if (IsLoad1) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + try + { + await Task.Delay(200); + + //1.查询数据库,加入筛选条件,并按照时间倒序排序 + var dbData = WarnInfoDb.db.Queryable() + .WhereIF(TimeGo != null, o => o.TimeGo > TimeGo) + .WhereIF(TimeTo != null, o => o.TimeGo < TimeTo) + .WhereIF(!string.IsNullOrWhiteSpace(Info1), o => o.Source.StartsWith(Info1.Trim())) + .WhereIF(!string.IsNullOrWhiteSpace(Info2), o => o.Level.StartsWith(Info2.Trim())) + .OrderByDescending(o => o.TimeGo); + + //2.开始分页(如模型不一样使用‘.Select()’来转换) + RefAsync totalNumber = 0; + RefAsync totalPage = 0; + DataList = await dbData.ToPageListAsync(PageIndex, DataCountPerPage, totalNumber, totalPage); + MaxPageCount = totalPage.Value; + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + IsLoad2 = false; + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + /// + /// 查看详情 + /// + public void See(MyTestTable obj) + { + if (IsLoad1 || IsLoad2) + { + Growl.Info("有任务正在进行,请稍等片刻。"); + return; + } + + Growl.Info("信息:" + Newtonsoft.Json.JsonConvert.SerializeObject(obj)); + } + + } +} diff --git a/货架标准上位机/ViewModels/DeviceViewModel.cs b/货架标准上位机/ViewModels/DeviceViewModel.cs new file mode 100644 index 0000000..aa10160 --- /dev/null +++ b/货架标准上位机/ViewModels/DeviceViewModel.cs @@ -0,0 +1,677 @@ +using HandyControl.Controls; +using Ping9719.WpfEx; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; + +namespace 货架标准上位机.ViewModel +{ + public class DeviceViewModel : BindableBase + { + //循环间隙时间 + int whileSleep = 1500; + /// + /// 是否繁忙。繁忙状态下不在进行定时刷新操作。 + /// + public bool IsBusy { get; set; } = false; + //public IIoTBase plc; + + #region 属性 + /// + /// 监听 + /// + public IEnumerable DataReads { get; set; } + /// + /// 控制 + /// + public IEnumerable DataWrites { get; set; } + /// + /// 气缸 + /// + public IEnumerable DataUrns { get; set; } + /// + /// 伺服 + /// + public IEnumerable DataServos { get; set; } + + private bool IsVis_ = false; + /// + /// 当前页面是否显示 + /// + public bool IsVis { get => IsVis_; set { SetProperty(ref IsVis_, value); } } + + #region 是否展示 + private bool IsVisRead_ = true; + public bool IsVisRead { get => IsVisRead_; set { SetProperty(ref IsVisRead_, value); } } + + private bool IsVisWrite_ = true; + public bool IsVisWrite { get => IsVisWrite_; set { SetProperty(ref IsVisWrite_, value); } } + + private bool IsVisUrn_ = true; + public bool IsVisUrn { get => IsVisUrn_; set { SetProperty(ref IsVisUrn_, value); } } + + private bool IsVisServo_ = true; + public bool IsVisServo { get => IsVisServo_; set { SetProperty(ref IsVisServo_, value); } } + #endregion + + #region 是否折叠 + private bool IsVisExpRead_ = true; + public bool IsVisExpRead { get => IsVisExpRead_; set { SetProperty(ref IsVisExpRead_, value); } } + + private bool IsVisExpWrite_ = true; + public bool IsVisExpWrite { get => IsVisExpWrite_; set { SetProperty(ref IsVisExpWrite_, value); } } + + private bool IsVisExpUrn_ = false; + public bool IsVisExpUrn { get => IsVisExpUrn_; set { SetProperty(ref IsVisExpUrn_, value); } } + + private bool IsVisExpServo_ = false; + public bool IsVisExpServo { get => IsVisExpServo_; set { SetProperty(ref IsVisExpServo_, value); } } + #endregion + + #endregion + + /// + /// 循环读取数据 + /// + public async void WhileRead() + { + while (true) + { + try + { + if (!IsVis || IsBusy) + { + await Task.Delay(whileSleep); + continue; + } + + ////监控 + if (DataReads != null && IsVisExpRead) + { + foreach (var item in DataReads) + { + if (!item.IsExpanded) + continue; + + var plcAdd = item.ExcelTag; + if (string.IsNullOrWhiteSpace(plcAdd.地址)) + continue; + + var ts = plcAdd.类型.Trim().ToLower(); + switch (ts) + { + case "bool": + //var datab = plc?.Read(plcAdd.地址); + //item.Value = datab?.IsSucceed == true ? datab.Value : false; + break; + case "byte": + //var datay = plc?.Read(plcAdd.地址); + //item.Value = datay?.IsSucceed == true ? datay.Value : "-"; + break; + case "int16": + //var datai16 = plc?.Read(plcAdd.地址); + //item.Value = datai16?.IsSucceed == true ? datai16.Value : "-"; + break; + case "int32": + //var datai32 = plc?.Read(plcAdd.地址); + //item.Value = datai32?.IsSucceed == true ? datai32.Value : "-"; + break; + case "uint16": + //var dataui16 = plc?.Read(plcAdd.地址); + //item.Value = dataui16?.IsSucceed == true ? dataui16.Value : "-"; + break; + case "uint32": + //var dataui32 = plc?.Read(plcAdd.地址); + //item.Value = dataui32?.IsSucceed == true ? dataui32.Value : "-"; + break; + case "float": + case "single": + //var datas = plc?.Read(plcAdd.地址); + //item.Value = datas?.IsSucceed == true ? datas.Value : "-"; + break; + case "double": + //var datad = plc?.Read(plcAdd.地址); + //item.Value = datad?.IsSucceed == true ? datad.Value : "-"; + break; + default: + break; + } + } + } + + ////控制 + if (DataWrites != null && IsVisExpWrite) + { + foreach (var item in DataWrites) + { + if (!item.IsExpanded) + continue; + + var plcAdd = item.ExcelTag; + if (string.IsNullOrWhiteSpace(plcAdd.读地址)) + continue; + + var ts = plcAdd.类型.Trim().ToLower(); + switch (ts) + { + case "bool": + //var datab = plc?.Read(plcAdd.读地址); + //item.Value = datab?.IsSucceed == true ? datab.Value : false; + break; + case "byte": + //var datay = plc?.Read(plcAdd.读地址); + //item.Value = datay?.IsSucceed == true ? datay.Value : "-"; + break; + case "int16": + //var datai16 = plc?.Read(plcAdd.读地址); + //item.Value = datai16?.IsSucceed == true ? datai16.Value : "-"; + break; + case "int32": + //var datai32 = plc?.Read(plcAdd.读地址); + //item.Value = datai32?.IsSucceed == true ? datai32.Value : "-"; + break; + case "uint16": + //var dataui16 = plc?.Read(plcAdd.读地址); + //item.Value = dataui16?.IsSucceed == true ? dataui16.Value : "-"; + break; + case "uint32": + //var dataui32 = plc?.Read(plcAdd.读地址); + //item.Value = dataui32?.IsSucceed == true ? dataui32.Value : "-"; + break; + case "float": + case "single": + //var datas = plc?.Read(plcAdd.读地址); + //item.Value = datas?.IsSucceed == true ? datas.Value : "-"; + break; + case "double": + //var datad = plc?.Read(plcAdd.读地址); + //item.Value = datad?.IsSucceed == true ? datad.Value : "-"; + break; + default: + break; + } + } + } + + ////气缸 + if (DataUrns != null && IsVisExpUrn) + { + foreach (var item in DataUrns) + { + if (!item.IsExpanded) + continue; + + var plcAdd = item.ExcelTag; + if (!string.IsNullOrWhiteSpace(plcAdd.推到位地址)) + { + //var data1 = plc?.Read(plcAdd.推到位地址); + //item.IsGoTo = data1?.IsSucceed == true ? data1.Value : false; + } + if (!string.IsNullOrWhiteSpace(plcAdd.回到位地址)) + { + //var data2 = plc?.Read(plcAdd.回到位地址); + //item.IsRetTo = data2?.IsSucceed == true ? data2.Value : false; + } + } + } + + ////伺服 + if (DataServos != null && IsVisExpServo) + { + foreach (var item in DataServos) + { + if (!item.IsExpanded) + continue; + + ////读取地址信息 + var plcAdd = item.ExcelTag; + if (!string.IsNullOrWhiteSpace(plcAdd.当前位置获取)) + { + //var data1 = plc?.Read(plcAdd.当前位置获取); + //item.Location = data1?.IsSucceed == true ? data1.Value : 0; + } + if (!string.IsNullOrWhiteSpace(plcAdd.手动速度获取) && (item.IsJog || !item.IsFold)) + { + //var data2 = plc?.Read(plcAdd.手动速度获取); + //item.JogSpeed = data2?.IsSucceed == true ? data2.Value : 0; + } + if (!string.IsNullOrWhiteSpace(plcAdd.自动速度设置) && (!item.IsJog || !item.IsFold)) + { + //var data3 = plc?.Read(plcAdd.自动速度设置); + //item.AutoSpeed = data3?.IsSucceed == true ? data3.Value : 0; + } + } + } + + await Task.Delay(whileSleep); + } + catch (Exception) + { + + } + } + } + + /*一起选中【操作控制】【操作气缸】【操作伺服】可以快速解开全部注释*/ + + #region 操作控制 + ////单击 + public void WriteClick(object sender, RoutedEventArgs e) + { + var data = (DeviceWriteModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (dataExcel.类型.Trim().ToLower() == "bool" && mode.StartsWith("切换")) + { + Task.Run(() => + { + var boolval = data.Value is true; + //plc?.Write(dataExcel.写地址, !boolval); + data.Value = !boolval; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = data.Value, Mode = mode }); + }); + } + else + { + var ts = dataExcel.类型.Trim().ToLower(); + switch (ts) + { + case "byte": + WriteClickDialog(data); + break; + case "int16": + WriteClickDialog(data); + break; + case "int32": + WriteClickDialog(data); + break; + case "uint16": + WriteClickDialog(data); + break; + case "uint32": + WriteClickDialog(data); + break; + case "float": + case "single": + WriteClickDialog(data); + break; + case "double": + WriteClickDialog(data); + break; + default: + break; + } + } + } + + ////单击弹框 + void WriteClickDialog(DeviceWriteModel data) where T : struct + { + var dataExcel = data.ExcelTag; + var val = TipInputView.Show($"请输入新的[{dataExcel.名称}]值:", "修改值", "请输入值"); + if (!val.HasValue) + return; + + //plc?.Write(dataExcel.写地址, val.Value); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = val.Value, Mode = "" }); + } + + ////按下左键 + public void LeftDown(object sender, MouseButtonEventArgs e) + { + var data = (DeviceWriteModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (dataExcel.类型.Trim().ToLower() == "bool" && mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.写地址, true); + data.Value = true; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = data.Value, Mode = mode }); + }); + } + } + + ////放开左键 + public void LeftUp(object sender, MouseButtonEventArgs e) + { + var data = (DeviceWriteModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (dataExcel.类型.Trim().ToLower() == "bool" && mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.写地址, false); + data.Value = false; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "控制", Funct = string.Empty, Val = data.Value, Mode = mode }); + }); + } + } + #endregion + + #region 操作气缸 + ////按钮1单击 + public void Button1_Click(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("切换")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, true); + //plc?.Write(dataExcel.回地址, false); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "推", Val = true, Mode = mode }); + }); + } + } + + ////按钮1按下 + public void But1ClickDown(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, true); + data.IsGoTo = true; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "推", Val = true, Mode = mode }); + }); + } + } + + ////按钮1松开 + public void But1ClickUp(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, false); + data.IsGoTo = false; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "推", Val = false, Mode = mode }); + }); + } + } + + ////按钮2单击 + public void Button2_Click(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("切换")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.推地址, false); + //plc?.Write(dataExcel.回地址, true); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "回", Val = true, Mode = mode }); + }); + } + } + + ////按钮2按下 + public void But2ClickDown(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.回地址, true); + data.IsRetTo = true; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "回", Val = true, Mode = mode }); + }); + } + } + + ////按钮2松开 + public void But2ClickUp(object sender, RoutedEventArgs e) + { + var data = (DeviceUrnModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = dataExcel.点动切换?.Trim() ?? ""; + + if (mode.StartsWith("点动")) + { + Task.Run(() => + { + //plc?.Write(dataExcel.回地址, false); + data.IsRetTo = false; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "气缸", Funct = "回", Val = false, Mode = mode }); + }); + } + } + #endregion + + #region 操作伺服 + ////尝试改变伺服的位置时 + public void LocationChange(object sender, RoutedEventArgs e) + { + var data = (DeviceServoModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = string.Empty; + + ////运动方式 + if (e.OriginalSource is ServoClickType servoClickType) + { + if (servoClickType == ServoClickType.StartDotAdd) + { + //plc?.Write(dataExcel.位置点动加, true); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "开始点动加", Val = true, Mode = mode }); + } + else if (servoClickType == ServoClickType.EndDotAdd) + { + //plc?.Write(dataExcel.位置点动加, false); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "结束点动加", Val = false, Mode = mode }); + } + else if (servoClickType == ServoClickType.StartDotSub) + { + //plc?.Write(dataExcel.位置点动减, true); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "开始点动减", Val = true, Mode = mode }); + } + else if (servoClickType == ServoClickType.EndDotSub) + { + //plc?.Write(dataExcel.位置点动减, false); + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "结束点动减", Val = false, Mode = mode }); + } + } + ////运动到指定位置 + else if (e.OriginalSource is double val) + { + //plc?.Write(dataExcel.位置移动, Convert.ToSingle(val)); + data.Location = val; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "位置移动", Val = val, Mode = mode }); + } + } + + ////尝试改变伺服的速度时 + public void SpeedChange(object sender, RoutedEventArgs e) + { + var data = (DeviceServoModel)((FrameworkElement)sender).DataContext; + var dataExcel = data.ExcelTag; + var mode = string.Empty; + + var data2 = (ServoSpeed)e.OriginalSource; + if (data2.Name.StartsWith("手动")) + { + //plc?.Write(dataExcel.手动速度设置, Convert.ToSingle(data2.Speed)); + data.JogSpeed = data2.Speed; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "手动速度设置", Val = data2.Speed, Mode = mode }); + } + else + { + //plc?.Write(dataExcel.自动速度设置, Convert.ToSingle(data2.Speed)); + data.AutoSpeed = data2.Speed; + IotDevice.UserChange?.Invoke(new IotDevice() { Name = data.Name, Type = "伺服", Funct = "自动速度设置", Val = data2.Speed, Mode = mode }); + + } + } + #endregion + } + + public class DeviceReadModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private object Value_; + /// + /// 值 + /// + public object Value { get => Value_; set { SetProperty(ref Value_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + /// + /// Excel原始数据 + /// + public ExcelDeviceReadModel ExcelTag { get; set; } + #endregion + } + + public class DeviceWriteModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private object Value_; + /// + /// 是否合格 + /// + public object Value { get => Value_; set { SetProperty(ref Value_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + /// + /// Excel原始数据 + /// + public ExcelDeviceWriteModel ExcelTag { get; set; } + #endregion + } + + public class DeviceUrnModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private bool IsGoTo_; + /// + /// 是否推到位 + /// + public bool IsGoTo { get => IsGoTo_; set { SetProperty(ref IsGoTo_, value); } } + + private bool IsRetTo_; + /// + /// 是否回到位 + /// + public bool IsRetTo { get => IsRetTo_; set { SetProperty(ref IsRetTo_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + /// + /// 自定义数据 + /// + public ExcelDeviceUrnModel ExcelTag { get; set; } + #endregion + } + + public class DeviceServoModel : BindableBase + { + #region 属性 + private string Name_; + /// + /// 名称 + /// + public string Name { get => Name_; set { SetProperty(ref Name_, value); } } + + private double JogSpeed_; + /// + /// 手动模式速度 + /// + public double JogSpeed { get => JogSpeed_; set { SetProperty(ref JogSpeed_, value); } } + + private double AutoSpeed_; + /// + /// 自动模式速度 + /// + public double AutoSpeed { get => AutoSpeed_; set { SetProperty(ref AutoSpeed_, value); } } + + private double Location_; + /// + /// 伺服当前位置 + /// + public double Location { get => Location_; set { SetProperty(ref Location_, value); } } + + private bool IsJog_ = true; + /// + /// 是否主页显示为手动模式 + /// + public bool IsJog { get => IsJog_; set { SetProperty(ref IsJog_, value); } } + + private bool IsFold_ = true; + /// + /// 是否折叠 + /// + public bool IsFold { get => IsFold_; set { SetProperty(ref IsFold_, value); } } + + /// + /// 是否可见 + /// + public bool IsExpanded { get; set; } + + private ExcelDeviceServoModel ExcelTag_; + /// + /// 自定义数据 + /// + public ExcelDeviceServoModel ExcelTag { get => ExcelTag_; set { SetProperty(ref ExcelTag_, value); } } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/HomeViewModel.cs b/货架标准上位机/ViewModels/HomeViewModel.cs new file mode 100644 index 0000000..88216c7 --- /dev/null +++ b/货架标准上位机/ViewModels/HomeViewModel.cs @@ -0,0 +1,109 @@ +using HandyControl.Controls; +using LiveCharts; +using Ping9719.WpfEx; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; +using HandyControl.Tools.Extension; +using 货架标准上位机.Views.Controls; +using 货架标准上位机.Api; +using WCS.Model; + +namespace 货架标准上位机.ViewModel +{ + public class HomeViewModel : BindableBase + { + WarnInfoContainer WarnInfo = new WarnInfoContainer();//警告、错误等信息 + + #region 绑定 + private string textErr; + /// + /// 错误文本 + /// + public string TextErr { get => textErr; set { SetProperty(ref textErr, value); } } + public ICommand ClearTextInfoCommand { get => new DelegateCommand(ClearTextInfo); } + /// + /// 清除信息文本 + /// + public void ClearTextInfo() + { + TextBoxLog.ClearLog(); + } + public ICommand ClearTextErrCommand { get => new DelegateCommand(ClearTextErr); } + /// + /// 清除全部错误文本 + /// + public void ClearTextErr() + { + WarnInfo.RemoveAll(WarnInfoType.AlwayWarn); + } + + public ICommand AddUserControlCommand { get => new DelegateCommand(AddUserControl); } + public WrapPanel wrapPanel; + public async void AddUserControl() + { + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetShelfStatusRequest() + { + UserName = "xxx", + DeviceType = "WCS前端", + GroupNames = LocalFile.Config.GroupName, + + }; + var Result = await ApiHelp.Post([LocalFile.Config.ApiIpHost, "home/getShelfStatus"], body); + if (Result != null && Result.Data?.Count > 0) + { + wrapPanel.Children.Clear(); + Result.Data.ForEach(t => + { + var shelf = new ShelfStatusControl(t.ShelfCode, t.CurentMode, t.GroupName); + wrapPanel.Children.Add(shelf); + }); + } + } + catch (Exception ex) + { + + } + finally + { + dia.Close(); + } + } + #endregion + + #region 页面加载时任务 + /// + /// 页面第一次加载时执行的任务 + /// + public void LoadTask() + { + //注册警告事件 + WarnInfo.WarnInfoChanged += (all, add, rem) => + { + TextErr = string.Join(Environment.NewLine, all.OrderBy(o => (o.WarnType, o.Source, o.Text))); + + if (add.Any()) + Logs.Write(add.Select(o => o.ToString()), LogsType.Warning); + if (rem.Any()) + Logs.Write(rem.Select(o => o.ToString()), LogsType.Warning); + + //警告信息保存到数据库 + if (WarnInfoDb.IsEnabled) + { + WarnInfoDb.db.Insertable(WarnInfoItemDb.GetList(add)).ExecuteCommand(); + WarnInfoDb.db.Updateable(WarnInfoItemDb.GetList(rem)).ExecuteCommand(); + } + }; + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/ImageListenerViewModel.cs b/货架标准上位机/ViewModels/ImageListenerViewModel.cs new file mode 100644 index 0000000..350175f --- /dev/null +++ b/货架标准上位机/ViewModels/ImageListenerViewModel.cs @@ -0,0 +1,55 @@ +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; + +namespace 货架标准上位机.ViewModel +{ + public class ImageListenerViewModel : BindableBase + { + #region MyRegion + private BitmapFrame ImageSource_; + public BitmapFrame ImageSource { get => ImageSource_; set { SetProperty(ref ImageSource_, value); } } + + public double ImageWidth { get; set; } + public double ImageHeight { get; set; } + #endregion + + #region 变换 + private double ScaleXY_ = 1; + + public double ScaleXY { get => ScaleXY_; set { SetProperty(ref ScaleXY_, value); } } + + private double CenterX_; + + public double CenterX { get => CenterX_; set { SetProperty(ref CenterX_, value); } } + + private double CenterY_; + + public double CenterY { get => CenterY_; set { SetProperty(ref CenterY_, value); } } + + private double TranslateX_; + + public double TranslateX { get => TranslateX_; set { SetProperty(ref TranslateX_, value); } } + + private double TranslateY_; + + public double TranslateY { get => TranslateY_; set { SetProperty(ref TranslateY_, value); } } + + /// + /// 自适应大小 + /// + public void ImgAutoSize() + { + ScaleXY = 1; + CenterX = 0; + CenterY = 0; + TranslateX = 0; + TranslateY = 0; + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/InInventoryViewModel.cs b/货架标准上位机/ViewModels/InInventoryViewModel.cs new file mode 100644 index 0000000..6b81278 --- /dev/null +++ b/货架标准上位机/ViewModels/InInventoryViewModel.cs @@ -0,0 +1,207 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using TouchSocket.Sockets; +using TouchSocket.Core; +using System.Text.RegularExpressions; +using System.Collections.ObjectModel; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using System.Security.Cryptography; + +namespace 货架标准上位机.ViewModel +{ + public class InInventoryViewModel : BindableBase + { + public InInventoryViewModel() + { + //初始化串口接收事件 + var scanners = ScannerManager.Scanners; + foreach (var scanner in scanners) + { + scanner.SerialPortClient.Received = (client, e) => + { + //获取串口号 + var COM = client.MainSerialPort.PortName; + //获取扫码枪对象 + var scanner = ScannerManager.Scanners.Where(t => t.COM == COM).FirstOrDefault(); + if (scanner == null) + return EasyTask.CompletedTask; + int newBytes = e.ByteBlock.Len; + if (newBytes > 0) + { + var currentScanedCode = Encoding.UTF8.GetString(e.ByteBlock, 0, e.ByteBlock.Len); + Logs.Write($"接收到扫码枪扫码数据{currentScanedCode}"); + scanner.TempCode += currentScanedCode; + //校验末尾码 + CheckDataCompleteness(scanner); + scanner.ScannerDisplayControl.RefreshValues(scanner.ShelfCode, scanner.MatSn); + } + return EasyTask.CompletedTask; + }; + } + } + + #region Property + private string shelfCode; + public string ShelfCode + { + get { return shelfCode; } + set + { + SetProperty(ref shelfCode, value); + } + } + #endregion + + #region Command + public void CheckDataCompleteness(Scanner scanner) + { + if (scanner.TempCode.EndsWith("\r"))//结束符 TODO结束符是否需要自定义 现场配置 + { + scanner.TempCode = scanner.TempCode.Replace("\r", string.Empty).Replace("\n", string.Empty); + try + { + //TO DO 配置项进行配置正则表达式 + //数据处理 + string ModuleCodePattern = "^[ABCD][0-9]{2}-R[0-9]{1,2}C[0-9]{1,2}$"; + var isModuleCode = Regex.IsMatch(scanner.TempCode, ModuleCodePattern); + if (isModuleCode) + { + ModuleCodeProcess(scanner); + } + //TO DO 增加正则表达式进行判断是否扫到的是物料码 + else + { + MatSnProcess(scanner); + } + } + catch (Exception ex) + { + var message = "入库扫码枪扫码发生异常:" + ex.Message; + + } + finally + { + //不管入库成功与否 认为本次扫码完毕 清空暂存数据 + scanner.TempCode = string.Empty; + } + } + } + + /// + /// 扫到模组码的数据处理 + /// + /// + public void ModuleCodeProcess(Scanner scanner) + { + //如果扫码枪前一个货架未退出入库 + if (scanner.IsInstoreMode) + { + //判断当前入库货架是否包含本次扫码的模组 + if (scanner.ModulesStr.Contains(scanner.TempCode)) + { + return; + } + else + { + #region 调用接口结束扫码枪占用入库的货架 + try + { + var body = new ShelfGoOutInStoreRequest() + { + ShelfCode = scanner.ShelfCode, + IPAdress = scanner.COM, + DeviceType = LocalFile.Config.DeviceType, + UserName = LocalStatic.CurrentUser, + }; + var Result = ApiHelp.GetDataFromHttp(LocalFile.Config.ApiIpHost + "instore/shelfGoOutInStore", body, "POST"); + if (Result != null && Result.Code == 200) + { + scanner.ShelfCode = string.Empty; + scanner.ModulesStr = string.Empty; + } + } + catch (Exception ex) + { + + } + #endregion + } + } + + //调用接口 请求进入入库模式 + #region 调用接口进入入库模式 + try + { + var body = new ShelfGoInInstoreRequest() + { + ModuleCode = scanner.TempCode, + DeviceType = LocalFile.Config.DeviceType, + UserName = LocalStatic.CurrentUser, + IpAdress = scanner.COM, + }; + var Result = ApiHelp.GetDataFromHttp(LocalFile.Config.ApiIpHost + "instore/shelfGoInInStore", body, "POST"); + if (Result != null && Result.Code == 200) + { + scanner.ShelfCode = Result.Data.ShelfCode; + scanner.ModulesStr = Result.Data.ModulesStr; + } + } + catch (Exception ex) + { + + } + #endregion + } + + /// + /// 扫到物料码的数据处理 + /// + public void MatSnProcess(Scanner scanner) + { + #region 调用接口 扫物料码获取物料信息并绑定 + try + { + var body = new QueryByMatSnRequest() + { + ShelfCode = scanner.ShelfCode, + IpAddress = scanner.COM, + DeviceType = LocalFile.Config.DeviceType, + UserName = LocalStatic.CurrentUser, + }; + var Result = ApiHelp.GetDataFromHttp(LocalFile.Config.ApiIpHost + "instore/queryByMatSn", body, "POST"); + if (Result != null && Result.Code == 200) + { + scanner.MatSn = Result.Data.materialBar; + } + } + catch (Exception ex) + { + + } + #endregion + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/InterfaceRecordViewModel.cs b/货架标准上位机/ViewModels/InterfaceRecordViewModel.cs new file mode 100644 index 0000000..1d988da --- /dev/null +++ b/货架标准上位机/ViewModels/InterfaceRecordViewModel.cs @@ -0,0 +1,288 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; + +namespace 货架标准上位机.ViewModel +{ + public class InterfaceRecordViewModel : BindableBase + { + #region Property + private List dataGridItemSource; + public List DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + /// + /// 接口地址 + /// + private string requestUrl; + public string RequestUrl + { + get { return requestUrl; } + set + { + SetProperty(ref requestUrl, value); + } + } + + /// + /// 请求参数 + /// + private string requestBody; + public string RequestBody + { + get { return requestBody; } + set + { + SetProperty(ref requestBody, value); + } + } + + /// + /// 请求时间的类型 + /// + private TimeType timeType; + public TimeType TimeType + { + get { return timeType; } + set + { + SetProperty(ref timeType, value); + } + } + + public IEnumerable TimeTypes => GetEnumValues(); + private IEnumerable GetEnumValues() + { + return Enum.GetNames(typeof(TimeType)); + } + + private DateTime startTime; + public DateTime StartTime + { + get { return startTime; } + set + { + SetProperty(ref startTime, value); + } + } + + private DateTime endTime; + public DateTime EndTime + { + get { return endTime; } + set + { + SetProperty(ref endTime, value); + } + } + + /// + /// 调用类型 调用/被调用 + /// + private string requestType; + public string RequestType + { + get { return requestType; } + set + { + SetProperty(ref requestType, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + RequestUrl = string.Empty; + RequestBody = string.Empty; + RequestType = string.Empty; + TimeType = TimeType.请求时间; + StartTime = DateTime.Now.Date; + EndTime = DateTime.Now.Date.AddDays(1); + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetInterfaceRecordsRequest() + { + RequestUrl = RequestUrl, + RequestBody = RequestBody, + RequestType = RequestType, + TimeType = TimeType, + StartTime = StartTime, + EndTime = EndTime, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "interfaceRecord/getInterfaceRecord", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + + + } + + public ICommand BtnExportCommand { get => new DelegateCommand(BtnExport); } + public async void BtnExport() + { + + try + { + #region 选择文件保存路径 + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "接口记录" + DateTime.Now.ToString("yyyyMMddhhmmss"); + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + return; + } + string path = sfd.FileName; + #endregion + + var body = new GetInterfaceRecordsRequest() + { + RequestUrl = RequestUrl, + RequestBody = RequestBody, + RequestType = RequestType, + TimeType = TimeType, + StartTime = StartTime, + EndTime = EndTime, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + + }; + await ApiHelp.PostDownloadFileAsync(path, System.Net.Http.HttpMethod.Post, LocalFile.Config.ApiIpHost + "interfaceRecord/exportInterfaceRecord", body); + Growl.Success("导出成功!"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/MainViewModel.cs b/货架标准上位机/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..93eaa5d --- /dev/null +++ b/货架标准上位机/ViewModels/MainViewModel.cs @@ -0,0 +1,227 @@ +using HandyControl.Controls; +using Newtonsoft.Json; +using Ping9719.WpfEx; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Markup; + +namespace 货架标准上位机.ViewModel +{ + public class MainViewModel : BindableBase + { + Mutex mutex; + private string title = string.Empty; + /// + /// 标题 + /// + public string Title { get => title; set { SetProperty(ref title, value); } } + + #region 专用_MainWindow2 + //隐藏式选项卡的高度 + public double TabItemHeight { get; set; } = 0; + + private string SelectedValue_ = "主页"; + public string SelectedValue { get => SelectedValue_; set { SetProperty(ref SelectedValue_, value); } } + #endregion + + private DateTime time; + /// + /// 时间 + /// + public DateTime Time { get => time; set { SetProperty(ref time, value); } } + /// + /// 在初始化前的相关检查 + /// + public bool InitAgo() + { + //只允许打开一个 + mutex = new Mutex(true, string.Concat("MengXun货架标准上位机", Path.GetFileNameWithoutExtension(LocalFile.AppName)), out bool createdNew); + if (!createdNew) + { + MessageBox.Warning("已有实列在运行!", "提示"); + return false; + } + + //初始化 + Tuple[] tuples = new Tuple[] + { + new Tuple("检测文件..", "缺少文件,尝试将项目[data/]中的所有文件复制到[bin/data/]中", () => + { + if(!System.IO.File.Exists(LocalFile.ConfigPath)) + throw new Exception("缺少文件,请尝试将项目[data/]中的所有文件复制到[bin/data/]中"); + }), + new Tuple("检测文件..", "配置文件中没有内容,请联系管理员", () => + { + if(string.IsNullOrWhiteSpace(System.IO.File.ReadAllText(LocalFile.ConfigPath, Encoding.UTF8))) + throw new Exception($"配置文件[{LocalFile.ConfigPath}]中没有内容"); + }), + new Tuple("初始化数据中..", "初始化数据库失败,请联系管理员", () => + { + + }), + new Tuple("初始化扫码枪连接..", "初始化扫码枪连接失败,请联系管理员", () => + { + ScannerManager.InitScanners(); + }), + }; + + MainLoadWindow.TaskSleepTime = 200; + if (!MainLoadWindow.Show(tuples)) + return false; + + //清理日志 + Task.Run(() => + { + if (LocalFile.Config.Sys.SaveLogDay < 0) + return; + + Logs.Clear(TimeSpan.FromDays(LocalFile.Config.Sys.SaveLogDay)); + }); + + + ////不登录,直接使用最高权限 + //{ + // UserLoginView.NotLogin(); + // return true; + //} + //登录 + { + var userLoginView = new UserLoginView(); + var isok = userLoginView.ShowDialog() == true; + userLoginView = null; + return isok; + } + } + + /// + /// 初始化并运行时间 + /// + public async void Init(System.Windows.Window window) + { + //加载 程序名称 + var versionInfo = FileVersionInfo.GetVersionInfo(LocalFile.AppPath); + Title = versionInfo.ProductName; + + //加载 窗体模式 + if (LocalFile.Config.Sys.StartupFull) + window.WindowState = System.Windows.WindowState.Maximized; + + //注册 设备 + IotDevice.UserChange = ((iot) => + { + if (string.IsNullOrEmpty(iot.Funct)) + Growl.Info($"你点击了[{iot.Name}],尝试改为[{iot.Val}]"); + else + Growl.Info($"你点击了[{iot.Name}][{iot.Funct}],尝试改为[{iot.Val}]"); + + }); + + //注册 信息 + TextBoxLog.TextBoxLogAdd = ((info) => + { + Logs.Write(info.Text, LogsType.Info, info.Time); + }); + + //加载 时钟 + while (true) + { + Time = DateTime.Now; + await Task.Delay(1); + } + } + + public ICommand OpenUserCommand { get => new DelegateCommand(OpenUser); } + /// + /// 打开用户 + /// + public void OpenUser() + { + if (UserInfoView.viewModel.IsLogin) + { + var userInfoView = new UserInfoView(); + userInfoView.ShowDialog(); + + if (userInfoView.IsExitLogin) + { + Growl.Info("您已退出登录。"); + userInfoView = null; + } + } + else + { + var userLoginView = new UserLoginView(); + + //登录成功 + if (userLoginView.ShowDialog() == true) + { + Growl.Success($"欢迎您:{UserInfoView.viewModel.LoginName}"); + userLoginView = null; + } + } + } + + public ICommand OpenLogCommand { get => new DelegateCommand(OpenLog); } + /// + /// 打开日记 + /// + public void OpenLog() + { + if (!System.IO.Directory.Exists(LocalFile.LogDir)) + { + Growl.Info("暂时没有日志。"); + return; + } + + try + { + Folder.OpenFolder(LocalFile.LogDir); + } + catch (Exception) + { + Growl.Error("打开日志目录失败。"); + } + } + + public ICommand OpenHelpCommand { get => new DelegateCommand(OpenHelp); } + /// + /// 打开帮助 + /// + public void OpenHelp() + { + if (!System.IO.File.Exists(LocalFile.DocPath)) + { + Growl.Info("帮助文档正在书写中。"); + return; + } + + try + { + Folder.OpenFolderAndSelectedFile(LocalFile.DocPath); + } + catch (Exception) + { + Growl.Error("打开帮助文档失败。"); + } + } + + public ICommand OpenWeCommand { get => new DelegateCommand(OpenWe); } + /// + /// 打开关于 + /// + public void OpenWe() + { + var aboutView = new AboutView(); + aboutView.ShowDialog(); + aboutView = null; + } + } +} diff --git a/货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs b/货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs new file mode 100644 index 0000000..0909878 --- /dev/null +++ b/货架标准上位机/ViewModels/MatBaseInfoAddOrUpdateViewModel.cs @@ -0,0 +1,41 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; + +namespace 货架标准上位机.ViewModel +{ + public class MatBaseInfoAddOrUpdateViewModel : BindableBase + { + private bool isEnable; + public bool IsEnable + { + get { return isEnable; } + set + { + SetProperty(ref isEnable, value); + } + } + } +} diff --git a/货架标准上位机/ViewModels/MatBaseInfoViewModel.cs b/货架标准上位机/ViewModels/MatBaseInfoViewModel.cs new file mode 100644 index 0000000..a81e5d5 --- /dev/null +++ b/货架标准上位机/ViewModels/MatBaseInfoViewModel.cs @@ -0,0 +1,470 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using System.Collections.ObjectModel; +using HandyControl.Tools.Extension; +using 货架标准上位机.Tool; + +namespace 货架标准上位机.ViewModel +{ + public class MatBaseInfoViewModel : BindableBase + { + #region Property + private ObservableCollection dataGridItemSource; + public ObservableCollection DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + public MatBaseInfoModel selectedataGridItem; + public MatBaseInfoModel SelectedataGridItem + { + get { return selectedataGridItem; } + set + { + SetProperty(ref selectedataGridItem, value); + } + } + + /// + /// 物料编码 + /// + private string matCode; + public string MatCode + { + get { return matCode; } + set + { + SetProperty(ref matCode, value); + } + } + + /// + /// 物料名称 + /// + private string matName; + public string MatName + { + get { return matName; } + set + { + SetProperty(ref matName, value); + } + } + + /// + /// 物料规格 + /// + private string matSpec; + public string MatSpec + { + get { return matSpec; } + set + { + SetProperty(ref matSpec, value); + } + } + + /// + /// 请求时间的类型 + /// + private bool? isEnable; + public bool? IsEnable + { + get { return isEnable; } + set + { + SetProperty(ref isEnable, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + MatCode = string.Empty; + MatName = string.Empty; + MatSpec = string.Empty; + IsEnable = null; + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetMatBaseInfoRequest() + { + MatCode = MatCode, + MatName = MatName, + MatSpec = MatSpec, + IsEnable = IsEnable, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/getMatBaseInfo", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = new ObservableCollection(Result.Data.Lists); + //DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + + + } + + /// + /// 导出数据为Excel文件 + /// + public ICommand BtnExportCommand { get => new DelegateCommand(BtnExport); } + public async void BtnExport() + { + + try + { + #region 选择文件保存路径 + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Title = "选择文件保存路径"; + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "物料管理" + DateTime.Now.ToString("yyyyMMddhhmmss"); + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + return; + } + string path = sfd.FileName; + #endregion + + var body = new GetMatBaseInfoRequest() + { + MatCode = MatCode, + MatName = MatName, + MatSpec = MatSpec, + IsEnable = IsEnable, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + await ApiHelp.PostDownloadFileAsync(path, System.Net.Http.HttpMethod.Post, LocalFile.Config.ApiIpHost + "matBaseInfo/exportMatBaseInfo", body); + Growl.Success("导出成功!"); + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + } + + public ICommand BtnImportCommand { get => new DelegateCommand(BtnImport); } + public async void BtnImport() + { + try + { + #region 选择需要导入文件的路径 + Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog(); + ofd.Title = "选择模板"; + ofd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + ofd.FileName = "物料管理" + DateTime.Now.ToString("yyyyMMddhhmmss"); + ofd.Multiselect = false; + + if (ofd.ShowDialog() != true) + { + return; + } + #endregion + //已经选择文件 调用接口进行导入数据 + string path = ofd.FileName; + + var body = new GetMatBaseInfoRequest() + { + MatCode = MatCode, + MatName = MatName, + MatSpec = MatSpec, + IsEnable = IsEnable, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + var result = await ApiHelp.PostImportFileAsync>>(path, System.Net.Http.HttpMethod.Post, + LocalFile.Config.ApiIpHost + "matBaseInfo/importMatBaseInfo", LocalStatic.CurrentUser, LocalFile.Config.DeviceType); + if (result.Code == 200) + { + Growl.Success("成功导入!"); + CurrentPage = 0; + } + else + { + if (result.Data != null && result.Data.Count > 0) + HandyControl.Controls.MessageBox.Show(result.Message + "\t\n" + String.Join("\t\n", result.Data)); + else + HandyControl.Controls.MessageBox.Show(result.Message); + } + + } + catch (Exception ex) + { + Growl.Error("导入失败:" + ex.Message); + } + } + + + /// + /// 物料新增操作 + /// + public ICommand BtnAddCommand { get => new DelegateCommand(BtnAdd); } + public async void BtnAdd() + { + var addView = new MatBaseInfoAddOrUpdateView("新增物料数据"); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + var matBaseInfo = addView.matBaseInfo; + matBaseInfo.ModifyTime = DateTime.Now; + matBaseInfo.ModifyUser = LocalStatic.CurrentUser; + + var body = new AddMatBaseInfoRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + MatBaseInfo = matBaseInfo, + AddOrUpdate = AddOrUpdate.Add + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/addOrUpdateMatBaseInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + CurrentPage = 1; + Growl.Success("添加成功!"); + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + //BtnAdd(); + } + } + } + + + /// + /// 物料修改操作 + /// + public ICommand BtnEditCommand { get => new DelegateCommand(BtnEdit); } + public async void BtnEdit() + { + //查询勾选的第一个数据 + var matBaseInfo = DataGridItemSource?.Where(t => t.IsSelected == true).FirstOrDefault(); + if (matBaseInfo == null) + { + Growl.Warning("请选择需要修改的数据!"); + } + else + { + var addView = new MatBaseInfoAddOrUpdateView("修改物料数据", matBaseInfo); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + matBaseInfo = addView.matBaseInfo; + + matBaseInfo.ModifyTime = DateTime.Now; + matBaseInfo.ModifyUser = LocalStatic.CurrentUser; + + var body = new AddMatBaseInfoRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + MatBaseInfo = matBaseInfo, + AddOrUpdate = AddOrUpdate.Update + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/addOrUpdateMatBaseInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + CurrentPage = 1; + Growl.Success("修改成功!"); + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + } + } + } + } + + /// + /// 物料删除操作 + /// + public ICommand BtnDeleteCommand { get => new DelegateCommand(BtnDelete); } + public async void BtnDelete() + { + Growl.Ask($"是否删除所有勾选得数据]!", isConfirmed => + { + if (isConfirmed) + { + //查询勾选的第一个数据 + var matBaseInfoIds = DataGridItemSource?.Where(t => t.IsSelected == true) + .Select(t => t.Id) + .ToList(); + + if (matBaseInfoIds == null) + { + Growl.Warning("请选择需要修改的数据!"); + } + else + { + var body = new DeleteMatBaseInfosRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + MatBaseInfoIds = matBaseInfoIds, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matBaseInfo/deleteMatBaseInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + CurrentPage = 1; + Growl.Success("删除成功!" + Result?.Message); + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + } + } + } + return true; + }); + } + + + + public ICommand BtnPrintCommand { get => new DelegateCommand(BtnPrint); } + public async void BtnPrint() + { + PrintTender.PrintTag(new PrintClass() + { + MatQty = "123", + MatCode = "123", + MatBatch = "123", + MatName = "123", + MatSn = "123", + MatSpec = "123", + + }); + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs b/货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs new file mode 100644 index 0000000..ae81bec --- /dev/null +++ b/货架标准上位机/ViewModels/MatInventoryDetailViewModel.cs @@ -0,0 +1,336 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; +using System.Windows.Controls; +using WCS.Model.ApiModel.InterfaceRecord; +using HandyControl.Collections; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.MatInventoryDetail; + +namespace 货架标准上位机.ViewModel +{ + public class MatInventoryDetailViewModel : BindableBase + { + public MatInventoryDetailViewModel() + { + //获取物料编码列表 + //matCodes = DbHelp.db.Queryable() + // .Select(t => new DataModel() + // { + // MatCode = t.MatCode + // }) + // .Distinct() + // .ToList(); + + } + + public void InitMatCode() + { + //调用接口更新! + Task.Run(() => + { + var body = new GetMatCodeListRequest() + { + IsFromBaseData = false, + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + }; + + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "matBaseInfo/getMatCodeList", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Count() > 0) + { + matCodes = Result.Data.Select(t => new DataModel() + { + MatCode = t + }).ToList(); + } + }); + } + + #region Property + private List dataGridItemSource; + public List DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + /// + /// 物料编码 + /// + private string matCode; + public string MatCode + { + get { return matCode; } + set + { + SetProperty(ref matCode, value); + FilterItems(value); + } + } + public ManualObservableCollection Items { get; set; } = new(); + private List matCodes = new List(); + private void FilterItems(string key) + { + //至少输入三个字符 避免删除或输入时界面变卡 + if (string.IsNullOrEmpty(key) || key.Length < 3) + { + Items.Clear(); + return; + } + key = key.ToUpper(); + Items.CanNotify = false; + Items.Clear(); + foreach (var matCode in matCodes) + { + if (matCode.MatCode.ToUpper().Contains(key)) + { + Items.Add(matCode); + } + } + Items.CanNotify = true; + } + public class DataModel() + { + public string MatCode { get; set; } + } + + /// + /// 物料名称 + /// + private string matName; + public string MatName + { + get { return matName; } + set + { + SetProperty(ref matName, value); + } + } + + /// + /// 物料批次 + /// + private string matBatch; + public string MatBatch + { + get { return matBatch; } + set + { + SetProperty(ref matBatch, value); + } + } + + + + /// + /// 库位 + /// + private string storeCode; + public string StoreCode + { + get { return storeCode; } + set + { + SetProperty(ref storeCode, value); + } + } + + /// + /// 物料条码 + /// + private string matSN; + public string MatSN + { + get { return matSN; } + set + { + SetProperty(ref matSN, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + MatCode = string.Empty; + MatName = string.Empty; + MatSN = string.Empty; + StoreCode = string.Empty; + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetMatInventoryDetailRequest() + { + MatName = MatName, + MatSN = MatSN, + MatBatch = MatBatch, + MatCode = MatCode, + StoreCode = StoreCode, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "matInventoryDetail/getMatInventoryDetail", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + } + + public ICommand BtnExportCommand { get => new DelegateCommand(BtnExport); } + public async void BtnExport() + { + try + { + #region 选择文件保存路径 + Microsoft.Win32.SaveFileDialog sfd = new Microsoft.Win32.SaveFileDialog(); + sfd.Filter = ".xlsx文件(*.xlsx)|*.xlsx"; + sfd.FileName = "库存数据" + DateTime.Now.ToString("yyyyMMddhhmmss"); + sfd.OverwritePrompt = true; + if (sfd.ShowDialog() != true) + { + return; + } + string path = sfd.FileName; + #endregion + + #region 调用接口导出数据 + var body = new GetMatInventoryDetailRequest() + { + MatName = MatName, + MatSN = MatSN, + MatBatch = MatBatch, + MatCode = MatCode, + StoreCode = StoreCode, + + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + await ApiHelp.PostDownloadFileAsync(path, System.Net.Http.HttpMethod.Post, LocalFile.Config.ApiIpHost + "matInventoryDetail/exportMatInventoryDetail", body); + Growl.Success("导出成功!"); + #endregion + } + catch (Exception ex) + { + Growl.Error("导出失败:" + ex.Message); + } + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/OutputStatChartViewModel.cs b/货架标准上位机/ViewModels/OutputStatChartViewModel.cs new file mode 100644 index 0000000..9814e50 --- /dev/null +++ b/货架标准上位机/ViewModels/OutputStatChartViewModel.cs @@ -0,0 +1,173 @@ +using LiveCharts; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace 货架标准上位机.ViewModel +{ + public class OutputStatChartViewModel : BindableBase + { + public OutputStatChartViewModel() + { + Values1.CollectionChanged += Values_CollectionChanged; + Values2.CollectionChanged += Values_CollectionChanged; + } + + void Values_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + IsZero = (Values1[0] + Values2[0]) == 0; + } + + //本地保存路径 + public static readonly string DailyStatisticsPath = System.IO.Path.Combine(LocalFile.DataDir, "outputStat"); + //文件锁 + static object lockObject = new object(); + + #region 图表 + public ChartValues Values1 { get; set; } = new ChartValues() { 10 }; + public ChartValues Values2 { get; set; } = new ChartValues() { 2 }; + public Func PointLabel { get; set; } = value => $"{value.Y}"; + #endregion + + private string Title_ = "当日生产统计"; + /// + /// 标题 + /// + public string Title { get => Title_; set { SetProperty(ref Title_, value); } } + + private bool IsZero_ = true; + /// + /// 是否为0 + /// + public bool IsZero { get => IsZero_; set { SetProperty(ref IsZero_, value); } } + + private DateTime? StartTime_ = null; + /// + /// 开始时间 + /// + public DateTime? StartTime + { + get => StartTime_; + set + { + StartTime_ = value; + Title = !value.HasValue ? "当日生产统计" : value.Value == DateTime.Now.Date ? "当日生产统计" : $"生产统计({value.Value.ToString(@"yyyy/MM/dd")})"; + } + } + + public void AddOkNg(int okNum, int ngNum) + { + if (okNum < 1 && ngNum < 1) + return; + + if (StartTime == null) + return; + + //重新计算 + if (StartTime.Value.Date != DateTime.Now.Date) + Reset(); + + if (okNum > 0) + Values1[0] = Values1[0] + okNum; + if (ngNum > 0) + Values2[0] = Values2[0] + ngNum; + + SaveData(); + } + + public void AddOk(int num = 1) + { + if (num < 1) + return; + + if (StartTime == null) + return; + + //重新计算 + if (StartTime.Value.Date != DateTime.Now.Date) + Reset(); + + Values1[0] = Values1[0] + num; + SaveData(); + } + + public void AddNg(int num = 1) + { + if (num < 1) + return; + + if (StartTime == null) + return; + + //重新计算 + if (StartTime.Value.Date != DateTime.Now.Date) + Reset(); + + Values2[0] = Values2[0] + num; + SaveData(); + } + + public void UpdataData() + { + try + { + if (!File.Exists(DailyStatisticsPath)) + { + Values1[0] = 0; + Values2[0] = 0; + StartTime = DateTime.Now.Date; + } + else + { + JObject? jo; + lock (lockObject) + jo = JsonConvert.DeserializeObject(File.ReadAllText(DailyStatisticsPath, Encoding.UTF8)); + + if (jo == null) + { + Values1[0] = 0; + Values2[0] = 0; + StartTime = DateTime.Now.Date; + } + else + { + Values1[0] = jo.Value("ok"); + Values2[0] = jo.Value("ng"); + StartTime = jo.Value("dt"); + } + } + } + catch (Exception) + { + + } + } + + public void SaveData() + { + try + { + var data = new { ok = Values1[0], ng = Values2[0], dt = StartTime }; + lock (lockObject) + File.WriteAllText(DailyStatisticsPath, JsonConvert.SerializeObject(data), Encoding.UTF8); + } + catch (Exception) + { + + } + } + + public void Reset() + { + Values1[0] = 0; + Values2[0] = 0; + StartTime = DateTime.Now.Date; + } + } +} diff --git a/货架标准上位机/ViewModels/RoleEditTreeViewModel.cs b/货架标准上位机/ViewModels/RoleEditTreeViewModel.cs new file mode 100644 index 0000000..e405199 --- /dev/null +++ b/货架标准上位机/ViewModels/RoleEditTreeViewModel.cs @@ -0,0 +1,126 @@ +using HandyControl.Controls; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using WCS.Model; + +namespace 货架标准上位机.ViewModel +{ + //https://dandelioncloud.cn/article/details/1472765022102446082 + public class RoleEditTreeViewModel : BindableBase, ITreeNode + { + private bool IsSelect_; + /// + /// 是否选择 + /// + public bool IsSelect { get => IsSelect_; set { SetProperty(ref IsSelect_, value); Linkage(value); } } + + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 主键Id + /// + public object Id { get; set; } + /// + /// 父Id + /// + public object Pid { get; set; } + + /// + /// 父级 + /// + public RoleEditTreeViewModel Parent { get; set; } + + /// + /// 子级 + /// + public List Children { get; set; } + + /// + /// 联动 + /// + public void Linkage(bool newbool) + { + //父级增加联动 + if (newbool && Parent != null) + Parent.IsSelect = true; + + //子级联动 + if (!newbool && Children != null) + foreach (var item in Children) + item.IsSelect = false; + } + + /// + /// 得到数据 + /// + /// 选中的值 + /// + public static List GetTreeViewModel(List select) + { + //值,名称,父级,子级 + List>> quan = new List>>(); + List vmodel = new List(); + + //1:解析枚举 + { + Type type = typeof(AuthEnum); + var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public) ?? new FieldInfo[] { }; + foreach (var field in fields) + { + var attr = field.GetCustomAttribute(false); + var attr1 = field.GetCustomAttribute(false); + + var v0 = Convert.ToInt32(field.GetRawConstantValue()); + var v1 = attr1 == null ? field.Name : attr1.Description; + var v2 = (int?)attr?.Parent; + var v3 = attr?.Childs?.Select(o => (int)o)?.ToList(); + quan.Add(new Tuple>(v0, v1, v2, (v3 ?? new List()))); + } + } + + //2:翻译数据 + { + vmodel.AddRange(quan.Select(o => new RoleEditTreeViewModel() + { + Id = o.Item1, + Name = o.Item2, + Pid = 0, + IsSelect = select?.Contains(o.Item1) ?? false, + })); + + //父子 + foreach (var item in vmodel) + { + var f = quan.FirstOrDefault(o => o.Item1 == (int)item.Id)?.Item3; + if (f.HasValue) + { + item.Parent = vmodel.FirstOrDefault(o => (int)o.Id == f.Value); + item.Pid = item.Parent.Id; + } + + var ff = quan.FirstOrDefault(o => o.Item1 == (int)item.Id)?.Item4; + if (ff != null && ff.Any()) + { + foreach (var item2 in ff) + { + vmodel.FirstOrDefault(o => (int)o.Id == item2).Parent = item; + vmodel.FirstOrDefault(o => (int)o.Id == item2).Pid = item.Id; + } + } + } + } + + //3:数据转为树对象 + vmodel = vmodel.ToTree(); + return vmodel; + } + } +} diff --git a/货架标准上位机/ViewModels/RoleViewModel.cs b/货架标准上位机/ViewModels/RoleViewModel.cs new file mode 100644 index 0000000..b2a83b9 --- /dev/null +++ b/货架标准上位机/ViewModels/RoleViewModel.cs @@ -0,0 +1,147 @@ +using HandyControl.Controls; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Input; +using SqlSugar; +using WCS.Model.ApiModel; +using HandyControl.Tools.Extension; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; + +namespace 货架标准上位机.ViewModel +{ + public class RoleViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 筛选 + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + #endregion + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public void UpdateList() + { + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetUsersRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Info = Info1, + }; + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "user/getRoles", body, "POST"); + if (Result != null && Result.Data != null) + { + DataList = Result.Data; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + public void See(RoleModel obj) + { + RoleEditView.Show(obj, CrudEnum.Read); + } + + public ICommand AddCommand { get => new DelegateCommand(Add); } + public void Add() + { + var isUp = RoleEditView.Show(new RoleModel(), CrudEnum.Create); + if (isUp) + { + UpdateList(); + Growl.Success("创建成功"); + } + } + + public ICommand UpdateCommand { get => new DelegateCommand(Update); } + public void Update(RoleModel obj) + { + var isUp = RoleEditView.Show(obj, CrudEnum.Update); + if (isUp) + { + UpdateList(); + Growl.Success("更新成功"); + } + } + + + public ICommand DelCommand { get => new DelegateCommand(Del); } + public void Del(RoleModel obj) + { + Growl.Ask($"是否删除角色[{obj.Name}]!", isConfirmed => + { + if (isConfirmed) + { + //try + //{ + // //var isContains = AuthDb1.db.Queryable().Select(o => o.RoleIds).ToList().SelectMany(o => o).Contains(obj.Id); + // //if (isContains) + // //{ + // // Growl.Info($"此角色被用户使用中,无法删除"); + // // return true; + // //} + + // //AuthDb1.db.Deleteable(obj).ExecuteCommand(); + //} + //catch (Exception ex) + //{ + // Growl.Error($"删除失败:{ex.ToString()}"); + // return true; + //} + + try + { + var body = new AddRoleRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Role = obj, + AddOrUpdate = AddOrUpdate.Delete, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addRole", body, "POST"); + if (Result.Code == 200) + { + Growl.Success("删除成功"); + UpdateList(); + return true; + } + else + { + Growl.Error(Result?.Message); + return true; + } + } + catch (Exception ex) + { + Growl.Error($"删除失败:{ex.ToString()}"); + return true; + } + } + else + return true; + }); + } + } +} diff --git a/货架标准上位机/ViewModels/SetViewModel.cs b/货架标准上位机/ViewModels/SetViewModel.cs new file mode 100644 index 0000000..ee16e23 --- /dev/null +++ b/货架标准上位机/ViewModels/SetViewModel.cs @@ -0,0 +1,219 @@ +using HandyControl.Controls; +using Microsoft.Win32; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Documents; +using System.Windows.Input; + +namespace 货架标准上位机.ViewModel +{ + public class SetViewModel : BindableBase + { + private List SaveLoginCountData_ = new List { 3, 5, 7, 10 }; + //记忆最大数量下拉框 + public List SaveLoginCountData { get => SaveLoginCountData_; set { SetProperty(ref SaveLoginCountData_, value); } } + + private Dictionary LogTimeData_ = new Dictionary() + { + { 30,"一月"},{ 91,"三月"},{ 182,"半年"},{ 365,"一年"},{ 1095,"三年"},{ -1,"永久"}, + }; + //日志缓存时间下拉框 + public Dictionary LogTimeData { get => LogTimeData_; set { SetProperty(ref LogTimeData_, value); } } + + + #region 页面输入信息 + private List scannerComList; + public List ScannerComList + { + get { return scannerComList; } + set + { + SetProperty(ref scannerComList, value); + } + } + + private string selectedScannerCom; + public string SelectedScannerCom + { + get { return selectedScannerCom; } + set + { + SetProperty(ref selectedScannerCom, value); + } + } + + + private List comList; + public List COMList + { + get { return comList; } + set + { + SetProperty(ref comList, value); + } + } + + private string selectedCOM; + public string SelectedCOM + { + get { return selectedCOM; } + set + { + SetProperty(ref selectedCOM, value); + } + } + + + + + private bool Powerboot_; + public bool Powerboot { get => Powerboot_; set { SetProperty(ref Powerboot_, value); } } + + private bool StartupFull_; + public bool StartupFull { get => StartupFull_; set { SetProperty(ref StartupFull_, value); } } + + private bool IsSaveLogin_; + public bool IsSaveLogin { get => IsSaveLogin_; set { SetProperty(ref IsSaveLogin_, value); } } + + private int SaveLoginCount_; + public int SaveLoginCount { get => SaveLoginCount_; set { SetProperty(ref SaveLoginCount_, value); } } + + private int SaveLogDay_; + public int SaveLogDay { get => SaveLogDay_; set { SetProperty(ref SaveLogDay_, value); } } + #endregion + + /// + /// 刷新界面 + /// + public void Update() + { + #region 加载配置项 + try + { + LocalFile.UpdateConfig(); + ScannerComList = LocalFile.Config.ScannerComList; + Powerboot = LocalFile.Config.Sys.Powerboot; + StartupFull = LocalFile.Config.Sys.StartupFull; + IsSaveLogin = LocalFile.Config.Sys.IsSaveLogin; + SaveLoginCount = LocalFile.Config.Sys.SaveLoginCount; + SaveLogDay = LocalFile.Config.Sys.SaveLogDay; + } + catch (Exception ex) + { + Growl.Info($"获取配置失败。{ex.Message}"); + } + #endregion + + #region 加载串口列表 + RefreshCOMList(); + #endregion + } + + public ICommand SaveCommand { get => new DelegateCommand(Save); } + /// + /// 保存 + /// + public void Save() + { + try + { + LocalFile.Config.Sys.Powerboot = Powerboot; + LocalFile.Config.Sys.StartupFull = StartupFull; + LocalFile.Config.Sys.IsSaveLogin = IsSaveLogin; + LocalFile.Config.Sys.SaveLoginCount = SaveLoginCount; + LocalFile.Config.Sys.SaveLogDay = SaveLogDay; + LocalFile.Config.ScannerComList = ScannerComList; + LocalFile.SaveConfig(); + Growl.Success($"保存成功。"); + + RunPowerboot(Powerboot); + } + catch (Exception ex) + { + LocalFile.UpdateConfig(); + Growl.Error($"保存失败。{ex.Message}"); + } + } + + private void RunPowerboot(bool isPowerboot) + { + try + { + if (isPowerboot) + { + RegistryKey rgkRun = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); + if (rgkRun == null) + rgkRun = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + + rgkRun.SetValue(Path.GetFileNameWithoutExtension(LocalFile.AppName), "\"" + Path.Combine(LocalFile.AppDir, LocalFile.AppName) + "\""); + } + else + { + RegistryKey rgkRun = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); + if (rgkRun == null) + rgkRun = Registry.LocalMachine.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"); + + rgkRun.DeleteValue(Path.GetFileNameWithoutExtension(LocalFile.AppName), false); + } + } + catch (Exception ex) + { + Logs.Write(ex); + } + } + + + public ICommand AddCOMCommand { get => new DelegateCommand(AddCOM); } + public void AddCOM() + { + //是否已选择COM号 + if (SelectedCOM == null) + { + Growl.Warning("请选择串口!"); + return; + } + //列表中是否存在 + var isExsist = ScannerComList.Where(t => t == SelectedCOM).Any(); + if (isExsist) + { + Growl.Warning($"已存在扫码枪{SelectedCOM}!"); + return; + } + //添加 + ScannerComList.Add(SelectedCOM); + ScannerComList = ScannerComList.ToList(); + } + + public ICommand DeleteCOMCommand { get => new DelegateCommand(DeleteCOM); } + public void DeleteCOM() + { + //是否已选择COM号 + if (SelectedScannerCom == null) + { + Growl.Warning("请在下方选择串口!"); + return; + } + + ScannerComList.RemoveAll(t => t == SelectedScannerCom); + ScannerComList = ScannerComList.ToList(); + } + + public ICommand RefreshCOMListCommand { get => new DelegateCommand(RefreshCOMList); } + public void RefreshCOMList() + { + try + { + COMList = SerialPort.GetPortNames().ToList(); + } + catch + { + } + } + } +} diff --git a/货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs b/货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs new file mode 100644 index 0000000..a5b8063 --- /dev/null +++ b/货架标准上位机/ViewModels/ShelfInfoAddOrUpdateViewModel.cs @@ -0,0 +1,170 @@ +using Ping9719.WpfEx.Mvvm; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using WCS.Model; +using WCS.Model.ApiModel.Home; +using WCS.Model.ApiModel.StoreInfo; +using 货架标准上位机.Tool; + +namespace 货架标准上位机.ViewModel +{ + public class ShelfInfoAddOrUpdateViewModel : BindableBase + { + #region Property 属性 + public ShelfInfoAddOrUpdateViewModel() + { + ShelfTypeItems = GetBaseData.GetShelfType(); + if (ShelfTypeItems != null && ShelfTypeItems.Count > 0) + SelectedShelfTypeItem = ShelfTypeItems.First(); + } + + public void SetValues(ShelfInfoModel shelfInfoModel) + { + if (shelfInfoModel != null) + { + ShelfId = shelfInfoModel.Id; + SelectedShelfTypeItem = shelfTypeItems.First(t => t.Id == shelfInfoModel.ShelfTypeId); + ShelfCode = shelfInfoModel.ShelfCode; + RowCounts = shelfInfoModel.Rowcounts; + ColumnCounts = shelfInfoModel.Columncounts; + LightId = shelfInfoModel.LightId; + ClientIp = shelfInfoModel.ClientIp; + GroupName = shelfInfoModel.GroupName; + IsBind = shelfInfoModel.IsBind; + BindShelfCode = shelfInfoModel.BindShelfCode; + } + } + + public ShelfInfoModel GetValues() + { + return new ShelfInfoModel() + { + Id = ShelfId, + ShelfTypeId = SelectedShelfTypeItem.Id, + ShelfTypeName = SelectedShelfTypeItem.ShelfTypeName, + ShelfCode = ShelfCode, + Rowcounts = RowCounts, + Columncounts = ColumnCounts, + LightId = LightId, + ClientIp = ClientIp, + GroupName = GroupName, + IsBind = IsBind, + BindShelfCode = BindShelfCode, + }; + } + + private int shelfId; + public int ShelfId + { + get { return shelfId; } + set + { + SetProperty(ref shelfId, value); + } + } + + + private List shelfTypeItems; + public List ShelfTypeItems + { + get { return shelfTypeItems; } + set + { + SetProperty(ref shelfTypeItems, value); + } + } + + private ShelfTypeModel selectedShelfTypeItem; + public ShelfTypeModel SelectedShelfTypeItem + { + get { return selectedShelfTypeItem; } + set + { + SetProperty(ref selectedShelfTypeItem, value); + } + } + + private string shelfCode; + public string ShelfCode + { + get { return shelfCode; } + set + { + SetProperty(ref shelfCode, value); + } + } + + private int rowCounts; + public int RowCounts + { + get { return rowCounts; } + set + { + SetProperty(ref rowCounts, value); + } + } + + private int columnCounts; + public int ColumnCounts + { + get { return columnCounts; } + set + { + SetProperty(ref columnCounts, value); + } + } + + private int lightId; + public int LightId + { + get { return lightId; } + set + { + SetProperty(ref lightId, value); + } + } + + private string clientIp; + public string ClientIp + { + get { return clientIp; } + set + { + SetProperty(ref clientIp, value); + } + } + + private string groupName; + public string GroupName + { + get { return groupName; } + set + { + SetProperty(ref groupName, value); + } + } + + private bool isBind; + public bool IsBind + { + get { return isBind; } + set + { + SetProperty(ref isBind, value); + } + } + + private string bindShelfCode; + public string BindShelfCode + { + get { return bindShelfCode; } + set + { + SetProperty(ref bindShelfCode, value); + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/ShelfInfoViewModel.cs b/货架标准上位机/ViewModels/ShelfInfoViewModel.cs new file mode 100644 index 0000000..5fffe2e --- /dev/null +++ b/货架标准上位机/ViewModels/ShelfInfoViewModel.cs @@ -0,0 +1,287 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using 货架标准上位机.Views.Controls; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel.Home; +using WCS.Model.ApiModel.StoreInfo; +using WCS.BLL.DbModels; +using WCS.Model.ApiModel.MatBaseInfo; +using WCS.Model.ApiModel.User; +using WCS.Model.ApiModel; +using Newtonsoft.Json.Bson; + +namespace 货架标准上位机.ViewModel +{ + public class ShelfInfoViewModel : BindableBase + { + public ShelfInfoViewModel() + { + + } + + #region Property + private List dataGridItemSource; + public List DataGridItemSource + { + get { return dataGridItemSource; } + set + { + SetProperty(ref dataGridItemSource, value); + } + } + + private ShelfInfoModel selectedataGridItem; + public ShelfInfoModel SelectedataGridItem + { + get { return selectedataGridItem; } + set + { + SetProperty(ref selectedataGridItem, value); + } + } + + + /// + /// 物料批次 + /// + private string shelfCode; + public string ShelfCode + { + get { return shelfCode; } + set + { + SetProperty(ref shelfCode, value); + } + } + + private List shelfTypeItems; + public List ShelfTypeItems + { + get { return shelfTypeItems; } + set + { + SetProperty(ref shelfTypeItems, value); + } + } + public void InitShelfTypeItems() + { + //调用接口更新! + Task.Run(() => + { + var body = new RequestBase() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + }; + + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "home/getShelfTypes", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists.Count() > 0) + { + ShelfTypeItems = Result.Data.Lists; + } + }); + } + + private ShelfTypeModel selectedShelfTypeItem; + public ShelfTypeModel SelectedShelfTypeItem + { + get { return selectedShelfTypeItem; } + set + { + SetProperty(ref selectedShelfTypeItem, value); + } + } + #endregion + + #region Command + public ICommand BtnResetCommand { get => new DelegateCommand(BtnReset); } + public void BtnReset() + { + SelectedShelfTypeItem = null; + ShelfCode = string.Empty; + } + + public ICommand BtnSearchCommand { get => new DelegateCommand(BtnSearchReset); } + public void BtnSearchReset() + { + BtnSearch(true); + } + + public void BtnSearch(bool IsPageReset = true) + { + if (CurrentPage == 0 || IsPageReset) + { + CurrentPage = 1; + return; + } + #region 调用接口获取数据 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetShelvesRequest() + { + ShelfTypeId = SelectedShelfTypeItem == null ? 0 : SelectedShelfTypeItem.Id, + ShelfCode = ShelfCode, + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + PageNumber = CurrentPage, + PageSize = 10, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "storeInfo/getShelves", body, "POST"); + if (Result != null && Result.Data != null && Result.Data.Lists != null) + { + DataGridItemSource = Result.Data.Lists; + MaxPage = Result.Data.MaxPage; + TotalCount = Result.Data.TotalCount; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + #endregion + } + + /// + /// 物料新增操作 + /// + public ICommand BtnAddCommand { get => new DelegateCommand(BtnAdd); } + public async void BtnAdd() + { + var addView = new ShelfInfoAddOrUpdateView("新增货架"); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + //添加或修改成功后重新查询 + CurrentPage = 1; + } + } + + public ICommand BtnEditCommand { get => new DelegateCommand(BtnEdit); } + public async void BtnEdit() + { + //查询勾选的第一个数据 + var shelfInfo = DataGridItemSource?.Where(t => t.IsSelected == true).FirstOrDefault(); + if (shelfInfo == null) + { + Growl.Warning("请选择需要修改的数据!"); + } + else + { + var addView = new ShelfInfoAddOrUpdateView("修改货架", shelfInfo); + addView.ShowDialog(); + if (addView.DialogResult == true) + { + CurrentPage = 1; + } + } + } + + public ICommand BtnDeleteCommand { get => new DelegateCommand(BtnDelete); } + public void BtnDelete() + { + //查询勾选的第一个数据 + var shelfInfo = DataGridItemSource?.Where(t => t.IsSelected == true).FirstOrDefault(); + if (shelfInfo == null) + { + Growl.Warning("请选择需要删除的数据!"); + } + else + { + var body = new AddShelfInfoRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + ShelfInfo = shelfInfo, + AddOrUpdate = AddOrUpdate.Delete + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "storeInfo/addOrUpdateShelfInfo", body, "POST"); + if (Result != null && Result.Code == 200) + { + Growl.Success("删除成功!"); + CurrentPage = 1; + } + else + { + Growl.Error($"{Result?.Message?.ToString()}"); + } + } + } + #endregion + + #region PageOperation 分页操作 + private int currentPage; + public int CurrentPage + { + get { return currentPage; } + set + { + SetProperty(ref currentPage, value); + BtnSearch(false); + } + } + + private int maxPage; + public int MaxPage + { + get { return maxPage; } + set { SetProperty(ref maxPage, value); } + } + + //总数量 + private int totalCount; + public int TotalCount + { + get { return totalCount; } + set { SetProperty(ref totalCount, value); } + } + + public ICommand BtnFirstPageCommand { get => new DelegateCommand(BtnFirstPage); } + public void BtnFirstPage() + { + CurrentPage = 1; + } + + public ICommand BtnPrePageCommand { get => new DelegateCommand(BtnPrePage); } + public void BtnPrePage() + { + if (CurrentPage > 1) + { + CurrentPage--; + } + } + + public ICommand BtnNextPageCommand { get => new DelegateCommand(BtnNextPage); } + public void BtnNextPage() + { + if (CurrentPage < MaxPage) + { + CurrentPage++; + } + } + + public ICommand BtnLastPageCommand { get => new DelegateCommand(BtnLastPage); } + public void BtnLastPage() + { + if (CurrentPage != MaxPage) + { + CurrentPage = MaxPage; + } + } + #endregion + } +} diff --git a/货架标准上位机/ViewModels/UserInfoViewModel.cs b/货架标准上位机/ViewModels/UserInfoViewModel.cs new file mode 100644 index 0000000..df9cc4c --- /dev/null +++ b/货架标准上位机/ViewModels/UserInfoViewModel.cs @@ -0,0 +1,44 @@ +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + public class UserInfoViewModel : BindableBase + { + private bool isLogin = false; + /// + /// 是否登录 + /// + public bool IsLogin { get => isLogin; set { SetProperty(ref isLogin, value); } } + + private string LoginName_; + /// + /// 登录名 + /// + public string LoginName { get => LoginName_; set { SetProperty(ref LoginName_, value); } } + + private object Auth_; + /// + /// 权限变化通知 + /// + public object Auth { get => Auth_; set { SetProperty(ref Auth_, value); } } + + private UserModel User_; + /// + /// 用户 + /// + public UserModel User { get => User_; set { SetProperty(ref User_, value); LoginName = value?.LoginName ?? null; } } + + private List Roles_; + /// + /// 角色 + /// + public List Roles { get => Roles_; set { SetProperty(ref Roles_, value); Auth = new object(); } } + + } +} diff --git a/货架标准上位机/ViewModels/UserViewModel.cs b/货架标准上位机/ViewModels/UserViewModel.cs new file mode 100644 index 0000000..a85c1ab --- /dev/null +++ b/货架标准上位机/ViewModels/UserViewModel.cs @@ -0,0 +1,137 @@ +using HandyControl.Controls; +using MiniExcelLibs; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using System.Windows.Media; +using SqlSugar; +using HandyControl.Data; +using System.Windows; +using Newtonsoft.Json.Linq; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using WCS.Model.ApiModel; + +namespace 货架标准上位机.ViewModel +{ + public class UserViewModel : BindableBase + { + private List dataList = new List(); + /// + /// 列表数据 + /// + public List DataList { get => dataList; set { SetProperty(ref dataList, value); } } + + #region 筛选 + private string info1; + public string Info1 { get => info1; set { SetProperty(ref info1, value); } } + #endregion + + public ICommand UpdateListCommand { get => new DelegateCommand(UpdateList); } + /// + /// 更新信息 + /// + public void UpdateList() + { + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetUsersRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Info = Info1, + }; + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "user/getUsers", body, "POST"); + if (Result != null && Result.Data != null) + { + DataList = Result.Data; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + } + + public ICommand SeeCommand { get => new DelegateCommand(See); } + public void See(UserModel obj) + { + UserEditView.Show(obj, CrudEnum.Read); + } + + public ICommand AddCommand { get => new DelegateCommand(Add); } + public void Add() + { + var isUp = UserEditView.Show(new UserModel(), CrudEnum.Create); + if (isUp) + { + UpdateList(); + Growl.Success("创建成功"); + } + } + + public ICommand UpdateCommand { get => new DelegateCommand(Update); } + public void Update(UserModel obj) + { + var isUp = UserEditView.Show(obj, CrudEnum.Update); + if (isUp) + { + UpdateList(); + Growl.Success("更新成功"); + } + } + + + public ICommand DelCommand { get => new DelegateCommand(Del); } + public void Del(UserModel obj) + { + Growl.Ask($"是否删除用户[{obj.LoginName}]!", isConfirmed => + { + if (isConfirmed) + { + try + { + var body = new AddUserRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + User = obj, + AddOrUpdate = AddOrUpdate.Delete + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addUser", body, "POST"); + if (Result != null && Result.Code == 200) + { + UpdateList(); + Growl.Success("删除成功"); + } + else + { + Growl.Error($"删除失败:{Result.Message.ToString()}"); + } + + } + catch (Exception ex) + { + Growl.Error($"删除失败:{ex.ToString()}"); + return true; + } + + } + return true; + }); + } + } +} diff --git a/货架标准上位机/Views/Controls/DataChartView.xaml b/货架标准上位机/Views/Controls/DataChartView.xaml new file mode 100644 index 0000000..8fae814 --- /dev/null +++ b/货架标准上位机/Views/Controls/DataChartView.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/DataChartView.xaml.cs b/货架标准上位机/Views/Controls/DataChartView.xaml.cs new file mode 100644 index 0000000..96caba0 --- /dev/null +++ b/货架标准上位机/Views/Controls/DataChartView.xaml.cs @@ -0,0 +1,44 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using Ping9719.WpfEx; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace 货架标准上位机 +{ + /// + /// 数据图表 + /// + public partial class DataChartView : UserControlBase + { + DataChartViewModel viewModel = new DataChartViewModel(); + public DataChartView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + //第一次加载 + private void loadFirst(object sender, EventArgs e) + { + if (IsInDesignMode) + return; + + viewModel.UpdataYear(); + } + } +} diff --git a/货架标准上位机/Views/Controls/DataListView.xaml b/货架标准上位机/Views/Controls/DataListView.xaml new file mode 100644 index 0000000..3377f9f --- /dev/null +++ b/货架标准上位机/Views/Controls/DataListView.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/DeviceView.xaml.cs b/货架标准上位机/Views/Controls/DeviceView.xaml.cs new file mode 100644 index 0000000..9bbf943 --- /dev/null +++ b/货架标准上位机/Views/Controls/DeviceView.xaml.cs @@ -0,0 +1,390 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace 货架标准上位机 +{ + /// + /// 设备手动信息 + /// + public partial class DeviceView : UserControlBase + { + DeviceViewModel viewModel = new DeviceViewModel(); + + public DeviceView() + { + InitializeComponent(); + //viewModel.plc = LocalStatic.Plc; + this.DataContext = viewModel; + } + + //第一次显示,渲染Ui + private void visfir(object sender, EventArgs e) + { + if (IsInDesignMode) + return; + + if (!System.IO.File.Exists(LocalFile.PlcDotPath)) + { + Growl.Info($"没有找到文档[{LocalFile.PlcDotPath}],请联系管理员。"); + return; + } + + //读Excel + viewModel.DataReads = ExcelDeviceReadModel.GetDatas(); + viewModel.DataWrites = ExcelDeviceWriteModel.GetDatas(); + viewModel.DataUrns = ExcelDeviceUrnModel.GetDatas(); + viewModel.DataServos = ExcelDeviceServoModel.GetDatas(); + + //加载页面 + ReadUi(viewModel.DataReads); + WriteUi(viewModel.DataWrites); + UrnUi(viewModel.DataUrns); + ServoUi(viewModel.DataServos); + + //展示限制 + viewModel.IsVisRead = viewModel.DataReads.Any(); + viewModel.IsVisWrite = viewModel.DataWrites.Any(); + viewModel.IsVisUrn = viewModel.DataUrns.Any(); + viewModel.IsVisServo = viewModel.DataServos.Any(); + + Task.Run(viewModel.WhileRead); + } + + private void vis(object sender, DependencyPropertyChangedEventArgs e) + { + if (IsInDesignMode) + return; + + viewModel.IsVis = (bool)e.NewValue; + } + + #region 渲染页面 + void ReadUi(IEnumerable data) + { + stackPanel1.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.Value = item.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + item.IsExpanded = true; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item.ExcelTag)}.{nameof(item.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + stackPanel1.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + item2.Value = item2.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item2; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item2.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item2.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item2.ExcelTag)}.{nameof(item2.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + expander.Content = wrapPanel; + stackPanel1.Children.Add(expander); + } + } + } + + void WriteUi(IEnumerable data) + { + if (true) + { + stackPanel2.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.Value = item.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + item.IsExpanded = true; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item; + iotState.Click += viewModel.WriteClick; + iotState.PreviewMouseLeftButtonDown += viewModel.LeftDown; + iotState.PreviewMouseLeftButtonUp += viewModel.LeftUp; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item.ExcelTag)}.{nameof(item.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + stackPanel2.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + item2.Value = item2.ExcelTag.类型.Trim().ToLower() == "bool" ? false : "-"; + + IotStateInfo iotState = new IotStateInfo(); + iotState.DataContext = item2; + iotState.Click += viewModel.WriteClick; + iotState.PreviewMouseLeftButtonDown += viewModel.LeftDown; + iotState.PreviewMouseLeftButtonUp += viewModel.LeftUp; + iotState.SetBinding(IotStateInfo.HeaderProperty, nameof(item2.Name)); + iotState.SetBinding(IotStateInfo.ValueProperty, nameof(item2.Value)); + iotState.SetBinding(IotStateInfo.PostfixProperty, $"{nameof(item2.ExcelTag)}.{nameof(item2.ExcelTag.单位)}"); + + wrapPanel.Children.Add(iotState); + } + expander.Content = wrapPanel; + stackPanel2.Children.Add(expander); + } + } + } + } + + void UrnUi(IEnumerable data) + { + if (true) + { + stackPanel3.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.IsExpanded = true; + + IotUrnMode iotUrn = new IotUrnMode(); + iotUrn.DataContext = item; + iotUrn.SetBinding(IotUrnMode.TextProperty, nameof(item.Name)); + iotUrn.SetBinding(IotUrnMode.IsButBadge1Property, nameof(item.IsGoTo)); + iotUrn.SetBinding(IotUrnMode.IsButBadge2Property, nameof(item.IsRetTo)); + iotUrn.Button1.Click += viewModel.Button1_Click; + iotUrn.Button1.PreviewMouseLeftButtonDown += viewModel.But1ClickDown; + iotUrn.Button1.PreviewMouseLeftButtonUp += viewModel.But1ClickUp; + iotUrn.Button2.Click += viewModel.Button2_Click; + iotUrn.Button2.PreviewMouseLeftButtonDown += viewModel.But2ClickDown; + iotUrn.Button2.PreviewMouseLeftButtonUp += viewModel.But2ClickUp; + + wrapPanel.Children.Add(iotUrn); + } + stackPanel3.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + IotUrnMode iotUrn = new IotUrnMode(); + iotUrn.DataContext = item2; + iotUrn.SetBinding(IotUrnMode.TextProperty, nameof(item2.Name)); + iotUrn.SetBinding(IotUrnMode.IsButBadge1Property, nameof(item2.IsGoTo)); + iotUrn.SetBinding(IotUrnMode.IsButBadge2Property, nameof(item2.IsRetTo)); + iotUrn.Button1.Click += viewModel.Button1_Click; + iotUrn.Button1.PreviewMouseLeftButtonDown += viewModel.But1ClickDown; + iotUrn.Button1.PreviewMouseLeftButtonUp += viewModel.But1ClickUp; + iotUrn.Button2.Click += viewModel.Button2_Click; + iotUrn.Button2.PreviewMouseLeftButtonDown += viewModel.But2ClickDown; + iotUrn.Button2.PreviewMouseLeftButtonUp += viewModel.But2ClickUp; + + wrapPanel.Children.Add(iotUrn); + } + expander.Content = wrapPanel; + stackPanel3.Children.Add(expander); + } + } + } + } + + void ServoUi(IEnumerable data) + { + if (true) + { + stackPanel4.Children.Clear(); + if (data == null || !data.Any()) + return; + + var moren = data.Where(o => string.IsNullOrWhiteSpace(o.ExcelTag.组名)); + var group = data.Where(o => !string.IsNullOrWhiteSpace(o.ExcelTag.组名)).GroupBy(o => o.ExcelTag.组名); + + if (moren.Any()) + { + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item in moren) + { + item.IsExpanded = true; + + IotServoMode iotServo = new IotServoMode(); + iotServo.DataContext = item; + iotServo.SetBinding(IotServoMode.TextProperty, nameof(item.Name)); + iotServo.SetBinding(IotServoMode.Speed1Property, nameof(item.JogSpeed)); + iotServo.SetBinding(IotServoMode.Speed2Property, nameof(item.AutoSpeed)); + iotServo.SetBinding(IotServoMode.LocationProperty, nameof(item.Location)); + iotServo.SetBinding(IotServoMode.IsVis1Property, new Binding(nameof(item.IsJog)) { Mode = BindingMode.TwoWay }); + iotServo.SetBinding(IotServoMode.IsFoldProperty, new Binding(nameof(item.IsFold)) { Mode = BindingMode.TwoWay }); + iotServo.LocationChange += viewModel.LocationChange; + iotServo.SpeedChange += viewModel.SpeedChange; + + wrapPanel.Children.Add(iotServo); + } + stackPanel4.Children.Add(wrapPanel); + } + if (group.Any()) + { + foreach (var item in group) + { + Expander expander = new Expander(); + expander.Header = item.Key; + expander.Tag = item; + expander.Expanded += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = true; + } + }; + expander.Collapsed += (s, e) => + { + var c = (IGrouping)((Expander)s).Tag; + foreach (var item in c) + { + item.IsExpanded = false; + } + }; + + WrapPanel wrapPanel = new WrapPanel(); + foreach (var item2 in item) + { + IotServoMode iotServo = new IotServoMode(); + iotServo.DataContext = item2; + iotServo.SetBinding(IotServoMode.TextProperty, nameof(item2.Name)); + iotServo.SetBinding(IotServoMode.Speed1Property, nameof(item2.JogSpeed)); + iotServo.SetBinding(IotServoMode.Speed2Property, nameof(item2.AutoSpeed)); + iotServo.SetBinding(IotServoMode.LocationProperty, nameof(item2.Location)); + iotServo.SetBinding(IotServoMode.IsVis1Property, new Binding(nameof(item2.IsJog)) { Mode = BindingMode.TwoWay }); + iotServo.SetBinding(IotServoMode.IsFoldProperty, new Binding(nameof(item2.IsFold)) { Mode = BindingMode.TwoWay }); + iotServo.LocationChange += viewModel.LocationChange; + iotServo.SpeedChange += viewModel.SpeedChange; + + wrapPanel.Children.Add(iotServo); + } + expander.Content = wrapPanel; + stackPanel4.Children.Add(expander); + } + } + } + } + #endregion + } +} diff --git a/货架标准上位机/Views/Controls/ImageListenerView.xaml b/货架标准上位机/Views/Controls/ImageListenerView.xaml new file mode 100644 index 0000000..f1f7ebb --- /dev/null +++ b/货架标准上位机/Views/Controls/ImageListenerView.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/ImageListenerView.xaml.cs b/货架标准上位机/Views/Controls/ImageListenerView.xaml.cs new file mode 100644 index 0000000..fd63653 --- /dev/null +++ b/货架标准上位机/Views/Controls/ImageListenerView.xaml.cs @@ -0,0 +1,236 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Path = System.IO.Path; + +namespace 货架标准上位机 +{ + /// + /// 图像监听。可针对文件夹文件进行监听显示 + /// + public partial class ImageListenerView : UserControl + { + ImageListenerViewModel viewModel = new ImageListenerViewModel(); + public FileSystemWatcher FileWatcher = new FileSystemWatcher(); + /// + /// 当前加载的图像路径 + /// + public string FullPath { get; private set; } + public ImageListenerView() + { + InitializeComponent(); + this.DataContext = viewModel; + + //拖动 + img.MouseLeftButtonDown += Img_MouseLeftButtonDown; + img.MouseLeftButtonUp += Img_MouseLeftButtonUp; + img.MouseMove += Img_MouseMove; + //鼠标滚轮 + this.MouseWheel += Img_MouseWheel; + //监听 + FileWatcher.Changed += FileSystemWatcher; + } + + /// + /// 如果在选项卡中,是否自动切换到当前变化的项来。默认为false + /// + public bool IsAutoActiveTabItem + { + get { return (bool)GetValue(IsAutoActiveTabItemProperty); } + set { SetValue(IsAutoActiveTabItemProperty, value); } + } + + public static readonly DependencyProperty IsAutoActiveTabItemProperty = + DependencyProperty.Register("IsAutoActiveTabItem", typeof(bool), typeof(ImageListenerView), new PropertyMetadata(false)); + + /// + /// 开始监听 + /// + /// 监听的目录或文件 + /// 对目录的筛选值(文件无效) + public void StartListener(string path, string filter = "*.jpg") + { + FileWatcher.EnableRaisingEvents = false; + + path = (path ?? "").Trim(); + if (string.IsNullOrEmpty(path)) + return; + + if (Path.HasExtension(path)) + { + var ext = Path.GetFileName(path); + if (!string.IsNullOrEmpty(ext)) + filter = ext; + + path = Path.GetDirectoryName(path); + } + + Directory.CreateDirectory(path); + + FileWatcher.Path = path; + FileWatcher.Filter = filter; + FileWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime | NotifyFilters.LastAccess; + FileWatcher.IncludeSubdirectories = false; + FileWatcher.EnableRaisingEvents = true; + } + + /// + /// 停止监听 + /// + public void StopListener() + { + FileWatcher.EnableRaisingEvents = false; + } + + string FullPathTop = string.Empty; + private void FileSystemWatcher(object sender, FileSystemEventArgs e) + { + if (FullPathTop == e.FullPath) + return; + + FullPathTop = e.FullPath; + + Thread.Sleep(400);//确保大图片的成功 + this.Dispatcher.BeginInvoke(new Action(() => + { + try + { + viewModel.ImageSource = null; + viewModel.ImageSource = BitmapFrame.Create(new Uri(e.FullPath), BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad); + viewModel.ImageHeight = viewModel.ImageSource.Height; + viewModel.ImageWidth = viewModel.ImageSource.Width; + + FullPath = e.FullPath; + viewModel.ImgAutoSize(); + + if (IsAutoActiveTabItem) + { + if (this.Parent is System.Windows.Controls.TabItem tabItem) + { + if (tabItem.Parent is System.Windows.Controls.TabControl tabControl) + { + tabControl.SelectedItem = tabItem; + } + } + } + } + catch (Exception) + { + } + finally + { + FullPathTop = string.Empty; + } + })); + } + + #region 变换 + private bool mouseLeftDown = false; + private Point mouseLeftXY; + + private void Img_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + mouseLeftDown = true; + mouseLeftXY = e.GetPosition((FrameworkElement)this); + } + + private void Img_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + mouseLeftDown = false; + } + + private void Img_MouseMove(object sender, MouseEventArgs e) + { + if (mouseLeftDown && e.LeftButton == MouseButtonState.Pressed) + { + var position = e.GetPosition((FrameworkElement)this); + viewModel.TranslateX -= mouseLeftXY.X - position.X; + viewModel.TranslateY -= mouseLeftXY.Y - position.Y; + mouseLeftXY = position; + } + } + + private void Img_MouseWheel(object sender, MouseWheelEventArgs e) + { + var delta = e.Delta * 0.001; + var scaleXY = viewModel.ScaleXY + delta; + if (scaleXY < 0.05 || scaleXY > 5) + return; + + viewModel.CenterX = img.ActualWidth / 2; + viewModel.CenterY = img.ActualHeight / 2; + + //校正 + var point = Mouse.GetPosition(img); + //图片外 + if (point.X < 0 || point.Y < 0 || point.X > img.ActualWidth || point.Y > img.ActualHeight) + { + //不需要校正 + } + else + { + var lx = img.ActualWidth / 2.00 - point.X; + var ly = img.ActualHeight / 2.00 - point.Y; + var pyx = lx * scaleXY - lx * viewModel.ScaleXY; + var pyy = ly * scaleXY - ly * viewModel.ScaleXY; + + viewModel.TranslateX += pyx; + viewModel.TranslateY += pyy; + } + + viewModel.ScaleXY = scaleXY; + } + #endregion + + #region 效果 + DateTime dtsj = DateTime.Now; + private void previewMouseDoubleClick(object sender, MouseButtonEventArgs e) + { + if ((DateTime.Now - dtsj).TotalMilliseconds <= 300) + { + if (e.ChangedButton == MouseButton.Left && !string.IsNullOrEmpty(FullPath)) + if (File.Exists(FullPath)) + new ImageBrowser(new Uri(FullPath)).Show(); + } + dtsj = DateTime.Now; + } + + private void ckyt(object sender, RoutedEventArgs e) + { + if (File.Exists(FullPath)) + new ImageBrowser(new Uri(FullPath)).Show(); + } + + private void syck(object sender, RoutedEventArgs e) + { + viewModel.ImgAutoSize(); + } + + private void ytdx(object sender, RoutedEventArgs e) + { + viewModel.ScaleXY = viewModel.ImageWidth / this.ActualWidth; + viewModel.CenterX = img.ActualWidth / 2; + viewModel.CenterY = img.ActualHeight / 2; + viewModel.TranslateX = 0; + viewModel.TranslateY = 0; + } + #endregion + + } +} diff --git a/货架标准上位机/Views/Controls/OutputStatChartView.xaml b/货架标准上位机/Views/Controls/OutputStatChartView.xaml new file mode 100644 index 0000000..f7849f2 --- /dev/null +++ b/货架标准上位机/Views/Controls/OutputStatChartView.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + 无数据 + + + + + + + + + diff --git a/货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs b/货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs new file mode 100644 index 0000000..a9feb84 --- /dev/null +++ b/货架标准上位机/Views/Controls/OutputStatChartView.xaml.cs @@ -0,0 +1,44 @@ +using LiveCharts.Wpf; +using LiveCharts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using 货架标准上位机.ViewModel; +using System.Runtime.InteropServices.ComTypes; +using Ping9719.WpfEx; + +namespace 货架标准上位机 +{ + /// + /// 日产量统计扇形图 + /// + public partial class OutputStatChartView : UserControlBase + { + public static OutputStatChartViewModel viewModel = new OutputStatChartViewModel(); + public OutputStatChartView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + private void loadFir(object sender, EventArgs e) + { + if (this.IsInDesignMode) + return; + + viewModel.UpdataData(); + } + + } +} diff --git a/货架标准上位机/Views/Controls/RoleView.xaml b/货架标准上位机/Views/Controls/RoleView.xaml new file mode 100644 index 0000000..c3858f4 --- /dev/null +++ b/货架标准上位机/Views/Controls/RoleView.xaml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 日志 + + + + + + + + + + + diff --git a/货架标准上位机/Views/HomeView.xaml.cs b/货架标准上位机/Views/HomeView.xaml.cs new file mode 100644 index 0000000..406f0e0 --- /dev/null +++ b/货架标准上位机/Views/HomeView.xaml.cs @@ -0,0 +1,44 @@ +using 货架标准上位机.ViewModel; +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using 货架标准上位机.Views.Controls; + +namespace 货架标准上位机 +{ + /// + /// 主页 + /// + public partial class HomeView : UserControlBase + { + HomeViewModel viewModel = new HomeViewModel(); + + public HomeView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + private void loadFir(object sender, EventArgs e) + { + viewModel.wrapPanel = shelfsWrapPanel; + if (this.IsInDesignMode) + return; + + viewModel.LoadTask(); + } + } +} diff --git a/货架标准上位机/Views/InInventoryView.xaml b/货架标准上位机/Views/InInventoryView.xaml new file mode 100644 index 0000000..789aec7 --- /dev/null +++ b/货架标准上位机/Views/InInventoryView.xaml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/InInventoryView.xaml.cs b/货架标准上位机/Views/InInventoryView.xaml.cs new file mode 100644 index 0000000..988aba8 --- /dev/null +++ b/货架标准上位机/Views/InInventoryView.xaml.cs @@ -0,0 +1,69 @@ +using Ping9719.WpfEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using 货架标准上位机.ViewModel; +using 货架标准上位机.Views.Controls; + +namespace 货架标准上位机 +{ + /// + /// InInventoryView.xaml 的交互逻辑 + /// + public partial class InInventoryView : UserControlBase + { + public InInventoryViewModel viewModel = new InInventoryViewModel(); + public InInventoryView() + { + InitializeComponent(); + this.DataContext = viewModel; + + + var scanners = ScannerManager.Scanners.Select(t => t).ToList(); + scanners.ForEach(t => + { + var control = new ScannerDisplayControl(t.COM); + t.ScannerDisplayControl = control; + scannersWrapPanel.Children.Add(control); + }); + } + + private void DataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e) + { + DataGrid datagrid = sender as DataGrid; + datagrid.UnselectAllCells(); + } + + private void UserControlBase_Loaded(object sender, RoutedEventArgs e) + { + + } + + private void Border_MouseUp(object sender, MouseButtonEventArgs e) + { + + } + + private void UserControlBase_LoadedVisibleFirst(object sender, EventArgs e) + { + if (IsInDesignMode) + return; + //viewModel.NewMethod(); + } + + private void UserControlBase_LoadedVisible(object sender, EventArgs e) + { + + } + } +} diff --git a/货架标准上位机/Views/InterfaceRecordView.xaml b/货架标准上位机/Views/InterfaceRecordView.xaml new file mode 100644 index 0000000..ae1ecff --- /dev/null +++ b/货架标准上位机/Views/InterfaceRecordView.xaml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 开机启动 + + 启动全屏 + + + + + + 登录记忆 + 在登录成功后会记住账号 + + + 记忆数量 + 在登录成功后记住的账号数量 + + + + + + + 日志缓存时间 + 在软件每次打开的时候会执行清理缓存 + + + + + + 文本框 + + + 文本框(带描述) + 我是描述 + + + 范围文本框 + 我是描述 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/RoleEditView.xaml.cs b/货架标准上位机/Views/Windows/RoleEditView.xaml.cs new file mode 100644 index 0000000..03df6a4 --- /dev/null +++ b/货架标准上位机/Views/Windows/RoleEditView.xaml.cs @@ -0,0 +1,176 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using HandyControl.Tools.Extension; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using MessageBox = HandyControl.Controls.MessageBox; +using Window = System.Windows.Window; +using WCS.Model.ApiModel; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; + +namespace 货架标准上位机 +{ + /// + /// 角色信息 + /// + public partial class RoleEditView : Window + { + public RoleEditView() + { + InitializeComponent(); + } + + /// + /// + /// + /// true:成功,false:取消 + public static bool Show(RoleModel roleBase, CrudEnum crudEnum) + { + bool isOk = false; + + Application.Current.Dispatcher.Invoke(new Action(() => + { + var view = new RoleEditView(); + List dataList = new List(); + + try + { + if (crudEnum == CrudEnum.Read) + view.qr.IsEnabled = false; + + view.textBox.Text = roleBase.Name; + dataList = RoleEditTreeViewModel.GetTreeViewModel(roleBase.Auths); + view.treeView.ItemsSource = dataList; + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + view = null; + return; + } + + view.qr.Click += (s, e) => + { + try + { + var treeNode = dataList.ToTreeNode(); + RoleModel newRole = new RoleModel() + { + Id = roleBase.Id, + IsAdmin = roleBase.IsAdmin, + Name = view.textBox.Text.Trim(), + Auths = treeNode.Where(o => o.IsSelect).Select(o => (int)o.Id).ToList(), + Time = roleBase.Time, + }; + if (crudEnum == CrudEnum.Update) + { + if (string.IsNullOrEmpty(newRole.Name)) + { + MessageBox.Show("请输入名称"); + return; + } + try + { + var body = new AddRoleRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Role = newRole, + AddOrUpdate = AddOrUpdate.Update + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addRole", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result?.Message); + } + } + catch (Exception ex) + { + Growl.Error("修改角色失败:" + ex.Message); + } + } + else if (crudEnum == CrudEnum.Create) + { + newRole.Id = 0; + newRole.Time = DateTime.Now; + + if (string.IsNullOrEmpty(newRole.Name)) + { + MessageBox.Show("请输入名称"); + return; + } + try + { + var body = new AddRoleRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Role = newRole, + AddOrUpdate = AddOrUpdate.Add, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addRole", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result?.Message); + } + } + catch (Exception ex) + { + Growl.Error("新增角色失败:" + ex.Message); + } + } + else + { + MessageBox.Show("不支持此操作"); + return; + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + return; + } + + //isOk = true; + //view.Close(); + }; + + view.ShowDialog(); + view = null; + })); + + return isOk; + } + + private void qx(object sender, RoutedEventArgs e) + { + this.Close(); + } + } +} diff --git a/货架标准上位机/Views/Windows/TipInputView.xaml b/货架标准上位机/Views/Windows/TipInputView.xaml new file mode 100644 index 0000000..3d78a35 --- /dev/null +++ b/货架标准上位机/Views/Windows/TipInputView.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/UserEditView.xaml.cs b/货架标准上位机/Views/Windows/UserEditView.xaml.cs new file mode 100644 index 0000000..dfdbb87 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserEditView.xaml.cs @@ -0,0 +1,219 @@ +using 货架标准上位机.ViewModel; +using HandyControl.Controls; +using HandyControl.Tools.Extension; +using Ping9719.WpfEx.Mvvm; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using MessageBox = HandyControl.Controls.MessageBox; +using Window = System.Windows.Window; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using WCS.Model; +using 货架标准上位机.Api; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 用户信息 + /// + public partial class UserEditView : Window + { + public UserEditView() + { + InitializeComponent(); + } + + /// + /// + /// + /// true:成功,false:取消 + public static bool Show(UserModel userBase, CrudEnum crudEnum) + { + bool isOk = false; + + var roleList = new List(); + //调用接口获取权限列表 + var dia = Dialog.Show(new TextDialog()); + try + { + var body = new GetUsersRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + Info = string.Empty, + }; + var Result = ApiHelp.GetDataFromHttp>>(LocalFile.Config.ApiIpHost + "user/getRoles", body, "POST"); + if (Result != null && Result.Data != null) + { + roleList = Result.Data; + } + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + dia.Close(); + } + + Application.Current.Dispatcher.Invoke(new Action(() => + { + var view = new UserEditView(); + + try + { + if (crudEnum == CrudEnum.Read) + view.qr.IsEnabled = false; + + var rs = roleList.Where(o => !o.IsAdmin).ToList(); + + view.textBox.Text = userBase.LoginName; + view.passwordBox.Password = userBase.Password; + view.checkComboBox.ItemsSource = rs; + view.checkComboBox.DisplayMemberPath = nameof(RoleModel.Name); + view.checkComboBox.SelectedValuePath = nameof(RoleModel.Id); + + //var aaa = rs.Where(o => userBase.RoleIds.Contains(o.Id)).ToList(); + //ListBoxAttach.SetSelectedItems(view.checkComboBox, aaa); + + foreach (var item in userBase.RoleIds) + { + var aaa = rs.FirstOrDefault(o => o.Id == item); + if (aaa != null) + view.checkComboBox.SelectedItems.Add(aaa); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + view = null; + return; + } + + view.qr.Click += (s, e) => + { + try + { + UserModel newuser = new UserModel() + { + Id = userBase.Id, + IsAdmin = userBase.IsAdmin, + LoginName = view.textBox.Text.Trim(), + Password = view.passwordBox.Password, + RoleIds = view.checkComboBox.SelectedItems.Cast().Select(o => o.Id).ToList(), + Time = userBase.Time, + }; + + if (crudEnum == CrudEnum.Update) + { + if (string.IsNullOrEmpty(newuser.LoginName)) + { + MessageBox.Show("请输入名称"); + return; + } + try + { + var body = new AddUserRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + User = newuser, + AddOrUpdate = AddOrUpdate.Update + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addUser", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result.Message); + } + } + catch (Exception ex) + { + Growl.Error("更新数据失败:" + ex.Message); + } + + } + else if (crudEnum == CrudEnum.Create) + { + newuser.Id = 0; + newuser.Time = DateTime.Now; + + if (string.IsNullOrEmpty(newuser.LoginName)) + { + MessageBox.Show("请输入名称"); + return; + } + + //调用接口获取权限列表 + try + { + var body = new AddUserRequest() + { + UserName = LocalStatic.CurrentUser, + DeviceType = LocalFile.Config.DeviceType, + User = newuser, + AddOrUpdate = AddOrUpdate.Add + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/addUser", body, "POST"); + if (Result != null && Result.Code == 200) + { + isOk = true; + view.Close(); + } + else + { + Growl.Error(Result.Message); + } + } + catch (Exception ex) + { + Growl.Error("新增用户失败:" + ex.Message); + } + } + else + { + MessageBox.Show("不支持此操作"); + return; + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + return; + } + //isOk = true; + //view.Close(); + }; + + view.ShowDialog(); + view = null; + })); + + return isOk; + } + + private void qx(object sender, RoutedEventArgs e) + { + this.Close(); + } + } +} diff --git a/货架标准上位机/Views/Windows/UserInfoView.xaml b/货架标准上位机/Views/Windows/UserInfoView.xaml new file mode 100644 index 0000000..cd899b1 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserInfoView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/UserInfoView.xaml.cs b/货架标准上位机/Views/Windows/UserInfoView.xaml.cs new file mode 100644 index 0000000..ab47d03 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserInfoView.xaml.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 用户信息 + /// + public partial class UserInfoView : Window + { + public static UserInfoViewModel viewModel = new UserInfoViewModel(); + + /// + /// 点击退出登录 + /// + public bool IsExitLogin = false; + public UserInfoView() + { + InitializeComponent(); + + this.DataContext = viewModel; + } + + private void tcdl(object sender, RoutedEventArgs e) + { + IsExitLogin = true; + viewModel.IsLogin = false; + viewModel.User = null; + viewModel.Roles = new List(); + this.Close(); + } + } +} diff --git a/货架标准上位机/Views/Windows/UserLoginView.xaml b/货架标准上位机/Views/Windows/UserLoginView.xaml new file mode 100644 index 0000000..ee3a181 --- /dev/null +++ b/货架标准上位机/Views/Windows/UserLoginView.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/货架标准上位机/Views/Windows/UserLoginView.xaml.cs b/货架标准上位机/Views/Windows/UserLoginView.xaml.cs new file mode 100644 index 0000000..11ac44d --- /dev/null +++ b/货架标准上位机/Views/Windows/UserLoginView.xaml.cs @@ -0,0 +1,173 @@ +using 货架标准上位机.ViewModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using HandyControl.Controls; +using 货架标准上位机.Views.Controls; +using WCS.Model.ApiModel.User; +using 货架标准上位机.Api; +using WCS.Model; +using Newtonsoft.Json; +using SqlSugar; +using WCS.Model.ApiModel; + +namespace 货架标准上位机 +{ + /// + /// 用户登录 + /// + public partial class UserLoginView : System.Windows.Window + { + UserInfoViewModel viewModel = UserInfoView.viewModel; + public UserLoginView() + { + InitializeComponent(); + this.DataContext = viewModel; + } + + private void load(object sender, RoutedEventArgs e) + { + //登录记忆 + if (LocalFile.Config.Sys.IsSaveLogin && LocalFile.Config.Sys.SaveLogin.Any()) + { + ComboBoxId.ItemsSource = LocalFile.Config.Sys.SaveLogin; + ComboBoxId.SelectedIndex = 0; + } + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + var loginName = ComboBoxId.Text.Trim(); + var pass = PasswordBoxPass.Password.ToString(); + + if (string.IsNullOrEmpty(loginName)) + { + HandyControl.Controls.MessageBox.Warning("请输入账号!", "提示"); + return; + } + if (string.IsNullOrEmpty(pass)) + { + HandyControl.Controls.MessageBox.Warning("请输入密码!", "提示"); + return; + } + + try + { + try + { + var body = new UserLoginRequest() + { + UserName = loginName, + DeviceType = LocalFile.Config.DeviceType, + PassWord = pass, + IsNoLogin = false, + }; + var Result = ApiHelp.GetDataFromHttp>(LocalFile.Config.ApiIpHost + "user/userLogin", + body, "POST"); + if (Result.Code != 200 || Result.Data == null) + { + HandyControl.Controls.MessageBox.Warning(Result.Message, "提示"); + return; + } + else + { + viewModel.User = Result.Data; + } + } + catch (Exception ex) + { + HandyControl.Controls.MessageBox.Warning($"登录发生异常:{ex.Message}", "提示"); + return; + } + + //登录记忆 + if (LocalFile.Config.Sys.IsSaveLogin) + { + LocalFile.Config.Sys.SaveLogin.RemoveAll(t => t == loginName); + LocalFile.Config.Sys.SaveLogin.Insert(0, loginName); + LocalFile.Config.Sys.SaveLogin = LocalFile.Config.Sys.SaveLogin.Take(LocalFile.Config.Sys.SaveLoginCount).ToList(); + LocalFile.SaveConfig(); + } + viewModel.Roles = viewModel.User?.GetRoles; + viewModel.IsLogin = true; + LocalStatic.CurrentUser = loginName; + this.DialogResult = true; + this.Close(); + } + catch (Exception ex) + { + HandyControl.Controls.MessageBox.Error(ex.Message, "错误"); + return; + } + } + + private void Window_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + Button_Click(null, null); + } + else if (e.Key == Key.Escape) + { + this.Close(); + } + } + + /// + /// 不登录,直接使用最高权限 + /// + public static void NotLogin() + { + try + { + var body = new GetUsersRequest() + { + UserName = "未登录", + DeviceType = "WCS前端", + Info = "admin", + }; + var Result = ApiHelp.Post>>([LocalFile.Config.ApiIpHost, "user/getUsers"], body).Result; + if (Result != null && Result.Data.Any()) + { + UserInfoView.viewModel.User = Result.Data.First(); + } + + var bodyRole = new GetUsersRequest() + { + UserName = "未登录", + DeviceType = "WCS前端", + Info = string.Empty, + + }; + var ResultRole = ApiHelp.Post>>([LocalFile.Config.ApiIpHost, "user/getRoles"], body).Result; + if (ResultRole != null && ResultRole.Data.Any()) + { + UserInfoView.viewModel.Roles = ResultRole.Data; + } + + UserInfoView.viewModel.IsLogin = true; + } + catch (Exception ex) + { + Growl.Error("加载数据失败:" + ex.Message); + } + finally + { + //dia.Close(); + } + } + + //接口获取User对象 + + } +} diff --git a/货架标准上位机/data/jsconfig.json b/货架标准上位机/data/jsconfig.json new file mode 100644 index 0000000..87c04ae --- /dev/null +++ b/货架标准上位机/data/jsconfig.json @@ -0,0 +1,31 @@ +{ + //连接不上加:SslMode=none; + "MySql": "server=localhost;Database=db1;Uid=root;Pwd=123456;Convert Zero Datetime=True", + //货架服务器的IP和端口号 + "ApiIpHost": "http://localhost:8888/", + //货架分区 + "GroupName": [ "A", "B", "C" ], + //设备类型 可以配置为每个电脑不一样 + "DeviceType": "WCS前端-开发电脑", + //货架类型的是否开机自检 + "IsBootSelfTest": false, + //扫码枪COM口列表 + "ScannerComList": [ "COM1", "COM2" ], + //串口扫码枪延时 + "ScannerTimeOut": 2000, + //系统配置 + "Sys": { + //是否保存登录历史 + "IsSaveLogin": true, + //登录历史 + "SaveLogin": [], + //登录历史数量 + "SaveLoginCount": 5, + //开机启动 + "Powerboot": false, + //启动全屏 + "StartupFull": false, + //日志保存天数 + "SaveLogDay": 182 + } +} \ No newline at end of file diff --git a/货架标准上位机/data/操作说明书.docx b/货架标准上位机/data/操作说明书.docx new file mode 100644 index 0000000..e39d291 Binary files /dev/null and b/货架标准上位机/data/操作说明书.docx differ diff --git a/货架标准上位机/货架标准上位机.csproj b/货架标准上位机/货架标准上位机.csproj new file mode 100644 index 0000000..7334c20 --- /dev/null +++ b/货架标准上位机/货架标准上位机.csproj @@ -0,0 +1,111 @@ + + + + WinExe + net472 + enable + true + latest + 重庆盟讯电子科技有限公司 + Copyright © 2024 + 1.0.0 + 1.0.0 + Resources\Logo.ico + 重庆盟讯电子科技有限公司 + 货架标准上位机 + 货架标准上位机 + + + + 1701;1702;8601;8618;8625 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\..\Windows\assembly\GAC_MSIL\Interop.BarTender\10.1.4.1__109ff779a1b4cbc7\Interop.BarTender.dll + True + + + + + + + PreserveNewest + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + Code + + + + + + Designer + + + + diff --git a/货架标准上位机/项目说明.txt b/货架标准上位机/项目说明.txt new file mode 100644 index 0000000..640fa93 --- /dev/null +++ b/货架标准上位机/项目说明.txt @@ -0,0 +1,64 @@ + + 项目模板版本(v 24.03) @ 2024 + + +一、项目介绍 + 此项目是用于盟讯快速开发WPF桌面端程序。 + + +二、开始使用 + 1.为了方便区分项目可以:更改解决方案的名称。 + 2.为了方便管理项目可以:右键‘编辑项目文件’将‘货架标准上位机程序’更改为你项目的名称。 + 3.为了方便生产项目可以:右键‘编辑项目文件’将‘货架标准上位机’可以更改程序的程序集名称(程序生产的名称),但是记得修改‘App.xaml’里面的‘’部分,不然字体会找不到。 + 4.将‘\data’拷贝到生成的bin中即可运行。 + 5.完成 + +三、权限 + 1.编辑[Models\AuthEnum.cs]文件。 + 2.可以使用特性'[Description()]'和'[EnumTree()]'。 + 3.在XAML中使用的2种办法。 +IsEnabled="{Binding Auth,Source={x:Static local:UserInfoView.viewModel},ConverterParameter={x:Static local:AuthEnum.设置},Converter={StaticResource AuthConverter}}" +Visibility="{Binding Auth,Source={x:Static local:UserInfoView.viewModel},ConverterParameter={x:Static local:AuthEnum.设置},Converter={StaticResource AuthVisConverter}}" + +四、文件夹/文件 +·Api + Web Api相关 +·Converters + 转换器 +·data + 存放数据。请将此目录拷贝到bin目录下才能运行! +·Db + 操作数据库。货架标准上位机默认自带MySql、SqlServer、Sqlite引擎。 +·Fonts + 字体文件夹,"\Fonts\demo\demo_index.html"中可以查看所有字体。 +·Resources + 资源文件夹。"LogoAll.zip"包含其他常用公司的Logo。 +·Tool + 扩展类文件夹。 +·ViewModels + 视图模型层。 +·Views + 视图层。WPF用户控件。 +·LocalFile.cs + 本地文件夹/文件路径静态管理。包含日志、帮助文档等基础的路径信息。 +·LocalStatic.cs + 本地全局静态管理。 + +五、其他包推荐 + [TouchSocket] Socket库 + [Flurl] url解析库 + [ScottPlot] 千万级图表库 + +六、常见问题 +问:如何更改项目图标? + 答:去‘\Resources’中替换掉‘Logo.ico’和‘Logo.png’后重新生成项目即可。注意你的项目如果没有任何更改那么重新生成将不会起作用,你可以将‘货架标准上位机.exe’删除后再重新生成即可。 +问:字体图标不够用,我如何使用其他字体图标? + 答:浏览器打开"\Fonts\demo\demo_index.html"后点击左上角的Logo即可进入到阿里矢量图标库。搜索比如‘主页’选择单色图标(加入购物车-选择购物车-添加至项目-下载到本地-解压-重命名-拷贝到‘\Fonts’),在项目中选中它右键属性,生成操作设置为资源即可。 +问:货架标准上位机最低支持的VS的版本是多少? + 答:VS2019。你需要去(项目右键-编辑项目文件)中把‘TargetFramework’属性只保留net472即可。 +问:货架标准上位机最低支持的操作系统是多少? + 答:Win7。部分电脑可能不支持net472可以去(项目右键-编辑项目文件)中把‘TargetFramework’属性中的net472改为net462即可。 +问:如何启动警告信息容器(WarnInfoContainer)的数据库本地保存和在页面上查看数据? + 答:去‘MainViewModel.cs’中解开注释‘WarnInfoDb.Ini()’。引用页面控件‘DataListWarnInfoView.xaml’放入主页中即可看到页面。 +问:货架标准上位机如何升级到Net? + 答:去项目文件中改为Net指定版本后,更改‘SqlSugar’包和它相关联的包为Net版本即可。‘DeviceCommunication’库本身是支持跨平台的。 \ No newline at end of file