diff --git a/SlnMesnac.Business/SlnMesnac.Business.csproj b/SlnMesnac.Business/SlnMesnac.Business.csproj new file mode 100644 index 0000000..4e2cf5e --- /dev/null +++ b/SlnMesnac.Business/SlnMesnac.Business.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.1 + enable + + + + + + + + diff --git a/SlnMesnac.Business/base/BaseBusiness.cs b/SlnMesnac.Business/base/BaseBusiness.cs new file mode 100644 index 0000000..4dd7e89 --- /dev/null +++ b/SlnMesnac.Business/base/BaseBusiness.cs @@ -0,0 +1,115 @@ +using Microsoft.Extensions.DependencyInjection; +using SlnMesnac.Plc; +using SlnMesnac.Rfid; +using SlnMesnac.Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Business.base +* 唯一标识:b00d95c1-a164-43a3-9f34-2a5d2efb3f34 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-12 17:36:19 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Business.@base +{ + internal class BaseBusiness + { + private readonly List _plcFactories; + + private readonly List _rfidFactories; + + private IServiceProvider _serviceProvider; + + public BaseBusiness(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + + using (var scope = _serviceProvider.CreateScope()) + { + _plcFactories = scope.ServiceProvider.GetRequiredService>(); + _rfidFactories = scope.ServiceProvider.GetRequiredService>(); + } + } + + /// + /// 根据Key获取PLC连接信息 + /// + /// + /// + /// + /// + public PlcAbsractFactory GetPlcByKey(string key) + { + if(_plcFactories == null) + { + throw new ArgumentNullException($"根据Key获取PLC连接信息异常:PLC 连接信息为空"); + } + + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentNullException("根据Key获取PLC连接信息异常:设备Key参数为空"); + } + + try + { + var info = _plcFactories.Where(x => x.ConfigKey == key).FirstOrDefault(); + + return info; + }catch(Exception ex) + { + throw new InvalidOperationException($"根据Key获取PLC连接信息异常:{ex.Message}"); + } + } + + + /// + /// 根据Key获取Rfid连接信息 + /// + /// + /// + /// + /// + public RfidAbsractFactory GetRfidByKey(string key) + { + if (_rfidFactories == null) + { + throw new ArgumentNullException($"根据Key获取RFID连接信息异常:PLC 连接信息为空"); + } + + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentNullException("根据Key获取RFID连接信息异常:设备Key参数为空"); + } + + try + { + var info = _rfidFactories.Where(x => x.ConfigKey == key).FirstOrDefault(); + + return info; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据Key获取RFID连接信息异常:{ex.Message}"); + } + } + } +} diff --git a/SlnMesnac.Common/ExpressionExtensions.cs b/SlnMesnac.Common/ExpressionExtensions.cs new file mode 100644 index 0000000..a5348c0 --- /dev/null +++ b/SlnMesnac.Common/ExpressionExtensions.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Linq; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Common +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Common +{ + /// + /// 谓词表达式构建器 + /// + public static class ExpressionExtensions + { + /// + /// 创建一个值恒为 true 的表达式。 + /// + /// 表达式方法类型 + /// 一个值恒为 true 的表达式。 + public static Expression> True() { return p => true; } + + /// + /// 创建一个值恒为 false 的表达式。 + /// + /// 表达式方法类型 + /// 一个值恒为 false 的表达式。 + public static Expression> False() { return f => false; } + + /// + /// 使用 Expression.OrElse 的方式拼接两个 System.Linq.Expression。 + /// + /// 表达式方法类型 + /// 左边的 System.Linq.Expression 。 + /// 右边的 System.Linq.Expression。 + /// 拼接完成的 System.Linq.Expression。 + public static Expression Or(this Expression left, Expression right) + { + return MakeBinary(left, right, Expression.OrElse); + } + + /// + /// 使用 Expression.AndAlso 的方式拼接两个 System.Linq.Expression。 + /// + /// 表达式方法类型 + /// 左边的 System.Linq.Expression 。 + /// 右边的 System.Linq.Expression。 + /// 拼接完成的 System.Linq.Expression。 + public static Expression And(this Expression left, Expression right) + { + return MakeBinary(left, right, Expression.AndAlso); + } + + /// + /// 使用自定义的方式拼接两个 System.Linq.Expression。 + /// + /// 表达式方法类型 + /// 左边的 System.Linq.Expression 。 + /// 右边的 System.Linq.Expression。 + /// + /// 拼接完成的 System.Linq.Expression。 + private static Expression MakeBinary(this Expression left, Expression right, Func func) + { + return MakeBinary((LambdaExpression)left, right, func) as Expression; + } + + /// + /// 拼接两个 + /// System.Linq.Expression + /// ,两个 + /// System.Linq.Expression + /// 的参数必须完全相同。 + /// + /// 左边的 + /// System.Linq.Expression + /// + /// 右边的 + /// System.Linq.Expression + /// + /// 表达式拼接的具体逻辑 + /// 拼接完成的 + /// System.Linq.Expression + /// + private static LambdaExpression MakeBinary(this LambdaExpression left, LambdaExpression right, Func func) + { + var data = Combinate(right.Parameters, left.Parameters).ToArray(); + + right = ParameterReplace.Replace(right, data) as LambdaExpression; + + return Expression.Lambda(func(left.Body, right.Body), left.Parameters.ToArray()); + } + + /// + /// 合并参数 + /// + /// + /// + /// + /// + private static IEnumerable> Combinate(IEnumerable left, IEnumerable right) + { + var a = left.GetEnumerator(); + var b = right.GetEnumerator(); + while (a.MoveNext() && b.MoveNext()) + yield return new KeyValuePair(a.Current, b.Current); + } + } + + internal sealed class ParameterReplace : ExpressionVisitor + { + public static Expression Replace(Expression e, IEnumerable> paramList) + { + var item = new ParameterReplace(paramList); + return item.Visit(e); + } + + private readonly Dictionary _parameters; + + public ParameterReplace(IEnumerable> paramList) + { + _parameters = paramList.ToDictionary(p => p.Key, p => p.Value, new ParameterEquality()); + } + + protected override Expression VisitParameter(ParameterExpression p) + { + ParameterExpression result; + if (_parameters.TryGetValue(p, out result)) + return result; + return base.VisitParameter(p); + } + + #region class: ParameterEquality + private class ParameterEquality : IEqualityComparer + { + public bool Equals(ParameterExpression x, ParameterExpression y) + { + if (x == null || y == null) + return false; + + return x.Type == y.Type; + } + + public int GetHashCode(ParameterExpression obj) + { + if (obj == null) + return 0; + + return obj.Type.GetHashCode(); + } + } + #endregion + } +} diff --git a/SlnMesnac.Common/SlnMesnac.Common.csproj b/SlnMesnac.Common/SlnMesnac.Common.csproj new file mode 100644 index 0000000..d031ec1 --- /dev/null +++ b/SlnMesnac.Common/SlnMesnac.Common.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.1 + enable + + + + + + + + diff --git a/SlnMesnac.Common/StringChange.cs b/SlnMesnac.Common/StringChange.cs new file mode 100644 index 0000000..6c4ff13 --- /dev/null +++ b/SlnMesnac.Common/StringChange.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Common +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Common +{ + public class StringChange + { + /// + /// 将字符串强制转换成int,转换失败则返回0 + /// + /// + /// + public int ParseToInt(string str) + { + int returnInt = 0; + if (str == null || str.Trim().Length < 1) + { + return returnInt; + } + if (int.TryParse(str, out returnInt)) + { + return returnInt; + } + else + { + return 0; + } + } + + /// + /// char数组转Array + /// + /// + /// + /// + public string CharArrayToString(char[] cha, int len) + { + string str = ""; + for (int i = 0; i < len; i++) + { + str += string.Format("{0}", cha[i]); + } + + return str; + } + + public string bytesToHexStr(byte[] bytes, int iLen)//e.g. { 0x01, 0x01} ---> " 01 01" + { + string returnStr = ""; + if (bytes != null) + { + for (int i = 0; i < iLen; i++) + { + returnStr += bytes[i].ToString("X2"); + } + } + return returnStr; + } + + public byte[] HexStrTorbytes(string strHex)//e.g. " 01 01" ---> { 0x01, 0x01} + { + strHex = strHex.Replace(" ", ""); + if ((strHex.Length % 2) != 0) + strHex += " "; + byte[] returnBytes = new byte[strHex.Length / 2]; + for (int i = 0; i < returnBytes.Length; i++) + returnBytes[i] = Convert.ToByte(strHex.Substring(i * 2, 2), 16); + return returnBytes; + } + + public string StringToHexString(string s, Encoding encode) + { + byte[] b = encode.GetBytes(s); //按照指定编码将string编程字节数组 + string result = string.Empty; + for (int i = 0; i < b.Length; i++) //逐字节变为16进制字符,以%隔开 + { + result += "%" + Convert.ToString(b[i], 16); + } + return result; + } + + public string HexStringToString(string hs, Encoding encode) + { + //以%分割字符串,并去掉空字符 + string[] chars = hs.Split(new char[] { '%' }, StringSplitOptions.RemoveEmptyEntries); + byte[] b = new byte[chars.Length]; + //逐个字符变为16进制字节数据 + for (int i = 0; i < chars.Length; i++) + { + b[i] = Convert.ToByte(chars[i], 16); + } + //按照指定编码将字节数组变为字符串 + return encode.GetString(b); + } + + public byte[] Swap16Bytes(byte[] OldU16) + { + byte[] ReturnBytes = new byte[2]; + ReturnBytes[1] = OldU16[0]; + ReturnBytes[0] = OldU16[1]; + return ReturnBytes; + } + + + /// 64Base码 + /// 保存路径 + /// 文件名称 + /// + public bool Base64ToImage(string strbase64, string path, string filename) + { + bool Flag = false; + try + { + //base64编码的文本 转为 图片 + //图片名称 + byte[] arr = Convert.FromBase64String(strbase64);//将指定的字符串(它将二进制数据编码为 Base64 数字)转换为等效的 8 位无符号整数数组。 + using (MemoryStream ms = new MemoryStream(arr)) + { + Bitmap bmp = new Bitmap(ms);//加载图像 + if (!Directory.Exists(path))//判断保存目录是否存在 + { + Directory.CreateDirectory(path); + } + bmp.Save((path + "\\" + filename + ".png"), System.Drawing.Imaging.ImageFormat.Png);//将图片以JPEG格式保存在指定目录(可以选择其他图片格式) + ms.Close();//关闭流并释放 + if (File.Exists(path + "\\" + filename + ".png"))//判断是否存在 + { + Flag = true; + } + } + } + catch (Exception ex) + { + Console.WriteLine("图片保存失败:" + ex.Message); + } + return Flag; + } + + /// + /// 获取时间戳 + /// + /// + public long GetTimeStamp() + { + TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); + return Convert.ToInt64(ts.TotalSeconds); + } + + public byte[] ConvertFloatToINt(byte[] floatBytes) + { + byte[] intBytes = new byte[floatBytes.Length / 2]; + for (int i = 0; i < intBytes.Length; i++) + { + intBytes[i] = floatBytes[i * 2]; + } + return intBytes; + } + + //CRC异或校验 + public byte CalculateVerify(byte[] pMessage, int iLength) + { + UInt16 i; + byte iVerify = 0; + + iVerify = pMessage[0]; + for (i = 1; i < iLength; i++) + { + iVerify = (byte)(iVerify ^ pMessage[i]); + } + return iVerify; + } + + public int HexStringToNegative(string strNumber) + { + + int iNegate = 0; + int iNumber = Convert.ToInt32(strNumber, 16); + if (iNumber > 127) + { + int iComplement = iNumber - 1; + string strNegate = string.Empty; + char[] binchar = Convert.ToString(iComplement, 2).PadLeft(8, '0').ToArray(); + foreach (char ch in binchar) + { + if (Convert.ToInt32(ch) == 48) + { + strNegate += "1"; + } + else + { + strNegate += "0"; + } + } + iNegate = -Convert.ToInt32(strNegate, 2); + } + return iNegate; + } + } +} \ No newline at end of file diff --git a/SlnMesnac.Config/AppConfig.cs b/SlnMesnac.Config/AppConfig.cs new file mode 100644 index 0000000..d2b0de6 --- /dev/null +++ b/SlnMesnac.Config/AppConfig.cs @@ -0,0 +1,87 @@ +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Config +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Config +{ + /// + /// 系统配置 + /// + #pragma warning disable CS8618 // Non-nullable field 'Data' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + public class AppConfig : IOptions + { + /// + /// 日志文件路径 + /// + public string logPath { get; set; } + + /// + /// Sql连接配置 + /// + public List sqlConfig { get; set; } + + /// + /// PLC连接配置 + /// + public List plcConfig { get; set; } + + /// + /// RFID连接配置 + /// + public List rfidConfig { get; set; } + + + /// + /// Redis配置 + /// + public string redisConfig { get; set; } + + /// + /// 修改配置文件 + /// + /// + public void SetValue(AppConfig appConfig) + { + var jsonObject = JsonConvert.SerializeObject(new + { + AppConfig = new + { + logPath = appConfig.logPath, + SqlConfig = appConfig.sqlConfig, + PlcConfig = appConfig.plcConfig, + RfidConfig = appConfig.rfidConfig, + RedisConfig = appConfig.redisConfig, + } + }, Newtonsoft.Json.Formatting.Indented); + var appSettingsPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); + File.WriteAllText(appSettingsPath, jsonObject); + } + + public AppConfig Value => this; + } +} diff --git a/SlnMesnac.Config/PlcConfig.cs b/SlnMesnac.Config/PlcConfig.cs new file mode 100644 index 0000000..6be7fb7 --- /dev/null +++ b/SlnMesnac.Config/PlcConfig.cs @@ -0,0 +1,61 @@ +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Config +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Config +{ + /// + /// PLC配置,通过AppConfig进行获取 + /// + #pragma warning disable CS8618 // Non-nullable field 'Data' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + public class PlcConfig + { + /// + /// PLC配置ID + /// + public int configId { get; set; } + + /// + /// PIC类型 + /// + public string plcType { get; set; } + + /// + /// PLC IP + /// + public string plcIp { get; set; } + + /// + /// PLC Port + /// + public int plcPort { get; set; } + + /// + /// PLC Key + /// + public string plcKey { get; set; } + + /// + /// 是否启用 + /// + public bool isFlage { get; set; } + } +} \ No newline at end of file diff --git a/SlnMesnac.Config/RfidConfig.cs b/SlnMesnac.Config/RfidConfig.cs new file mode 100644 index 0000000..87622ea --- /dev/null +++ b/SlnMesnac.Config/RfidConfig.cs @@ -0,0 +1,52 @@ +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Config +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Config +{ + public class RfidConfig + { + /// + /// 配置ID + /// + public int configId { get; set; } + + /// + /// 设备 IP + /// + public string? equipIp { get; set; } + + /// + /// 设备 Port + /// + public int equipPort { get; set; } + + /// + /// 设备 Key + /// + public string? equipKey { get; set; } + + /// + /// 是否启用 + /// + public bool isFlage { get; set; } + } +} \ No newline at end of file diff --git a/SlnMesnac.Config/SlnMesnac.Config.csproj b/SlnMesnac.Config/SlnMesnac.Config.csproj new file mode 100644 index 0000000..daf8195 --- /dev/null +++ b/SlnMesnac.Config/SlnMesnac.Config.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.1 + enable + + + + + + + + diff --git a/SlnMesnac.Config/SqlConfig.cs b/SlnMesnac.Config/SqlConfig.cs new file mode 100644 index 0000000..cc3de31 --- /dev/null +++ b/SlnMesnac.Config/SqlConfig.cs @@ -0,0 +1,46 @@ +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Config +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Config +{ + /// + /// Sql连接配置 + /// + #pragma warning disable CS8618 // Non-nullable field 'Data' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + public class SqlConfig + { + /// + /// Sql 配置ID,实体通过该ID关联数据源 + /// + public string configId { get; set; } + + /// + /// 数据库类型,MySql-0;SqlServer-1;Sqlite-2;Oracle-3 + /// + public int dbType { get; set; } + + /// + /// 连接字符串 + /// + public string connStr { get; set; } + } +} \ No newline at end of file diff --git a/SlnMesnac.Extensions/PlcFactorySetup.cs b/SlnMesnac.Extensions/PlcFactorySetup.cs new file mode 100644 index 0000000..3298593 --- /dev/null +++ b/SlnMesnac.Extensions/PlcFactorySetup.cs @@ -0,0 +1,131 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using SlnMesnac.Config; +using SlnMesnac.Plc; +using SlnMesnac.Plc.Factory; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Extensions +* 唯一标识:9bf604b4-3937-476a-adb0-27adc6fbea28 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-12 15:25:47 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Extensions +{ + /// + /// PLC工厂 + /// + public static class PlcFactorySetup + { + + public static void AddPlcFactorySetup(this IServiceCollection services) + { + services.AddSingleton>(x => + { + AppConfig appConfig = x.GetService(); + + List absractFactories = new List(); + + try + { + do + { + if (!HslCommunication.Authorization.SetAuthorizationCode("1839541f-8fb4-42c4-a13f-733b027fe5af")) + { + Log.Information("HslCommunication激活失败,可用时长为24小时"); + break; + } + else + { + Log.Information("HslCommunication激活成功"); + } + + if (appConfig.plcConfig != null) + { + foreach (var item in appConfig.plcConfig) + { + if (item.isFlage) + { + PlcAbsractFactory _plc = InitPlc(x, item.plcType); + + var connectResult = _plc.Connect(item.plcIp, item.plcPort); + if (connectResult) + { + Log.Information($"PLC:{item.plcIp}:{item.plcPort};连接成功,时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); + _plc.ConfigKey = item.plcKey; + + if (absractFactories.Contains(_plc)) + { + absractFactories.Remove(_plc); + } + + absractFactories.Add(_plc); + } + else + { + Log.Information($"PLC:{item.plcIp}:{item.plcPort};连接失败,时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); + } + } + } + } + }while(false); + } + catch (Exception e) + { + Log.Error($"PLC初始化连接异常:{e.Message}"); + } + + return absractFactories; + }); + } + + private static PlcAbsractFactory InitPlc(IServiceProvider serviceProvider,string plcType) + { + PlcAbsractFactory _plc = null; + var _inovance = serviceProvider.GetRequiredService(); + var _melsecBinary = serviceProvider.GetRequiredService(); + var _omronNj = serviceProvider.GetRequiredService(); + var _siemens = serviceProvider.GetRequiredService(); + + switch (plcType) + { + case "InovancePlc": + _plc = _inovance; + break; + case "MelsecBinaryPlc": + _plc = _melsecBinary; + break; + case "OmronNJPlc": + _plc = _omronNj; + break; + case "SiemensPlc": + _plc = _siemens; + break; + default: + break; + } + + return _plc; + } + } +} diff --git a/SlnMesnac.Extensions/RfidFactorySetup.cs b/SlnMesnac.Extensions/RfidFactorySetup.cs new file mode 100644 index 0000000..ac5e29f --- /dev/null +++ b/SlnMesnac.Extensions/RfidFactorySetup.cs @@ -0,0 +1,87 @@ +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using SlnMesnac.Config; +using SlnMesnac.Plc; +using SlnMesnac.Rfid; +using SlnMesnac.Rfid.Factory; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Extensions +* 唯一标识:007aaf92-2adf-42a1-8b64-4e02925e3d5b +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-12 17:08:27 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Extensions +{ + public static class RfidFactorySetup + { + public static void AddRfidFactorySetup(this IServiceCollection services) + { + services.AddSingleton>(x => + { + AppConfig appConfig = x.GetService(); + List absractFactories = new List(); + + try + { + if (appConfig.rfidConfig != null) + { + foreach (var item in appConfig.rfidConfig) + { + if (item.isFlage) + { + RfidAbsractFactory _rfid = x.GetService(); + bool connectResult = _rfid.Connect(item.equipIp, item.equipPort); + if (connectResult) + { + Log.Information($"RFID:{item.equipIp}:{item.equipPort};连接成功,时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); + _rfid.ConfigKey = item.equipKey; + + if (absractFactories.Contains(_rfid)) + { + absractFactories.Remove(_rfid); + } + + absractFactories.Add(_rfid); + } + else + { + Log.Information($"RFID:{item.equipIp}:{item.equipPort};连接失败,时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); + } + } + } + } + else + { + Log.Error("RFID配置信息为空"); + } + } + catch (Exception e) + { + Log.Error($"RFID初始化连接异常:{e.Message}"); + } + + return absractFactories; + }); + } + } +} diff --git a/SlnMesnac.Extensions/SlnMesnac.Extensions.csproj b/SlnMesnac.Extensions/SlnMesnac.Extensions.csproj new file mode 100644 index 0000000..cd6c9bd --- /dev/null +++ b/SlnMesnac.Extensions/SlnMesnac.Extensions.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.1 + enable + + + + + + + + + + diff --git a/SlnMesnac.Extensions/SqlsugarSetup.cs b/SlnMesnac.Extensions/SqlsugarSetup.cs new file mode 100644 index 0000000..8761bea --- /dev/null +++ b/SlnMesnac.Extensions/SqlsugarSetup.cs @@ -0,0 +1,69 @@ +using Microsoft.Extensions.DependencyInjection; +using SlnMesnac.Config; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Extensions +* 唯一标识:bbb46406-e99d-4205-8046-ad954cf88315 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-12 17:31:43 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Extensions +{ + public static class SqlsugarSetup + { + /// + /// 注册SqlSugar + /// + /// + public static void AddSqlSugarSetup(this IServiceCollection services) + { + services.AddSingleton(x => + { + var appConfig = x.GetService(); + + var connectConfigList = new List(); + if (appConfig.sqlConfig != null) + { + foreach (var item in appConfig.sqlConfig) + { + var config = new ConnectionConfig() + { + ConfigId = item.configId, + DbType = (DbType)item.dbType, + ConnectionString = item.connStr, + InitKeyType = InitKeyType.Attribute, + IsAutoCloseConnection = true, + }; + connectConfigList.Add(config); + } + } + SqlSugarScope Db = new SqlSugarScope(connectConfigList, db => + { + db.Aop.OnLogExecuting = (sql, pars) => { }; + }); + + return Db; + }); + } + } +} diff --git a/SlnMesnac.Generate/GenerateCode.cs b/SlnMesnac.Generate/GenerateCode.cs new file mode 100644 index 0000000..812b0f9 --- /dev/null +++ b/SlnMesnac.Generate/GenerateCode.cs @@ -0,0 +1,113 @@ +using SlnMesnac.Generate.Templates.Service; +using SlnMesnac.Generate.Templates.Service.Impl; +using SqlSugar; +using System; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Generate +* 唯一标识:78595105-fab6-40f0-97b4-1272dc3e0e86 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-11 13:35:01 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Generate +{ + /// + /// 生成代码 + /// + public class GenerateCode + { + private readonly ISqlSugarClient _sqlSugarClient; + + public GenerateCode(ISqlSugarClient sqlSugarClient) + { + _sqlSugarClient = sqlSugarClient; + } + + public bool CreateCode(string configId,string tableName,string savePath,string nameSpace) + { + if (string.IsNullOrEmpty(configId)) + { + throw new ArgumentNullException($"代码生成异常:configId参数为空"); + } + + if (string.IsNullOrEmpty(tableName)) + { + throw new ArgumentNullException($"代码生成异常:表格名称参数为空"); + } + + if (string.IsNullOrEmpty(savePath)) + { + throw new ArgumentNullException($"代码生成异常:文件存储路径参数为空"); + } + + if (string.IsNullOrEmpty(nameSpace)) + { + throw new ArgumentNullException($"代码生成异常:命名空间参数为空"); + } + + try + { + savePath += $"\\{tableName}"; + + var scope = _sqlSugarClient.AsTenant().GetConnectionScope(configId); + + scope.DbFirst.IsCreateAttribute() + .FormatPropertyName(it=> ToCamelCase(it)).Where(p => p == tableName).CreateClassFile($"{savePath}\\Entity", nameSpace); + + var isc = new IServiceCreate(); + bool iscRes = isc.Create(tableName, nameSpace, savePath); + if (!iscRes) + { + throw new InvalidOperationException($"Service接口生成失败"); + } + + var sc = new ServiceCreate(); + var scRes = sc.Create(tableName, nameSpace, savePath); + + if (!scRes) + { + throw new InvalidOperationException($"Service实现类生成失败"); + } + + return true; + }catch (Exception ex) + { + throw new InvalidOperationException($"代码生成异常:{ex.Message}"); + } + } + + private static string ToCamelCase(string input) + { + // 将字符串转换为驼峰格式,但保持每个单词的首字母大写 + string[] words = input.Split('_'); + for (int i = 0; i < words.Length; i++) + { + if (i > 0) + { + words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower(); + } + else + { + words[i] = words[i].ToLower(); + } + } + return string.Join("", words); + } + } +} diff --git a/SlnMesnac.Generate/SlnMesnac.Generate.csproj b/SlnMesnac.Generate/SlnMesnac.Generate.csproj new file mode 100644 index 0000000..7e094ef --- /dev/null +++ b/SlnMesnac.Generate/SlnMesnac.Generate.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + diff --git a/SlnMesnac.Generate/Templates/Service/IServiceCreate.cs b/SlnMesnac.Generate/Templates/Service/IServiceCreate.cs new file mode 100644 index 0000000..1306e4c --- /dev/null +++ b/SlnMesnac.Generate/Templates/Service/IServiceCreate.cs @@ -0,0 +1,78 @@ +using Commons.Collections; +using NVelocity.App; +using NVelocity.Runtime; +using NVelocity; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Generate.Templates +* 唯一标识:4dbafd45-d689-4d1a-b54d-b936dae7d17c +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-11 13:28:04 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Generate.Templates.Service +{ + public class IServiceCreate + { + private static readonly string templateDir = @"F:\桌面\SlnMesnac\SlnMesnac.Generate\Templates\Service"; + + public bool Create(string tableName, string NameSpace, string outdir) + { + + try + { + VelocityEngine velocityEngine = new VelocityEngine(); + ExtendedProperties props = new ExtendedProperties(); + props.AddProperty(RuntimeConstants.RESOURCE_LOADER, @"file"); + props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, templateDir); + props.AddProperty(RuntimeConstants.INPUT_ENCODING, "utf-8"); + props.AddProperty(RuntimeConstants.OUTPUT_ENCODING, "utf-8"); + //模板的缓存设置 + props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, true); //是否缓存 + props.AddProperty("file.resource.loader.modificationCheckInterval", (Int64)30); //缓存时间(秒) + velocityEngine.Init(props); + //为模板变量赋值 + VelocityContext context = new VelocityContext(); + context.Put("tableName", tableName); + context.Put("NameSpace", NameSpace); + context.Put("outdir", outdir); + //从文件中读取模板 + Template template = velocityEngine.GetTemplate(@"\IServices.vm"); + if (!Directory.Exists(outdir + "\\IServices")) + { + Directory.CreateDirectory(outdir + "\\IServices"); + } + //合并模板 + using (StreamWriter writer = new StreamWriter(outdir + $"\\IServices\\I{tableName.Substring(0, 1).ToUpper()}{tableName.Substring(1)}Service.cs", false)) + { + template.Merge(context, writer); + } + return true; + }catch(Exception ex) + { + throw new InvalidOperationException($"Service接口模板创建异常:{ex.Message}"); + } + } + + + } +} diff --git a/SlnMesnac.Generate/Templates/Service/IServices.vm b/SlnMesnac.Generate/Templates/Service/IServices.vm new file mode 100644 index 0000000..a5b8992 --- /dev/null +++ b/SlnMesnac.Generate/Templates/Service/IServices.vm @@ -0,0 +1,13 @@ +using SlnMesnac.Model.domain; +using SlnMesnac.Repository.service.@base; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ${NameSpace}.service +{ + public interface I${tableName}Services: IBaseService<${tableName}> + { + + } +} \ No newline at end of file diff --git a/SlnMesnac.Generate/Templates/Service/Impl/ServiceCreate.cs b/SlnMesnac.Generate/Templates/Service/Impl/ServiceCreate.cs new file mode 100644 index 0000000..0aa6838 --- /dev/null +++ b/SlnMesnac.Generate/Templates/Service/Impl/ServiceCreate.cs @@ -0,0 +1,75 @@ +using Commons.Collections; +using NVelocity.App; +using NVelocity.Runtime; +using NVelocity; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Generate.Templates +* 唯一标识:4acc596a-6223-4156-b16c-952c225eff25 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-11 13:27:33 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Generate.Templates.Service.Impl +{ + public class ServiceCreate + { + private static readonly string templateDir = @"F:\桌面\SlnMesnac\SlnMesnac.Generate\Templates\Service\Impl\"; + + public bool Create(string tableName, string NameSpace, string outdir) + { + try + { + VelocityEngine velocityEngine = new VelocityEngine(); + ExtendedProperties props = new ExtendedProperties(); + props.AddProperty(RuntimeConstants.RESOURCE_LOADER, @"file"); + props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, templateDir); + props.AddProperty(RuntimeConstants.INPUT_ENCODING, "utf-8"); + props.AddProperty(RuntimeConstants.OUTPUT_ENCODING, "utf-8"); + //模板的缓存设置 + props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, true); //是否缓存 + props.AddProperty("file.resource.loader.modificationCheckInterval", (Int64)30); //缓存时间(秒) + velocityEngine.Init(props); + //为模板变量赋值 + VelocityContext context = new VelocityContext(); + context.Put("tableName", tableName); + context.Put("NameSpace", NameSpace); + context.Put("outdir", outdir); + //从文件中读取模板 + Template template = velocityEngine.GetTemplate(@"\Services.vm"); + if (!Directory.Exists(outdir + "\\Services")) + { + Directory.CreateDirectory(outdir + "\\Services"); + } + //合并模板 + using (StreamWriter writer = new StreamWriter(outdir + $"\\Services\\{tableName.Substring(0, 1).ToUpper()}{tableName.Substring(1)}ServiceImpl.cs", false)) + { + template.Merge(context, writer); + } + return true; + }catch(Exception ex) + { + throw new InvalidOperationException($"Service实现类模板创建异常:{ex.Message}"); + } + } + } +} diff --git a/SlnMesnac.Generate/Templates/Service/Impl/Services.vm b/SlnMesnac.Generate/Templates/Service/Impl/Services.vm new file mode 100644 index 0000000..bcf9a49 --- /dev/null +++ b/SlnMesnac.Generate/Templates/Service/Impl/Services.vm @@ -0,0 +1,14 @@ +using SlnMesnac.Model.domain; +using SlnMesnac.Repository.service.@base; +using System; +using System.Collections.Generic; + +namespace ${NameSpace}.service.Impl +{ + public class ${tableName}ServiceImpl : BaseServiceImpl<${tableName}>, I${tableName}Service + { + public ${tableName}ServiceImpl(Repository<${tableName}> repository):base(repository) + { + } + } +} \ No newline at end of file diff --git a/SlnMesnac.Library/GRreader.dll b/SlnMesnac.Library/GRreader.dll new file mode 100644 index 0000000..70ee539 Binary files /dev/null and b/SlnMesnac.Library/GRreader.dll differ diff --git a/SlnMesnac.Library/HslCommunication.dll b/SlnMesnac.Library/HslCommunication.dll new file mode 100644 index 0000000..7082ca2 Binary files /dev/null and b/SlnMesnac.Library/HslCommunication.dll differ diff --git a/SlnMesnac.Model/SlnMesnac.Model.csproj b/SlnMesnac.Model/SlnMesnac.Model.csproj new file mode 100644 index 0000000..4f9d9b5 --- /dev/null +++ b/SlnMesnac.Model/SlnMesnac.Model.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.1 + enable + + + + + + + diff --git a/SlnMesnac.Model/domain/BaseMaterialInfo.cs b/SlnMesnac.Model/domain/BaseMaterialInfo.cs new file mode 100644 index 0000000..c62d5aa --- /dev/null +++ b/SlnMesnac.Model/domain/BaseMaterialInfo.cs @@ -0,0 +1,309 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; +using System.Xml.Linq; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Model.domain +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Model.domain +{ + + + [SugarTable("BasMaterial"), TenantAttribute("mes")] + [DataContract(Name = "BasMaterial 物料信息")] + #pragma warning disable CS8618 // Non-nullable field 'Data' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + public class BaseMaterialInfo + { + /// + /// + /// + [SugarColumn(ColumnName = "ObjID", IsPrimaryKey = true)] + public int ObjID { get; set; } + /// + /// 大类+小类+规格+胶代码或最后4顺序号 + /// + [SugarColumn(ColumnName = "MaterialCode")] + public string MaterialCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MajorTypeID")] + public int? MajorTypeID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MinorTypeID")] + public string MinorTypeID { get; set; } + /// + /// + /// 默认值: ('') + /// + [SugarColumn(ColumnName = "RubCode")] + public string RubCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MaterialName")] + public string MaterialName { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MaterialOtherName")] + public string MaterialOtherName { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MaterialSimpleName")] + public string MaterialSimpleName { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ProductMaterialCode")] + public string ProductMaterialCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MaterialLevel")] + public string MaterialLevel { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MaterialGroup")] + public string MaterialGroup { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "UserCode")] + public string UserCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "PlanPrice")] + public decimal? PlanPrice { get; set; } + /// + /// 具体到县级市,长度为6,国外的只具体国家 + /// + [SugarColumn(ColumnName = "ProductArea")] + public string ProductArea { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MinStock")] + public decimal? MinStock { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "MaxStock")] + public decimal? MaxStock { get; set; } + /// + /// 千克,克,块,桶,升 + /// + [SugarColumn(ColumnName = "UnitID")] + public int? UnitID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "StaticUnitID")] + public int? StaticUnitID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "StaticUnitCoefficient")] + public decimal? StaticUnitCoefficient { get; set; } + /// + /// 显为百分比 + /// + [SugarColumn(ColumnName = "CheckPermitError")] + public decimal? CheckPermitError { get; set; } + /// + /// 按小时计算 + /// + [SugarColumn(ColumnName = "MaxParkTime")] + public decimal? MaxParkTime { get; set; } + /// + /// 小时计算 + /// + [SugarColumn(ColumnName = "MinParkTime")] + public decimal? MinParkTime { get; set; } + /// + /// + /// 默认值: (getdate()) + /// + [SugarColumn(ColumnName = "DefineDate")] + public DateTime? DefineDate { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "StandardCode")] + public string StandardCode { get; set; } + /// + /// + /// 默认值: ((1)) + /// + [SugarColumn(ColumnName = "StaticClass")] + public int? StaticClass { get; set; } + /// + /// + /// 默认值: ((0)) + /// + [SugarColumn(ColumnName = "IsEqualMaterial")] + public string IsEqualMaterial { get; set; } + /// + /// + /// 默认值: ((0)) + /// + [SugarColumn(ColumnName = "IsPutJar")] + public string IsPutJar { get; set; } + /// + /// + /// 默认值: ((1)) + /// + [SugarColumn(ColumnName = "IsQualityRateCount")] + public string IsQualityRateCount { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ERPCode")] + public string ERPCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Remark")] + public string Remark { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "DeleteFlag")] + public string DeleteFlag { get; set; } + /// + /// + /// 默认值: ((0)) + /// + [SugarColumn(ColumnName = "ValidDate")] + public decimal ValidDate { get; set; } + /// + /// + /// 默认值: ((0)) + /// + [SugarColumn(ColumnName = "ValidDateB")] + public decimal ValidDateB { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "SAPMaterialCode")] + public string SAPMaterialCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "SAPMaterialShortCode")] + public string SAPMaterialShortCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ERPCode_Bak")] + public string ErpcodeBak { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "OperSourceTemp")] + public string OperSourceTemp { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "IsQualityrateCountBak")] + public int? IsQualityrateCountBak { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "CMaterialLevel")] + public string CMaterialLevel { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "CMaterialGroup")] + public string CMaterialGroup { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "XBStock")] + public decimal? XBStock { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "HFCode")] + public string HFCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "HFCode2")] + public string HFCode2 { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "UNITName")] + public string UNITName { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "KFACSTATUS")] + public string Kfacstatus { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Ordertype")] + public string Ordertype { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "CreateDate")] + public string CreateDate { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "UpdateDate")] + public string UpdateDate { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "UnAudit")] + public string UnAudit { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ChkStand")] + public string ChkStand { get; set; } + /// + /// 1 KG 2 PC 3 标准KG + /// 默认值: ((1)) + /// + [SugarColumn(ColumnName = "SapUpUnit")] + public int? SapUpUnit { get; set; } + /// + /// 是否为轨道事业部物料:0:不是,1:是 + /// + [SugarColumn(ColumnName = "IsGDMaterial")] + public int? IsGDMaterial { get; set; } + } +} diff --git a/SlnMesnac.Model/domain/BaseUser.cs b/SlnMesnac.Model/domain/BaseUser.cs new file mode 100644 index 0000000..04dd56f --- /dev/null +++ b/SlnMesnac.Model/domain/BaseUser.cs @@ -0,0 +1,131 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Security.Principal; +using System.Text; +using System.Xml.Linq; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Model.domain +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Model.domain +{ + /// + /// 系统基础资料-人员基础资料 yuany + /// + [SugarTable("BasUser"), TenantAttribute("mes")] + [DataContract(Name = "BaseUser 人员基础资料")] + #pragma warning disable CS8618 // Non-nullable field 'Data' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + public class BaseUser + { + /// + /// + /// + [SugarColumn(ColumnName = "ObjID", IsPrimaryKey = true, IsIdentity = true)] + public int ObjID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "UserName")] + public string UserName { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "UserPWD")] + public string UserPWD { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "RealName")] + public string RealName { get; set; } + /// + /// + /// 默认值: ((1)) + /// + [SugarColumn(ColumnName = "Sex")] + public int? Sex { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Telephone")] + public string Telephone { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "WorkBarcode")] + public string WorkBarcode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "DeptCode")] + public string DeptCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "WorkID")] + public int? WorkID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ShiftID")] + public int? ShiftID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "WorkShopID")] + public int? WorkShopID { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "HRCode")] + public string HRCode { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "ERPCode")] + public string ERPCode { get; set; } + /// + /// + /// 默认值: ((0)) + /// + [SugarColumn(ColumnName = "DeleteFlag")] + public string DeleteFlag { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Remark")] + public string Remark { get; set; } + /// + /// + /// 默认值: ((1)) + /// + [SugarColumn(ColumnName = "IsEmployee")] + public string IsEmployee { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "RecordTime")] + public DateTime? RecordTime { get; set; } + } +} + diff --git a/SlnMesnac.Model/dto/TagInfo.cs b/SlnMesnac.Model/dto/TagInfo.cs new file mode 100644 index 0000000..d4f28b6 --- /dev/null +++ b/SlnMesnac.Model/dto/TagInfo.cs @@ -0,0 +1,40 @@ +using System; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Model.dto +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Model.dto +{ + #pragma warning disable CS8618 // Non-nullable field 'Data' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + public class TagInfo + { + public byte[] PC = new byte[2]; + public int Count { get; set; } + public int RSSI{ get; set; } + public int Antana{ get; set; } + public byte[] EPC{ get; set; } + public byte[] Data{ get; set; } + public string PCstring = (string) null; + public string EPCstring = (string) null; + public DateTime Time{ get; set; } + } +} \ No newline at end of file diff --git a/SlnMesnac.Mqtt/MqttClient.cs b/SlnMesnac.Mqtt/MqttClient.cs new file mode 100644 index 0000000..c80618e --- /dev/null +++ b/SlnMesnac.Mqtt/MqttClient.cs @@ -0,0 +1,169 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using System.Threading; +using MQTTnet.Client; +using System.Security.Authentication; +using MQTTnet; +using Microsoft.Extensions.Logging; +using SlnMesnac.Serilog; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Mqtt +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Mqtt +{ + /// + /// MQTT客户端 + /// + public class MqttClient + { + public readonly SerilogHelper _logger; + + private IMqttClient _client; + + public MqttClient(SerilogHelper logger) + { + _logger = logger; + } + + /// + /// 链接服务器 + /// + /// + /// + /// + /// + /// + public async void Connect(string ip, int port, string clientId, string username, string password) + { + try + { + MqttClientOptions options = new MqttClientOptionsBuilder() + .WithTcpServer(ip, port) + .WithClientId(clientId) + .WithCredentials(username, password) + .WithTls(o => //开启ssl + { + o.CertificateValidationHandler = _ => true; + + o.SslProtocol = SslProtocols.Tls12; + }) + .Build(); + _client = new MqttFactory().CreateMqttClient(); + + _client.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceived; + + MqttClientConnectResult result = await _client.ConnectAsync(options); + + if (result != null) + { + if (result.ResultCode == MQTTnet.Client.MqttClientConnectResultCode.Success) + { + _logger.Info($"连接服务器成功{ip}:{port}"); + } + else + { + _logger.Info($"连接服务器失败"); + } + } + } + catch (Exception ex) + { + _logger.Error("连接服务器异常",ex); + } + } + + /// + /// 断开链接 + /// + public void DisConnect() + { + _client.DisconnectAsync(); + _logger.Info($"断开连接"); + } + + /// + /// 订阅主题 + /// + /// + public async void SubscriptionAsync(string topic) + { + try + { + var mqttFactory = new MqttFactory(); + var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder() + .WithTopicFilter( + f => + { + f.WithTopic(topic); + }) + .Build(); + + MqttClientSubscribeResult result = await _client.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None); + + _logger.Info($"订阅主题:{topic}"); + } + catch (Exception ex) + { + _logger.Error("订阅主题异常",ex); + } + } + + /// + /// 取消订阅 + /// + /// + public void Unsubscribe(string topic) + { + _client.UnsubscribeAsync(topic); + _logger.Info($"取消订阅,主题:{topic}"); + } + + /// + /// 推送消息 + /// + /// + /// + public void Publish(string topic, string message) + { + try + { + var msg = new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(message) + .Build(); + _client.PublishAsync(msg, CancellationToken.None); + _logger.Info($"向服务端推送成功,主题:{topic};内容:{message}"); + } + catch (Exception ex) + { + _logger.Error("向服务端推送消息异常",ex); + } + } + + private async Task MqttClient_ApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs eventArgs) + { + var info = $"接收到主题:{eventArgs.ApplicationMessage.Topic}的消息,内容:{Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)}"; + _logger.Info(info); + } + + } +} diff --git a/SlnMesnac.Mqtt/SlnMesnac.Mqtt.csproj b/SlnMesnac.Mqtt/SlnMesnac.Mqtt.csproj new file mode 100644 index 0000000..659191d --- /dev/null +++ b/SlnMesnac.Mqtt/SlnMesnac.Mqtt.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + diff --git a/SlnMesnac.Plc/Factory/InovanceFactory.cs b/SlnMesnac.Plc/Factory/InovanceFactory.cs new file mode 100644 index 0000000..d9eebc1 --- /dev/null +++ b/SlnMesnac.Plc/Factory/InovanceFactory.cs @@ -0,0 +1,346 @@ +using System; +using HslCommunication; +using HslCommunication.Profinet.Inovance; +using SlnMesnac.Common; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Plc.Factory +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Plc.Factory +{ + public class InovanceFactory:PlcAbsractFactory + { + private StringChange _stringChange; + + private InovanceTcpNet inovanceTcp = null; + + public InovanceFactory(StringChange stringChange) + { + _stringChange = stringChange; + + this.inovanceTcp = new InovanceTcpNet(); + this.inovanceTcp.ConnectTimeOut = 2000; + } + + public override bool IsConnected { get; set; } + + /// + /// 建立连接 + /// + /// + /// + /// + /// + public override bool Connect(string ip, int port) + { + try + { + inovanceTcp?.ConnectClose(); + if (inovanceTcp != null) + { + inovanceTcp.IpAddress = ip; + inovanceTcp.Port = port; + inovanceTcp.DataFormat = HslCommunication.Core.DataFormat.CDAB; + + OperateResult connect = inovanceTcp.ConnectServer(); + this.IsConnected = connect.IsSuccess; + if (!connect.IsSuccess) + { + throw new InvalidOperationException($"汇川PLC连接失败:{connect.Message}"); + } + + return connect.IsSuccess; + } + else + { + throw new ArgumentException($"汇川PLC实例inovanceTcp为null"); + } + } + catch (Exception ex) + { + throw new InvalidOperationException($"汇川PLC连接异常:{ex.Message}"); + } + } + + /// + /// 断开连接 + /// + /// + /// + public override bool DisConnect() + { + try + { + OperateResult disConnect = inovanceTcp.ConnectClose(); + this.IsConnected = false; + if (!disConnect.IsSuccess) + { + throw new InvalidOperationException($"汇川PLC断开连接失败:{disConnect.Message}"); + } + return disConnect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"汇川PLC断开连接异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取指定长度数据 + /// + /// + /// + /// + /// + public override byte[] readValueByAddress(string address, int len) + { + try + { + OperateResult read = inovanceTcp.Read(address, (ushort)(len)); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据失败:{read.Message}"); + } + return _stringChange.ConvertFloatToINt(read.Content); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取int16数据 + /// + /// + /// + /// + public override int readInt16ByAddress(string address) + { + try + { + OperateResult read = inovanceTcp.ReadInt16(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址写入int16数据 + /// + /// + /// + /// + /// + public override bool writeInt16ByAddress(string address, int value) + { + try + { + OperateResult operateResult = new OperateResult(); + int s = 0; + string[] strArry = address.Split('.'); + + //先读取整个块的内容 + var info = inovanceTcp.ReadInt16(strArry[0]); + if (info.Content == 0) + { + int length = _stringChange.ParseToInt(strArry[1]) + 1; + string[] array = new string[length]; + for (int i = 0; i < length; i++) + { + if (i == _stringChange.ParseToInt(strArry[1])) + { + array[i] = value.ToString(); + } + else + { + array[i] = "0"; + } + } + //反转 + Array.Reverse(array); + byte[] buffer = new byte[array.Length]; + string result = ""; + for (int i = 0; i < array.Length; i++) + { + result += (byte)Convert.ToInt32(array[i], 16); + } + s = Convert.ToInt32(result.Trim(), 2); + operateResult = inovanceTcp.Write(strArry[0], (ushort)s); + } + else + { + var inf2 = Convert.ToString(info.Content, 2); + string[] infoArray = new string[inf2.Length]; + for (int i = 0; i < inf2.Length; i++) + { + infoArray[i] = inf2.Substring(i, 1); + } + Array.Reverse(infoArray); + infoArray[_stringChange.ParseToInt(strArry[1])] = value.ToString(); + string result = ""; + foreach (var item in infoArray) + { + result = result + item; + } + s = Convert.ToInt32(result.Trim(), 10); + operateResult = inovanceTcp.Write(strArry[0], s); + } + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取string类型数据 + /// + /// + /// + /// + /// + public override string readStringByAddress(string address, ushort length) + { + try + { + OperateResult read = inovanceTcp.ReadString(address, length); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入String类型数据 + /// + /// + /// + /// + /// + public override bool writeStringByAddress(string address, string value) + { + try + { + OperateResult operateResult = inovanceTcp.Write(address, value); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取Bool类型数据 + /// + /// + /// + /// + public override bool readBoolByAddress(string address) + { + try + { + OperateResult read = inovanceTcp.ReadBool(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Bool类型数据 + /// + /// + /// + /// + /// + public override bool writeBoolByAddress(string address, bool value) + { + try + { + OperateResult operateResult = inovanceTcp.Write(address, short.Parse(_stringChange.ParseToInt(value ? "1" : "0").ToString())); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Double类型数据 + /// + /// + /// + /// + /// + public override bool writeDoubleByAddress(string address, int value) + { + try + { + OperateResult operateResult = inovanceTcp.Write(address, Convert.ToDouble(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据异常:{ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/SlnMesnac.Plc/Factory/MelsecBinaryFactory.cs b/SlnMesnac.Plc/Factory/MelsecBinaryFactory.cs new file mode 100644 index 0000000..28b9a8e --- /dev/null +++ b/SlnMesnac.Plc/Factory/MelsecBinaryFactory.cs @@ -0,0 +1,287 @@ +using System; +using HslCommunication; +using HslCommunication.Profinet.Melsec; +using SlnMesnac.Common; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Plc.Factory +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Plc.Factory +{ + public class MelsecBinaryFactory:PlcAbsractFactory + { + private StringChange _stringChange; + + private MelsecMcNet melsec_net = null; + + public MelsecBinaryFactory(StringChange stringChange) + { + _stringChange = stringChange; + + this.melsec_net = new MelsecMcNet(); + this.melsec_net.ConnectTimeOut = 2000; + } + + public override bool IsConnected { get; set; } + + /// + /// 建立连接 + /// + /// + /// + /// + /// + public override bool Connect(string iP, int port) + { + try + { + melsec_net.IpAddress = iP; + melsec_net.Port = port; + OperateResult connect = melsec_net.ConnectServer(); + this.IsConnected = connect.IsSuccess; + if (!connect.IsSuccess) + { + throw new InvalidOperationException($"三菱PLC连接失败:{connect.Message}"); + } + + return connect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"三菱PLC连接异常:{ex.Message}"); + } + } + + /// + /// 断开连接 + /// + /// + /// + public override bool DisConnect() + { + try + { + OperateResult disConnect = melsec_net.ConnectClose(); + this.IsConnected = false; + if (!disConnect.IsSuccess) + { + throw new InvalidOperationException($"三菱PLC断开连接失败:{disConnect.Message}"); + } + return disConnect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"三菱PLC断开连接异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取指定长度数据 + /// + /// + /// + /// + /// + public override byte[] readValueByAddress(string address, int len) + { + try + { + OperateResult read = melsec_net.Read(address, (ushort)(len)); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据失败:{read.Message}"); + } + return _stringChange.ConvertFloatToINt(read.Content); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取int16数据 + /// + /// + /// + /// + public override int readInt16ByAddress(string address) + { + try + { + OperateResult read = melsec_net.ReadInt16(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址写入int16数据 + /// + /// + /// + /// + /// + public override bool writeInt16ByAddress(string address, int value) + { + try + { + OperateResult operateResult = melsec_net.Write(address, Convert.ToInt16(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取string类型数据 + /// + /// + /// + /// + /// + public override string readStringByAddress(string address, ushort length) + { + try + { + OperateResult read = melsec_net.ReadString(address, length); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入String类型数据 + /// + /// + /// + /// + /// + public override bool writeStringByAddress(string address, string value) + { + try + { + OperateResult operateResult = melsec_net.Write(address, value); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取Bool类型数据 + /// + /// + /// + /// + public override bool readBoolByAddress(string address) + { + try + { + OperateResult read = melsec_net.ReadBool(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Bool类型数据 + /// + /// + /// + /// + /// + public override bool writeBoolByAddress(string address, bool value) + { + try + { + OperateResult operateResult = melsec_net.Write(address, short.Parse(_stringChange.ParseToInt(value ? "1" : "0").ToString())); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Double类型数据 + /// + /// + /// + /// + /// + public override bool writeDoubleByAddress(string address, int value) + { + try + { + OperateResult operateResult = melsec_net.Write(address, Convert.ToDouble(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据异常:{ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/SlnMesnac.Plc/Factory/OmronNJFactory.cs b/SlnMesnac.Plc/Factory/OmronNJFactory.cs new file mode 100644 index 0000000..a3812e9 --- /dev/null +++ b/SlnMesnac.Plc/Factory/OmronNJFactory.cs @@ -0,0 +1,290 @@ +using System; +using HslCommunication; +using HslCommunication.Profinet.Omron; +using SlnMesnac.Common; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Plc.Factory +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Plc.Factory +{ + public class OmronNJFactory:PlcAbsractFactory + { + private StringChange _stringChange; + + private OmronFinsNet omronFinsNet = null; + + public OmronNJFactory(StringChange stringChange) + { + _stringChange = stringChange; + + this.omronFinsNet = new OmronFinsNet(); + this.omronFinsNet.ConnectTimeOut = 2000; + } + + public override bool IsConnected { get; set; } + + /// + /// 建立连接 + /// + /// + /// + /// + /// + public override bool Connect(string iP, int port) + { + try + { + omronFinsNet.IpAddress = iP; + omronFinsNet.Port = 9600; + omronFinsNet.SA1 = (byte)192; + omronFinsNet.DA1 = (byte)239; + omronFinsNet.DA2 = (byte)0; + OperateResult connect = omronFinsNet.ConnectServer(); + this.IsConnected = connect.IsSuccess; + if (!connect.IsSuccess) + { + throw new InvalidOperationException($"欧姆龙PLC连接失败:{connect.Message}"); + } + + return connect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"欧姆龙PLC连接异常:{ex.Message}"); + } + } + + /// + /// 断开连接 + /// + /// + /// + public override bool DisConnect() + { + try + { + OperateResult disConnect = omronFinsNet.ConnectClose(); + this.IsConnected = false; + if (!disConnect.IsSuccess) + { + throw new InvalidOperationException($"欧姆龙PLC断开连接失败:{disConnect.Message}"); + } + return disConnect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"欧姆龙PLC断开连接异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取指定长度数据 + /// + /// + /// + /// + /// + public override byte[] readValueByAddress(string address, int len) + { + try + { + OperateResult read = omronFinsNet.Read(address, (ushort)(len)); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据失败:{read.Message}"); + } + return _stringChange.ConvertFloatToINt(read.Content); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取int16数据 + /// + /// + /// + /// + public override int readInt16ByAddress(string address) + { + try + { + OperateResult read = omronFinsNet.ReadInt16(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址写入int16数据 + /// + /// + /// + /// + /// + public override bool writeInt16ByAddress(string address, int value) + { + try + { + OperateResult operateResult = omronFinsNet.Write(address, Convert.ToInt16(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取string类型数据 + /// + /// + /// + /// + /// + public override string readStringByAddress(string address, ushort length) + { + try + { + OperateResult read = omronFinsNet.ReadString(address, length); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入String类型数据 + /// + /// + /// + /// + /// + public override bool writeStringByAddress(string address, string value) + { + try + { + OperateResult operateResult = omronFinsNet.Write(address, value); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取Bool类型数据 + /// + /// + /// + /// + public override bool readBoolByAddress(string address) + { + try + { + OperateResult read = omronFinsNet.ReadBool(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Bool类型数据 + /// + /// + /// + /// + /// + public override bool writeBoolByAddress(string address, bool value) + { + try + { + OperateResult operateResult = omronFinsNet.Write(address, short.Parse(_stringChange.ParseToInt(value ? "1" : "0").ToString())); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Double类型数据 + /// + /// + /// + /// + /// + public override bool writeDoubleByAddress(string address, int value) + { + try + { + OperateResult operateResult = omronFinsNet.Write(address, Convert.ToDouble(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据异常:{ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/SlnMesnac.Plc/Factory/SiemensFactory.cs b/SlnMesnac.Plc/Factory/SiemensFactory.cs new file mode 100644 index 0000000..2e0ed6d --- /dev/null +++ b/SlnMesnac.Plc/Factory/SiemensFactory.cs @@ -0,0 +1,287 @@ +using System; +using HslCommunication; +using HslCommunication.Profinet.Siemens; +using SlnMesnac.Common; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Plc.Factory +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Plc.Factory +{ + public class SiemensFactory:PlcAbsractFactory + { + + private StringChange _stringChange; + + private const SiemensPLCS type = SiemensPLCS.S200Smart; + + private SiemensS7Net s7 = new SiemensS7Net(type); + + public SiemensFactory(StringChange stringChange) + { + _stringChange = stringChange; + } + + public override bool IsConnected { get; set; } + + /// + /// 建立连接 + /// + /// + /// + /// + /// + public override bool Connect(string iP, int port) + { + try + { + s7.IpAddress = iP; + s7.Port = 102; + OperateResult connect = s7.ConnectServer(); + this.IsConnected = connect.IsSuccess; + if (!connect.IsSuccess) + { + throw new InvalidOperationException($"西门子S系列PLC连接失败:{connect.Message}"); + } + + return connect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"西门子S系列PLC连接异常:{ex.Message}"); + } + } + + /// + /// 断开连接 + /// + /// + /// + public override bool DisConnect() + { + try + { + OperateResult disConnect = s7.ConnectClose(); + this.IsConnected = false; + if (!disConnect.IsSuccess) + { + throw new InvalidOperationException($"西门子S系列PLC断开连接失败:{disConnect.Message}"); + } + return disConnect.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"西门子S系列PLC断开连接异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取指定长度数据 + /// + /// + /// + /// + /// + public override byte[] readValueByAddress(string address, int len) + { + try + { + OperateResult read = s7.Read(address, (ushort)(len)); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据失败:{read.Message}"); + } + return _stringChange.ConvertFloatToINt(read.Content); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取指定长度数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址读取int16数据 + /// + /// + /// + /// + public override int readInt16ByAddress(string address) + { + try + { + OperateResult read = s7.ReadInt16(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取int16数据异常:{ex.Message}"); + } + } + + /// + /// 根据地址写入int16数据 + /// + /// + /// + /// + /// + public override bool writeInt16ByAddress(string address, int value) + { + try + { + OperateResult operateResult = s7.Write(address, Convert.ToInt16(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入int16数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取string类型数据 + /// + /// + /// + /// + /// + public override string readStringByAddress(string address, ushort length) + { + try + { + OperateResult read = s7.ReadString(address, length); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入String类型数据 + /// + /// + /// + /// + /// + public override bool writeStringByAddress(string address, string value) + { + try + { + OperateResult operateResult = s7.Write(address, value); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入string数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址读取Bool类型数据 + /// + /// + /// + /// + public override bool readBoolByAddress(string address) + { + try + { + OperateResult read = s7.ReadBool(address); + if (!read.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据失败:{read.Content}"); + } + return read.Content; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};读取bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Bool类型数据 + /// + /// + /// + /// + /// + public override bool writeBoolByAddress(string address, bool value) + { + try + { + OperateResult operateResult = s7.Write(address, short.Parse(_stringChange.ParseToInt(value ? "1" : "0").ToString())); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入bool数据异常:{ex.Message}"); + } + } + + /// + /// 通过PLC地址写入Double类型数据 + /// + /// + /// + /// + /// + public override bool writeDoubleByAddress(string address, int value) + { + try + { + OperateResult operateResult = s7.Write(address, Convert.ToDouble(value)); + if (!operateResult.IsSuccess) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据失败:{operateResult.Message}"); + } + return operateResult.IsSuccess; + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据地址:{address};写入double数据异常:{ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/SlnMesnac.Plc/PlcAbsractFactory.cs b/SlnMesnac.Plc/PlcAbsractFactory.cs new file mode 100644 index 0000000..049cf0a --- /dev/null +++ b/SlnMesnac.Plc/PlcAbsractFactory.cs @@ -0,0 +1,109 @@ +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Plc +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Plc +{ + public abstract class PlcAbsractFactory + { + + public string ConfigKey { get;set; } + + /// + /// 是否连接 + /// + public abstract bool IsConnected { get; set; } + + /// + /// 建立连接 + /// + /// + /// + /// + public abstract bool Connect(string ip, int port); + + /// + /// 断开连接 + /// + /// + public abstract bool DisConnect(); + + /// + /// 根据地址读取指定长度数据 + /// + /// + /// + /// + public abstract byte[] readValueByAddress(string address,int len); + + /// + /// 通过PLC地址读取int16类型数据 + /// + /// + /// + public abstract int readInt16ByAddress(string address); + + /// + /// 通过PLC地址写入int16类型数据 + /// + /// + /// + /// + public abstract bool writeInt16ByAddress(string address,int value); + + /// + /// 通过PLC地址读取string类型数据 + /// + /// + /// + public abstract string readStringByAddress(string address, ushort length); + + /// + /// 通过PLC地址写入String类型数据 + /// + /// + /// + /// + public abstract bool writeStringByAddress(string address, string value); + + /// + /// 通过PLC地址读取Bool类型数据 + /// + /// + /// + public abstract bool readBoolByAddress(string address); + + /// + /// 通过PLC地址写入Bool类型数据 + /// + /// + /// + public abstract bool writeBoolByAddress(string address, bool value); + + /// + /// 通过PLC地址写入Double类型数据 + /// + /// + /// + /// + public abstract bool writeDoubleByAddress(string address, int value); + } +} \ No newline at end of file diff --git a/SlnMesnac.Plc/SlnMesnac.Plc.csproj b/SlnMesnac.Plc/SlnMesnac.Plc.csproj new file mode 100644 index 0000000..4074e53 --- /dev/null +++ b/SlnMesnac.Plc/SlnMesnac.Plc.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + + + diff --git a/SlnMesnac.Quartz/Job/Job2.cs b/SlnMesnac.Quartz/Job/Job2.cs new file mode 100644 index 0000000..cf4623c --- /dev/null +++ b/SlnMesnac.Quartz/Job/Job2.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.Logging; +using Quartz; +using SlnMesnac.Serilog; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Quartz.Job +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Quartz.Job +{ + internal class Job2 : IJob + { + private readonly SerilogHelper _logger; + + public Job2(SerilogHelper logger) + { + _logger = logger; + } + + public Task Execute(IJobExecutionContext context) + { + _logger.Info($"执行Job2:{DateTime.Now.ToString("HH:mm:ss")}"); + return Task.CompletedTask; + } + } +} diff --git a/SlnMesnac.Quartz/Job/MyJob.cs b/SlnMesnac.Quartz/Job/MyJob.cs new file mode 100644 index 0000000..e12d7ba --- /dev/null +++ b/SlnMesnac.Quartz/Job/MyJob.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.Logging; +using Quartz; +using SlnMesnac.Serilog; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Quartz.Job +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Quartz.Job +{ + public class MyJob : IJob + { + private readonly SerilogHelper _logger; + + public MyJob(SerilogHelper logger) + { + _logger = logger; + } + + public Task Execute(IJobExecutionContext context) + { + _logger.Info($"执行MyJob:{DateTime.Now.ToString("HH:mm:ss")}"); + return Task.CompletedTask; + } + } +} diff --git a/SlnMesnac.Quartz/QuartzSetUp.cs b/SlnMesnac.Quartz/QuartzSetUp.cs new file mode 100644 index 0000000..1a6bb23 --- /dev/null +++ b/SlnMesnac.Quartz/QuartzSetUp.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using SlnMesnac.Quartz.Job; +using System; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Quartz +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Quartz +{ + public static class QuartzSetUp + { + [Obsolete] + public static void AddQuartzSetUp(this IServiceCollection services) + { + services.AddQuartz(q => + { + q.UseMicrosoftDependencyInjectionJobFactory(); + + q.ScheduleJob(trigger => + trigger.WithCronSchedule("*/3 * * * * ?").WithIdentity("MyJob", "MyJobGroup") // 示例:每3s执行一次 + ); + + q.ScheduleJob(trigger => + trigger.WithCronSchedule("*/5 * * * * ?").WithIdentity("Job2", "Job2Group") // 示例:每5s执行一次 + ); + }); + + services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true); + + services.AddSingleton(provider => provider.GetRequiredService().GetScheduler().Result); + + } + } +} diff --git a/SlnMesnac.Quartz/SlnMesnac.Quartz.csproj b/SlnMesnac.Quartz/SlnMesnac.Quartz.csproj new file mode 100644 index 0000000..344e515 --- /dev/null +++ b/SlnMesnac.Quartz/SlnMesnac.Quartz.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + diff --git a/SlnMesnac.Redis/RedisHandler.cs b/SlnMesnac.Redis/RedisHandler.cs new file mode 100644 index 0000000..7501351 --- /dev/null +++ b/SlnMesnac.Redis/RedisHandler.cs @@ -0,0 +1,93 @@ +using Microsoft.Extensions.Logging; +using SlnMesnac.Config; +using SlnMesnac.Serilog; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Redis +* 唯一标识:00418016-53c9-4f87-a13f-daa19d656bba +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-12 15:15:25 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Redis +{ + public class RedisHandler + { + private SerilogHelper _logger; + + private readonly AppConfig _appConfig; + + private readonly ISubscriber _subscriber; + + private readonly ConnectionMultiplexer redis; + + public RedisHandler(AppConfig appConfig, SerilogHelper logger) + { + _appConfig = appConfig; + + redis = ConnectionMultiplexer.Connect(_appConfig.redisConfig); + _subscriber = redis.GetSubscriber(); + _logger = logger; + } + + + + /// + /// 推送消息 + /// + /// + /// + public void PublishMessage(string channel, string message) + { + long res = _subscriber.Publish(channel, message); + + _logger.Info($"向主题:{channel};推送消息:{message};结果:{res}"); + } + + /// + /// 订阅消息 + /// + /// + /// + public void SubscribeToChannel(string channel, Action onMessageReceived) + { + _subscriber.Subscribe(channel, (ch, message) => + { + onMessageReceived(ch, message); + _logger.Info($"订阅主题:{channel};收到主题:{ch};推送的消息:{message}"); + }); + } + + public void CleanExpiredMessages(string channel) + { + var redis = _subscriber.Multiplexer.GetDatabase(); + redis.KeyDelete(channel); + } + + public void SetValue(string key, string message) + { + IDatabase db = redis.GetDatabase(0); + TimeSpan expiry = TimeSpan.FromSeconds(10); + db.StringSet(key, message, expiry); + } + } +} diff --git a/SlnMesnac.Redis/SlnMesnac.Redis.csproj b/SlnMesnac.Redis/SlnMesnac.Redis.csproj new file mode 100644 index 0000000..9d4e6d6 --- /dev/null +++ b/SlnMesnac.Redis/SlnMesnac.Redis.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + diff --git a/SlnMesnac.Repository/Repository.cs b/SlnMesnac.Repository/Repository.cs new file mode 100644 index 0000000..7216a1c --- /dev/null +++ b/SlnMesnac.Repository/Repository.cs @@ -0,0 +1,42 @@ +using SqlSugar; +using System; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Repository +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Repository +{ + public class Repository : SimpleClient where T : class, new() + { + public ITenant itenant = null;//多租户事务、GetConnection、IsAnyConnection等功能 + + public Repository(ISqlSugarClient db) + { + itenant = db.AsTenant();//用来处理事务 + base.Context = db.AsTenant().GetConnectionScopeWithAttr();//获取子Db + + //如果不想通过注入多个仓储 + //用到ChangeRepository或者Db.GetMyRepository需要看标题4写法 + } + + } +} \ No newline at end of file diff --git a/SlnMesnac.Repository/SlnMesnac.Repository.csproj b/SlnMesnac.Repository/SlnMesnac.Repository.csproj new file mode 100644 index 0000000..50714c1 --- /dev/null +++ b/SlnMesnac.Repository/SlnMesnac.Repository.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + + + + diff --git a/SlnMesnac.Repository/service/IBaseMaterialService.cs b/SlnMesnac.Repository/service/IBaseMaterialService.cs new file mode 100644 index 0000000..5e3e59e --- /dev/null +++ b/SlnMesnac.Repository/service/IBaseMaterialService.cs @@ -0,0 +1,62 @@ +using SlnMesnac.Model.domain; +using SlnMesnac.Repository.service.@base; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Repository.service +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Repository.service +{ + public interface IBaseMaterialService : IBaseService + { + + /// + /// 获取所有的物料信息 + /// + /// + List GetMaterialInfos(); + + /// + /// 通过物料编码获取物料信息 + /// + /// + /// + BaseMaterialInfo GetMaterialInfoByMaterialCode(string materialCode); + + /// + /// 通过SAP物料编码获取物料信息 + /// + /// + /// + BaseMaterialInfo GetMaterialInfoBySapMaterialCode(string sapMaterialCode); + + /// + /// 通过物料类别获取物料信息 + /// + /// 物料大类 + /// 物料细类 + /// + List GetMaterialInfosByMaterialType(int majorTypeId, string minorTypeId); + } +} diff --git a/SlnMesnac.Repository/service/IBaseUserService.cs b/SlnMesnac.Repository/service/IBaseUserService.cs new file mode 100644 index 0000000..d1ece41 --- /dev/null +++ b/SlnMesnac.Repository/service/IBaseUserService.cs @@ -0,0 +1,46 @@ +using SlnMesnac.Model.domain; +using SlnMesnac.Repository.service.@base; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Repository.service +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Repository.service +{ + public interface IBaseUserService:IBaseService + { + /// + /// 获取用户信息 + /// + /// + List GetUsers(); + + /// + /// 验证添加用户信息,有一个错误时进行回滚 + /// + /// + /// + bool InsertUsers(List users); + } +} diff --git a/SlnMesnac.Repository/service/Impl/BaseMaterialServiceImpl.cs b/SlnMesnac.Repository/service/Impl/BaseMaterialServiceImpl.cs new file mode 100644 index 0000000..71e33bc --- /dev/null +++ b/SlnMesnac.Repository/service/Impl/BaseMaterialServiceImpl.cs @@ -0,0 +1,132 @@ +using Microsoft.Extensions.Logging; +using SlnMesnac.Model.domain; +using SlnMesnac.Common; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text; +using SlnMesnac.Repository.service.@base; +using SlnMesnac.Serilog; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Repository.service.Impl +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Repository.service.Impl +{ + public class BaseMaterialServiceImpl : BaseServiceImpl, IBaseMaterialService + { + private SerilogHelper _logger; + + public BaseMaterialServiceImpl(Repository repository, SerilogHelper logger) :base(repository) + { + _logger = logger; + } + + /// + /// 通过物料编码获取物料信息 + /// + /// + /// + public BaseMaterialInfo GetMaterialInfoByMaterialCode(string materialCode) + { + BaseMaterialInfo materialInfo = null; + try + { + materialInfo = base._rep.GetFirst(x => x.MaterialCode == materialCode); + } + catch (Exception ex) + { + _logger.Error($"根据物料编号获取物料信息异常:{ex.Message}"); + } + return materialInfo; + } + + /// + /// 通过SAP物料编码获取物料信息 + /// + /// + /// + public BaseMaterialInfo GetMaterialInfoBySapMaterialCode(string sapMaterialCode) + { + BaseMaterialInfo materialInfo = null; + try + { + materialInfo = base._rep.GetFirst(x => x.SAPMaterialCode == sapMaterialCode); + } + catch (Exception ex) + { + _logger.Error($"根据SAP物料编号获取物料信息异常:{ex.Message}"); + } + return materialInfo; + } + + /// + /// 获取所有的物料信息 + /// + /// + public List GetMaterialInfos() + { + List materialInfos = null; + try + { + materialInfos = base._rep.GetList(); + } + catch (Exception ex) + { + _logger.Error($"获取物料信息异常:{ex.Message}"); + } + return materialInfos; + } + + /// + /// 通过物料类别获取物料信息 + /// + /// 物料大类 + /// 物料细类 + /// + public List GetMaterialInfosByMaterialType(int majorTypeId, string minorTypeId) + { + List materialInfos = null; + try + { + Expression> exp = x => true; + + if (majorTypeId != 0) + { + exp = exp.And(x => x.MajorTypeID == majorTypeId); + } + else if (!string.IsNullOrEmpty(minorTypeId)) + { + exp = exp.And(x => x.MinorTypeID == minorTypeId); + } + + materialInfos = base._rep.GetList(exp); + } + catch (Exception ex) + { + _logger.Error($"通过物料类型获取物料信息异常:{ex.Message}"); + } + return materialInfos; + } + } +} + diff --git a/SlnMesnac.Repository/service/Impl/BaseUserServiceImpl.cs b/SlnMesnac.Repository/service/Impl/BaseUserServiceImpl.cs new file mode 100644 index 0000000..1e33e08 --- /dev/null +++ b/SlnMesnac.Repository/service/Impl/BaseUserServiceImpl.cs @@ -0,0 +1,76 @@ +using Microsoft.Extensions.Logging; +using SlnMesnac.Model.domain; +using SlnMesnac.Repository.service.@base; +using SlnMesnac.Serilog; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Repository.service.Impl +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Repository.service.Impl +{ + public class BaseUserServiceImpl : BaseServiceImpl,IBaseUserService + { + private readonly SerilogHelper _logger; + + public BaseUserServiceImpl(Repository rep, SerilogHelper logger) :base(rep) + { + _logger = logger; + } + + + public List GetUsers() + { + List users = null; + try + { + users = base._rep.GetList(); + } + catch (Exception ex) + { + _logger.Error($"获取用户信息异常{ex.Message}"); + } + return users; + } + + public bool InsertUsers(List users) + { + bool result = false; + try + { + base._rep.AsTenant().BeginTran(); + + result = base._rep.InsertRange(users); + + base._rep.AsTenant().CommitTran(); + } + catch (Exception ex) + { + base._rep.AsTenant().RollbackTran(); + _logger.Error($"用户信息添加异常:{ex.Message}"); + } + return result; + } + } +} diff --git a/SlnMesnac.Repository/service/base/BaseServiceImpl.cs b/SlnMesnac.Repository/service/base/BaseServiceImpl.cs new file mode 100644 index 0000000..2227110 --- /dev/null +++ b/SlnMesnac.Repository/service/base/BaseServiceImpl.cs @@ -0,0 +1,358 @@ +using Microsoft.Extensions.Logging; +using SlnMesnac.Repository.service.@base; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Repository.service.Impl +* 唯一标识:70cc8c3a-2c3b-4034-894b-f1a4f04aa21e +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-08 09:49:07 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Repository.service.@base +{ + public class BaseServiceImpl : IBaseService where T : class, new() + { + public readonly Repository _rep; + + public BaseServiceImpl(Repository rep) + { + _rep = rep; + } + + /// + /// 添加实体信息 + /// + /// + /// + /// + /// + public bool Insert(T model) + { + if (model == null) + { + throw new ArgumentNullException($"添加实体信息异常:实体参数为空"); + } + + try + { + return _rep.Insert(model); + } + catch (Exception ex) + { + throw new InvalidOperationException($"添加实体信息异常:{ex.Message}"); + } + + } + + /// + /// 批量添加实体集合 + /// + /// + /// + /// + /// + public bool Insert(List lisT) + { + if (lisT == null) + { + throw new ArgumentNullException($"批量添加实体集合异常:实体集合参数为空"); + } + try + { + _rep.AsTenant().BeginTran(); + var info = _rep.InsertRange(lisT); + _rep.AsTenant().CommitTran(); + return true; + } + catch (Exception ex) + { + _rep.AsTenant().RollbackTran(); + throw new InvalidOperationException($"批量添加实体集合异常:{ex.Message}"); + } + } + + /// + /// 根据id 删除信息 + /// + /// + /// + /// + public bool DeleteById(object id) + { + if (id == null) + { + throw new ArgumentNullException($"根据id删除信息异常:Id参数为空"); + } + try + { + return _rep.DeleteById(id); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据id删除信息异常:{ex.Message}"); + } + } + + /// + /// 根据实体删除信息 + /// + /// + /// + /// + /// + public bool Delete(T model) + { + if (model == null) + { + throw new ArgumentNullException($"根据实体删除信息异常:实体参数为空"); + } + try + { + return _rep.DeleteById(model); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据实体删除信息异常:{ex.Message}"); + } + } + + /// + /// 根据实体集合批量删除信息 + /// + /// + /// + /// + public bool Deletes(List entitys) + { + if (entitys == null) + { + throw new ArgumentNullException($"根据实体集合批量删除信息异常:实体集合参数为空"); + } + try + { + return _rep.Delete(entitys); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据实体集合批量删除信息异常:{ex.Message}"); + } + } + + /// + /// 根据实体更新信息 + /// + /// + /// + /// + public bool Update(T model) + { + if (model == null) + { + throw new ArgumentNullException($"根据实体更新信息异常:实体参数为空"); + } + try + { + return _rep.Update(model); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据实体更新信息异常:{ex.Message}"); + } + } + + /// + /// 批量更新实体集合信息 + /// + /// + /// + /// + public bool Update(List entitys) + { + if (entitys == null) + { + throw new ArgumentNullException($"批量更新实体集合信息异常:实体集合参数为空"); + } + + try + { + return _rep.UpdateRange(entitys); + } + catch (Exception ex) + { + throw new InvalidOperationException($"批量更新实体集合信息异常:{ex.Message}"); + } + } + + /// + /// 根据Where条件更新实体信息 + /// + /// + /// + /// + public bool Update(T entity, string strWhere) + { + if (entity == null) + { + throw new ArgumentNullException($"根据Where条件更新实体信息异常:实体参数为空"); + } + + if (string.IsNullOrEmpty(strWhere)) + { + throw new ArgumentNullException($"根据Where条件更新实体信息异常:Where参数为空"); + } + + try + { + return _rep.AsUpdateable(entity).Where(strWhere).ExecuteCommandHasChange(); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据Where条件更新实体信息异常:{ex.Message}"); + } + } + + /// + /// 根据实体更新指定列 + /// + /// + /// + /// + /// + /// + public bool Update(T entity, List lstColumns = null, List lstIgnoreColumns = null, string strWhere = "") + { + try + { + IUpdateable up = _rep.AsUpdateable(entity); + if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0) + { + up = up.IgnoreColumns(lstIgnoreColumns.ToArray()); + } + if (lstColumns != null && lstColumns.Count > 0) + { + up = up.UpdateColumns(lstColumns.ToArray()); + } + if (!string.IsNullOrEmpty(strWhere)) + { + up = up.Where(strWhere); + } + return up.ExecuteCommandHasChange(); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据实体更新指定列异常:{ex.Message}"); + } + } + + /// + /// 查询所有信息 + /// + /// + /// + public List Query() + { + try + { + return _rep.GetList(); + } + catch (Exception ex) + { + throw new InvalidOperationException($"查询所有信息异常:{ex.Message}"); + } + } + + /// + /// 根据Id查询实体 + /// + /// + /// + /// + public T Query(object objId) + { + if (objId == null) + { + throw new ArgumentNullException($"根据Id查询实体信息异常:Id参数为空"); + } + try + { + return _rep.GetById(objId); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据Id查询实体信息异常:{ex.Message}"); + } + } + + /// + /// 根据表达式查询 + /// + /// + /// + /// + public List Query(Expression> whereExpression) + { + if (whereExpression == null) + { + throw new ArgumentNullException($"根据表达式查询实体信息异常:表达式参数为空"); + } + try + { + return _rep.GetList(whereExpression); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据表达式查询实体信息异常:{ex.Message}"); + } + } + + /// + /// 根据表达式排序查询 + /// + /// + /// + /// + /// + /// + public List Query(Expression> whereExpression, Expression> orderByExpression, bool isAsc = true) + { + if (whereExpression == null) + { + throw new ArgumentNullException($"根据表达式排序查询信息异常:条件表达式参数为空"); + } + + if (orderByExpression == null) + { + throw new ArgumentNullException($"根据表达式排序查询信息异常:排序表达式参数为空"); + } + + try + { + return _rep.AsQueryable().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToList(); + } + catch (Exception ex) + { + throw new InvalidOperationException($"根据表达式排序查询信息异常:{ex.Message}"); + } + } + } +} diff --git a/SlnMesnac.Repository/service/base/IBaseService.cs b/SlnMesnac.Repository/service/base/IBaseService.cs new file mode 100644 index 0000000..029ac99 --- /dev/null +++ b/SlnMesnac.Repository/service/base/IBaseService.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text; + +namespace SlnMesnac.Repository.service.@base +{ + public interface IBaseService where T : class + { + /// + /// 添加实体信息 + /// + /// + /// + bool Insert(T model); + + /// + /// 批量添加实体集合 + /// + /// + /// + bool Insert(List lisT); + + /// + /// 根据id 删除信息 + /// + /// + /// + bool DeleteById(object id); + + /// + /// 根据实体删除信息 + /// + /// + /// + bool Delete(T model); + + /// + /// 根据实体集合批量删除信息 + /// + /// + /// + bool Deletes(List entitys); + + /// + /// 根据实体更新信息 + /// + /// + /// + bool Update(T model); + + /// + /// 批量更新实体集合信息 + /// + /// + /// + bool Update(List entitys); + + /// + /// 根据Where条件更新实体信息 + /// + /// + /// + /// + bool Update(T entity, string strWhere); + + /// + /// 根据实体更新指定列 + /// + /// + /// + /// + /// + /// + bool Update(T entity, List lstColumns = null, List lstIgnoreColumns = null, string strWhere = ""); + + /// + /// 查询所有信息 + /// + /// + List Query(); + + /// + /// 根据Id查询实体 + /// + /// + /// + T Query(object objId); + + /// + /// 根据表达式查询 + /// + /// + /// + List Query(Expression> whereExpression); + + /// + /// 根据表达式排序查询 + /// + /// 查询条件 + /// 排序条件 + /// 是否正序 + /// + List Query(Expression> whereExpression, Expression> orderByExpression, bool isAsc = true); + } +} diff --git a/SlnMesnac.Rfid/Dto/MessagePack.cs b/SlnMesnac.Rfid/Dto/MessagePack.cs new file mode 100644 index 0000000..284d42f --- /dev/null +++ b/SlnMesnac.Rfid/Dto/MessagePack.cs @@ -0,0 +1,31 @@ +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Rfid.Dto +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Rfid.Dto +{ + public class MessagePack + { + //public byte m_beginChar1 = 0xBB; //开始包 + public byte[] m_pData = null; //发送数据 + //public byte m_EndChar1 = 0x0D; //结束包 + } +} \ No newline at end of file diff --git a/SlnMesnac.Rfid/Enum/RecvState.cs b/SlnMesnac.Rfid/Enum/RecvState.cs new file mode 100644 index 0000000..f9f1708 --- /dev/null +++ b/SlnMesnac.Rfid/Enum/RecvState.cs @@ -0,0 +1,43 @@ +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Rfid.Enum +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Rfid.Enum +{ + public enum RecvState + { + //RFly-I160 返回数据 BB DD 00 01 40 41 0D + WaitingBeginChar1_State = 1, //等待接收帧同步字符1 0xBB + WaitingBeginChar2_State = 2, //等待接收帧同步字符2 0xDD + WaitingForBarcodeLength_State = 3, //等待条码长度不固定 + WaitingForCode_State = 4, //等待指令编号Code 0x02 + WaitingForStus_State = 5, //等待接受状态码 0x00 + WaitingForTagCount_State = 6, //等待接受标签组数不固定 + WaitingForCount_State = 7, //等待接收第一组标签读取次数 0x01 + WaitingForRSSI_State = 8, //等待接收读取信号强度 0xCB + WaitingForAnt_State = 9, //等待接收天线端口 0x01 + WaitingForPC1_State = 10, //等待接收EPC区域 0x00 + WaitingForPC2_State = 11, //等待接收EPC区域 0x00 + WaitingForData_State = 12, //等待接收数据字符 + WaitingForXor_State = 13, //等待比对校验位 + WaitingForEndChar_State = 14, //等待接收尾字符 0x0D + } +} \ No newline at end of file diff --git a/SlnMesnac.Rfid/Factory/RflyFactory.cs b/SlnMesnac.Rfid/Factory/RflyFactory.cs new file mode 100644 index 0000000..5d9e63b --- /dev/null +++ b/SlnMesnac.Rfid/Factory/RflyFactory.cs @@ -0,0 +1,484 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using SlnMesnac.Common; +using SlnMesnac.Model.dto; +using SlnMesnac.Rfid.Dto; +using SlnMesnac.Rfid.Enum; +using SlnMesnac.Serilog; +using TouchSocket.Core; +using TouchSocket.Sockets; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Rfid.Factory +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Rfid.Factory +{ + public class RflyFactory:RfidAbsractFactory + { + private SerilogHelper _logger; + private readonly TcpClient _tcpClient = new TcpClient(); + private readonly StringChange _stringChange; + + public RflyFactory(SerilogHelper logger,StringChange stringChange) + { + _logger = logger; + _stringChange = stringChange; + } + + /// + /// 建立连接 + /// + /// + /// + /// + /// + public override bool Connect(string ip, int port) + { + try + { + _tcpClient.Setup(new TouchSocketConfig().SetRemoteIPHost($"{ip}:{port}")); + _tcpClient.Connect(); + return true; + } + catch (Exception e) + { + throw new InvalidOperationException($"设备连接异常:{e.Message}"); + } + } + + /// + /// 按时间段盘点 + /// + /// + /// + /// + public override List TimePeriodRead(int timeout = 5000) + { + byte[] u16byte = new byte[2]; + byte[] bCRC = new byte[4]; + try + { + #region 指令封装 + MessagePack pMessagePack = new MessagePack(); + pMessagePack.m_pData = new byte[8]; + pMessagePack.m_pData[0] = 0xAA; + pMessagePack.m_pData[1] = 0x55; + pMessagePack.m_pData[2] = 0x02; + pMessagePack.m_pData[3] = 0x02; + u16byte = BitConverter.GetBytes(timeout); //超时时间 + u16byte = _stringChange.Swap16Bytes(u16byte); //协议里为大端在前 + Array.Copy(u16byte, 0, pMessagePack.m_pData, 4, 2); + Array.Copy(pMessagePack.m_pData, 2, bCRC, 0, 4); + pMessagePack.m_pData[6] = _stringChange.CalculateVerify(bCRC, bCRC.Length); + pMessagePack.m_pData[7] = 0x0D; + #endregion + + var waitClient = _tcpClient.CreateWaitingClient(new WaitingOptions() + { + FilterFunc = response => + { + return true; + } + }); + + byte[] reciveBuffer = waitClient.SendThenReturn(pMessagePack.m_pData, timeout); + + _logger.Info($"接收原始报文:{_stringChange.bytesToHexStr(reciveBuffer,reciveBuffer.Length)}"); + + byte[] resultBuffer = PareReceiveBufferData(reciveBuffer,reciveBuffer.Length); + + List tagInfoList = Device_DealTagInfoList(resultBuffer); + + return tagInfoList; + } + catch (Exception e) + { + throw new InvalidOperationException($"按时间段盘点异常:{e.Message}"); + } + } + + #region 标签解析 + + /// + /// 状态机函数 + /// + /// + /// + /// + /// + private byte[] PareReceiveBufferData(byte[] buffer, int iLen) + { + RecvState enumRecvState = RecvState.WaitingBeginChar1_State; + int m_iPosition = 0; + UInt16 m_iFullMessageLength = 0; + int iBarcodeLength = 0;//条码长度 + ArrayList m_FrecvData = new ArrayList(); + byte m_iVerify = 0; + try + { + var bufferStr = _stringChange.bytesToHexStr(buffer, iLen); + byte[] m_szFullMessage = new byte[iLen]; + for (int i = 0; i < iLen; i++) + { + switch (enumRecvState) + { + case RecvState.WaitingBeginChar1_State: //开始接受数据帧1 0xBB + Array.Clear(m_szFullMessage, 0, iLen);//清空为0 + if (buffer[i] == 0xBB) + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + enumRecvState = RecvState.WaitingBeginChar2_State; + } + else + { + m_iFullMessageLength = 0; + m_iPosition = 0; + enumRecvState = RecvState.WaitingBeginChar1_State; + } + break; + case RecvState.WaitingBeginChar2_State: //开始接受数据帧1 0xDD + if (buffer[i] == 0xDD) + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + enumRecvState = RecvState.WaitingForBarcodeLength_State; + } + else + { + m_iFullMessageLength = 0; + m_iPosition = 0; + enumRecvState = RecvState.WaitingBeginChar1_State; + } + break; + case RecvState.WaitingForBarcodeLength_State: //开始接受数据长度(TagCount - EPC) + m_szFullMessage[m_iPosition] = buffer[i]; + iBarcodeLength = buffer[i]; //单组标签:18;两组标签:35 + m_iPosition++; + enumRecvState = RecvState.WaitingForCode_State; + break; + + case RecvState.WaitingForCode_State: //开始接受指令编号 + if (buffer[i] == 0x02) + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + enumRecvState = RecvState.WaitingForStus_State; + } + else if (buffer[i] == 0x90) // 如果是心跳BB DD 01 90 00 1F 8E 0D + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + enumRecvState = RecvState.WaitingForEndChar_State; + } + else if (buffer[i] == 0xBF) // 如果是心跳BB DD 04 BF 00 00 00 F9 0B 49 0D + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + enumRecvState = RecvState.WaitingForEndChar_State; + } + else + { + m_iFullMessageLength = 0; + m_iPosition = 0; + enumRecvState = RecvState.WaitingBeginChar1_State; + } + break; + case RecvState.WaitingForStus_State: //开始接受状态码 + if (buffer[i] == 0x00) + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + enumRecvState = RecvState.WaitingForTagCount_State; + } + else if (buffer[i] == 0x40) + { + m_szFullMessage[m_iPosition] = buffer[i]; + //LogService.Instance.Debug("RFU620等待接受WaitingForEndChar_State:Noread"); + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + m_iPosition = 0; + i = iLen; + enumRecvState = RecvState.WaitingBeginChar1_State; + //LogService.Instance.Debug("RFly-I160状态机结束。"); + } + break; + case RecvState.WaitingForTagCount_State: //开始接受标签组数 + Array.Copy(buffer, i, m_szFullMessage, m_iPosition, iBarcodeLength);//m_iPosition = 5 + byte[] tempData = new byte[iBarcodeLength]; + Array.Clear(tempData, 0, iBarcodeLength); + Array.Copy(buffer, i, tempData, 0, iBarcodeLength); + m_iPosition = m_iPosition + iBarcodeLength; //m_iPosition = 39 + i = i + iBarcodeLength - 1; //i = 39 + enumRecvState = RecvState.WaitingForXor_State; + break; + case RecvState.WaitingForXor_State: //开始比对校验位 Rfly160 + byte[] m_CRCVerify = new byte[1024]; //此数组用于校验位计算 + Array.Clear(m_CRCVerify, 0, m_CRCVerify.Length); + Array.Copy(m_szFullMessage, 2, m_CRCVerify, 0, iBarcodeLength + 3); //校验位计算是从Length - EPC 结束 + m_szFullMessage[m_iPosition] = buffer[i]; + m_iVerify = m_szFullMessage[m_iPosition]; + if (m_iVerify == _stringChange.CalculateVerify(m_CRCVerify, m_CRCVerify.Length)) + { + m_iPosition++; + enumRecvState = RecvState.WaitingForEndChar_State; + } + else //如果校验不成功 + { + m_iFullMessageLength = 0; + m_iPosition = 0; + enumRecvState = RecvState.WaitingBeginChar1_State; + } + break; + case RecvState.WaitingForEndChar_State: + if (buffer[0] == 0xBB && buffer[1] == 0xDD && buffer[2] == 0x00 && buffer[3] != 0x90) //此处为Noread数据显示 + { + m_szFullMessage[0] = 0xBB; + m_szFullMessage[1] = 0xDD; + m_szFullMessage[2] = 0x00; + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + m_iPosition = 0; + i = iLen; + enumRecvState = RecvState.WaitingBeginChar1_State; + } + else if (buffer[0] == 0xBB && buffer[1] == 0xDD && buffer[2] == 0x04 && buffer[3] == 0xBF) + { + Array.Copy(buffer, 0, m_szFullMessage, 0, 11); + i = 11; + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + i = iLen; + } + else if (buffer[i] == 0x00) //获取温度 + { + Array.Copy(buffer, 0, m_szFullMessage, 0, 8); + i = 8; + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + i = iLen; + } + else if (buffer[i] == 0x11) + { + Array.Copy(buffer, 0, m_szFullMessage, 0, 7); + i = 7; + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + } + else if (buffer[i] == 0x01) + { + Array.Copy(buffer, 0, m_szFullMessage, 0, 8); + i = 8; + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + } + else + { + m_szFullMessage[m_iPosition] = buffer[i]; + m_iPosition++; + if (buffer[i] == 0x0D) + { + lock (m_FrecvData) + { + m_FrecvData.Add(m_szFullMessage); + } + } + } + m_iPosition = 0; + enumRecvState = RecvState.WaitingBeginChar1_State; + break; + } + } + + return m_szFullMessage; + } + catch (Exception e) + { + throw new InvalidOperationException($"状态机逻辑处理异常:{e.Message}"); + } + } + + private Mutex mutauto = new Mutex(); + /// + /// 解析函数 + /// + /// + /// + /// + public List Device_DealTagInfoList(byte[] AutoDealReportData) + { + List tagInfoList = new List(); + byte[] bResultEPC_Data = new byte[14]; + byte[] m_AutoReadEPC = null; + int m_readEPCDataLen = 0; + try + { + mutauto.WaitOne(); + int iFirstCountPos = 6; //第一次读取标签次数位置 + int iFirstRSSIPos = 7; //第一次读取标签强度位置 + int iFirstAnt = 8; + int iFirstPC = 9; //第一次读取标签天线位置 + int iFirstLeftBarcketPos = 11;//EPC数据起始位置 + UInt16 tempDataCount = 0; + int tempDataRSSI = 0; + UInt16 tempDataANT = 0; + int iBarcodeGroupCount = Convert.ToInt32(AutoDealReportData[5].ToString()); //标签组数 + int iBarcodeLength = 16; //标签长度 + int iCommonSecondFlag = 0; + for (int j = 0; j < iBarcodeGroupCount; j++) + { + TagInfo tag = new TagInfo(); + byte[] tempPCByte = new byte[2]; //取出PC + Array.Clear(tempPCByte, 0, 2); + Array.Copy(AutoDealReportData, iFirstPC, tempPCByte, 0, 2); + + int pc = Convert.ToInt32(tempPCByte[0].ToString("X")); + int epcLength = EPCLengthByPC(pc); + iBarcodeLength = epcLength; + + byte[] tempDataByte = new byte[epcLength]; + Array.Clear(tempDataByte, 0, iBarcodeLength); + Array.Copy(AutoDealReportData, iFirstLeftBarcketPos, tempDataByte, 0, iBarcodeLength); + + byte[] tempCountByte = new byte[1]; //取出标签次数 + Array.Clear(tempCountByte, 0, 1); + Array.Copy(AutoDealReportData, iFirstCountPos, tempCountByte, 0, 1); + tempDataCount = tempCountByte[0]; + + byte[] tempRSSIByte = new byte[1]; //取出标签强度 + Array.Clear(tempRSSIByte, 0, 1); + Array.Copy(AutoDealReportData, iFirstRSSIPos, tempRSSIByte, 0, 1); + + tempDataRSSI = _stringChange.HexStringToNegative(_stringChange.bytesToHexStr(tempRSSIByte, 1)); + + #region add by wenjy 20220829 取出天线号 + byte[] tempAntByte = new byte[1]; //取出天线号 + Array.Clear(tempAntByte, 0, 1); + Array.Copy(AutoDealReportData, iFirstAnt, tempAntByte, 0, 1); + tempDataANT = tempAntByte[0]; + #endregion + + tag.Count = tempDataCount; + tag.RSSI = tempDataRSSI; + tag.EPC = tempDataByte; + + if (pc == 24) + { + tag.EPCstring = _stringChange.bytesToHexStr(tempDataByte, tempDataByte.Length).Substring(0, 7); + } + else + { + tag.EPCstring = Encoding.ASCII.GetString(tempDataByte); + } + + tag.PC = tempPCByte; + tag.Antana = tempDataANT; + tagInfoList.Add(tag); + int iBarcodeListLen = tagInfoList.Count; //特别注意,必须这样,要不然会多一条数据 + + iFirstCountPos = iFirstCountPos + iBarcodeLength + 5; //次数 + iFirstRSSIPos = iFirstCountPos + 1; //强度 + iFirstAnt = iFirstRSSIPos + 1; //天线 + iFirstPC = iFirstAnt + 1; + iFirstLeftBarcketPos = iFirstLeftBarcketPos + iBarcodeLength + 5; + + _logger.Info("----函数调用:Device_DealTagInfoList 第[" + (iCommonSecondFlag + 1) + "]次数据解析为:" + tag.EPCstring + ",读取标签次数:[" + tempDataCount + "],标签信号强度:[" + tempDataRSSI + "],天线号:[" + tempDataANT + "]"); + iCommonSecondFlag++; + if (iCommonSecondFlag == iBarcodeGroupCount) + { + mutauto.ReleaseMutex(); + _logger.Info("《《《返回标签数据!"); + return tagInfoList; + } + } + return tagInfoList; + } + catch (Exception ex) + { + mutauto.ReleaseMutex(); + throw new InvalidOperationException($"Device_AutoDealContent 自动处理函数异常:{ex.Message}"); + } + } + + /// + /// 根据PC获取EPC长度 + /// + /// + /// + private int EPCLengthByPC(int pcValue) + { + int epcLength = 0; + if (pcValue >= 10 && pcValue < 20) + { + epcLength = 4; + } + else if (pcValue >= 20 && pcValue < 30) + { + epcLength = 8; + } + else if (pcValue >= 30 && pcValue < 40) + { + epcLength = 12; + } + else if (pcValue >= 40 && pcValue < 50) + { + epcLength = 16; + } + else if (pcValue >= 50 && pcValue < 60) + { + epcLength = 20; + } + else if (pcValue >= 60 && pcValue < 70) + { + epcLength = 24; + } + else if (pcValue >= 70 && pcValue < 80) + { + epcLength = 28; + } + else if (pcValue >= 80 && pcValue < 90) + { + epcLength = 30; + } + return epcLength; + } + + #endregion + } +} \ No newline at end of file diff --git a/SlnMesnac.Rfid/RfidAbsractFactory.cs b/SlnMesnac.Rfid/RfidAbsractFactory.cs new file mode 100644 index 0000000..2a2c1b7 --- /dev/null +++ b/SlnMesnac.Rfid/RfidAbsractFactory.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using SlnMesnac.Model.dto; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Rfid +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Rfid +{ + /// + /// RFID抽象工厂 + /// + public abstract class RfidAbsractFactory + { + + public string ConfigKey { get; set; } + + /// + /// 建立连接 + /// + /// + /// + /// + public abstract bool Connect(string ip, int port); + + /// + /// 按时间段盘点 + /// + /// + /// + public abstract List TimePeriodRead(int timeout = 5000); + } +} \ No newline at end of file diff --git a/SlnMesnac.Rfid/SlnMesnac.Rfid.csproj b/SlnMesnac.Rfid/SlnMesnac.Rfid.csproj new file mode 100644 index 0000000..ac2b62d --- /dev/null +++ b/SlnMesnac.Rfid/SlnMesnac.Rfid.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.1 + enable + + + + + + + + + diff --git a/SlnMesnac.Serilog/SerilogExtensions.cs b/SlnMesnac.Serilog/SerilogExtensions.cs new file mode 100644 index 0000000..87a5374 --- /dev/null +++ b/SlnMesnac.Serilog/SerilogExtensions.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using Serilog.Events; +using SlnMesnac.Config; +using System; +using System.IO; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.Serilog +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Serilog +{ + /// + /// Serilog + /// + public static class SerilogExtensions + { + public static void UseSerilogExtensions(this IServiceProvider service) + { + #region 通过配置文件读取日志存放位置 + var appConfig = service.GetService(); + var logPath = $"{appConfig.logPath}/Logs/"; + + #endregion + + //Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console() + // .WriteTo.File(Path.Combine(logPath, "Info.log"), LogEventLevel.Information) + // .WriteTo.File(Path.Combine(logPath, "Error.log"), LogEventLevel.Error) + // .WriteTo.File(Path.Combine(logPath, "Warn.log"), LogEventLevel.Warning) + // //.WriteTo.File(Path.Combine(logPath, "Debug.log"), LogEventLevel.Debug, fileSizeLimitBytes: 5 * 1024) + // .CreateLogger(); + + Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console() + .WriteTo.Logger(lc => lc + .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Info")) + .WriteTo.File(Path.Combine($"{logPath}/Info/", "Info.log"), rollingInterval: RollingInterval.Day)) + .WriteTo.Logger(lc => lc + .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Plc")) + .WriteTo.File(Path.Combine($"{logPath}/Plc/", "Plc.log"), rollingInterval: RollingInterval.Day)) + .WriteTo.Logger(lc => lc + .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Camera")) + .WriteTo.File(Path.Combine($"{logPath}/Camera/", "Camera.log"), rollingInterval: RollingInterval.Day)) + .WriteTo.Logger(lc => lc + .Filter.ByIncludingOnly(logEvent => logEvent.Properties.ContainsKey("Module") && logEvent.Properties["Module"].ToString().Contains("Error")) + .WriteTo.File(Path.Combine($"{logPath}/Error/", "Error.log"), rollingInterval: RollingInterval.Day)) + .CreateLogger(); + } + } +} diff --git a/SlnMesnac.Serilog/SerilogHelper.cs b/SlnMesnac.Serilog/SerilogHelper.cs new file mode 100644 index 0000000..fc542a8 --- /dev/null +++ b/SlnMesnac.Serilog/SerilogHelper.cs @@ -0,0 +1,108 @@ +using Serilog; +using System; +using System.Collections.Generic; +using System.Text; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:T14-GEN3-7895 +* 命名空间:SlnMesnac.Serilog +* 唯一标识:fae9d68d-1992-4a03-b299-19edd9fc786d +* +* 创建者:WenJY +* 电子邮箱: +* 创建时间:2024-12-26 8:46:21 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.Serilog +{ + /// + /// Serilog日志类 + /// + public class SerilogHelper + { + private readonly ILogger? Info_logger = Log.ForContext("Module", "Info"); + private readonly ILogger? Plc_logger = Log.ForContext("Module", "Plc"); + private readonly ILogger? Error_logger = Log.ForContext("Module", "Error"); + private readonly ILogger? Camera_logger = Log.ForContext("Module", "Camera"); + + /// + /// Info日志 + /// + /// + public void Info(string msg) + { + if (Info_logger != null) + { + this.Info_logger.Information(msg); + } + } + + /// + /// Plc日志 + /// + /// + public void Plc(string msg) + { + if (Plc_logger != null) + { + this.Plc_logger.Information(msg); + } + } + + /// + /// 相机日志 + /// + /// + public void Camera(string msg) + { + if (Camera_logger != null) + { + this.Camera_logger.Information(msg); + } + } + + /// + /// Error日志 + /// + /// + /// + public void Error(string msg, Exception ex = null) + { + if (!string.IsNullOrEmpty(msg) && ex == null) + { + this.Error_logger.Information("【附加信息】 : {0}
", new object[] { msg }); + } + else if (!string.IsNullOrEmpty(msg) && ex != null) + { + string errorMsg = BeautyErrorMsg(ex); + this.Error_logger.Information("【附加信息】 : {0}
{1}", new object[] { msg, errorMsg }); + } + else if (string.IsNullOrEmpty(msg) && ex != null) + { + string errorMsg = BeautyErrorMsg(ex); + this.Error_logger.Information(errorMsg); + } + } + + private string BeautyErrorMsg(Exception ex) + { + string errorMsg = string.Format("【异常类型】:{0}
【异常信息】:{1}
【堆栈调用】:{2}", new object[] { ex.GetType().Name, ex.Message, ex.StackTrace }); + errorMsg = errorMsg.Replace("\r\n", "
"); + errorMsg = errorMsg.Replace("位置", "位置"); + return errorMsg; + } + + } +} \ No newline at end of file diff --git a/SlnMesnac.Serilog/SlnMesnac.Serilog.csproj b/SlnMesnac.Serilog/SlnMesnac.Serilog.csproj new file mode 100644 index 0000000..2377389 --- /dev/null +++ b/SlnMesnac.Serilog/SlnMesnac.Serilog.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + + diff --git a/SlnMesnac.TouchSocket/ApiServer.cs b/SlnMesnac.TouchSocket/ApiServer.cs new file mode 100644 index 0000000..d704959 --- /dev/null +++ b/SlnMesnac.TouchSocket/ApiServer.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; +using TouchSocket.Rpc; +using TouchSocket.WebApi; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:T14-GEN3-7895 +* 命名空间:SlnMesnac.TouchSocket +* 唯一标识:649766cc-308e-4bf3-8d69-dea48ec40642 +* +* 创建者:WenJY +* 电子邮箱: +* 创建时间:2024-09-04 10:51:54 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.TouchSocket +{ + public class ApiServer: RpcServer + { + + public delegate void RefreshScanInfoInCenterStart(); + /// + /// 入库开始事件刷新 + /// + public event RefreshScanInfoInCenterStart RefreshScanInfoInCenterStartEvent; + + public delegate void RefreshScanInfoInCenterStop(); + /// + /// 入库结束事件刷新 + /// + public event RefreshScanInfoInCenterStop RefreshScanInfoInCenterStopEvent; + + public delegate void RefreshScanInfoOutCenterStart(); + /// + /// 出库开始事件刷新 + /// + public event RefreshScanInfoOutCenterStart RefreshScanInfoOutCenterStartEvent; + + public delegate void RefreshScanInfoOutCenterStop(); + /// + /// 出库结束事件刷新 + /// + public event RefreshScanInfoOutCenterStop RefreshScanInfoOutCenterStopEvent; + + /// + /// 入库开始 + /// + /// + /// + [EnableCors("cors")] + [WebApi(HttpMethodType.POST)] + public object getScanInfoInCenterStart(string messageHeader) + { + RefreshScanInfoInCenterStartEvent?.Invoke(); + return true; + } + + /// + /// 入库结束 + /// + /// + /// + [EnableCors("cors")] + [WebApi(HttpMethodType.POST)] + public object getScanInfoInCenterStop(string messageHeader) + { + RefreshScanInfoInCenterStopEvent?.Invoke(); + return true; + } + + /// + /// 出库开始 + /// + /// + /// + [WebApi(HttpMethodType.POST)] + public object getScanInfoOutCenterStart(string messageHeader) + { + RefreshScanInfoOutCenterStartEvent?.Invoke(); + return true; + } + + /// + /// 出库结束 + /// + /// + /// + [WebApi(HttpMethodType.POST)] + public object getScanInfoOutCenterStop(string messageHeader) + { + RefreshScanInfoOutCenterStopEvent?.Invoke(); + return true; + } + + } +} diff --git a/SlnMesnac.TouchSocket/SlnMesnac.TouchSocket.csproj b/SlnMesnac.TouchSocket/SlnMesnac.TouchSocket.csproj new file mode 100644 index 0000000..94f69ee --- /dev/null +++ b/SlnMesnac.TouchSocket/SlnMesnac.TouchSocket.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + + diff --git a/SlnMesnac.TouchSocket/TcpServer.cs b/SlnMesnac.TouchSocket/TcpServer.cs new file mode 100644 index 0000000..f62e138 --- /dev/null +++ b/SlnMesnac.TouchSocket/TcpServer.cs @@ -0,0 +1,115 @@ +using Microsoft.Extensions.Logging; +using SlnMesnac.Serilog; +using System; +using System.Collections.Generic; +using System.Text; +using TouchSocket.Core; +using TouchSocket.Sockets; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.TouchSocket +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.TouchSocket +{ + public class TcpServer + { + private SerilogHelper _logger; + private readonly TcpService _service; + /// + /// 接收客户端指令委托 + /// + public delegate void ReceivedClientBuffer(byte[] buffer); + public event ReceivedClientBuffer? ReceivedClientBufferEvent; + + public delegate void RefreshClientInfo(TcpService tcpService); + public event RefreshClientInfo? RefreshClientInfoEvent; + + public TcpServer(SerilogHelper logger, TcpService tcpService) + { + _logger = logger; + _service = tcpService; + } + + public void Init(int serverPort) + { + try + { + _service.Connecting = (client, e) => { + _logger.Info($"客户端{client.IP}正在接入服务"); + return EasyTask.CompletedTask; + }; + _service.Connected = (client, e) => { + _logger.Info($"客户端{client.IP}接入服务成功"); + RefreshClientInfoEvent?.Invoke(_service); + return EasyTask.CompletedTask; + }; + _service.Disconnected = (client, e) => { + _logger.Info($"客户端{client.IP}断开连接"); + RefreshClientInfoEvent?.Invoke(_service); + return EasyTask.CompletedTask; + }; + _service.Received = (client, e) => + { + //从客户端收到信息 + var mes = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 0, e.ByteBlock.Len);//注意:数据长度是byteBlock.Len + + byte[] receivedBuffer = new byte[e.ByteBlock.Len]; + Array.Copy(e.ByteBlock.Buffer, 0, receivedBuffer, 0, e.ByteBlock.Len); + ReceivedClientBufferEvent?.Invoke(receivedBuffer); + + return EasyTask.CompletedTask; + }; + + _service.Setup(new TouchSocketConfig()//载入配置 + .SetListenIPHosts(new IPHost[] { new IPHost($"0.0.0.0:{serverPort}") }) + .ConfigureContainer(a =>//容器的配置顺序应该在最前面 + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + //自定义插件 + })); + _service.Start(); + _logger.Info($"TcpServer启动成功,监听端口:{serverPort}"); + } + catch (Exception ex) + { + //throw new InvalidOperationException($"TcpServer启动异常:{ex.Message}"); + _logger.Error($"TcpServer启动异常:{ex.Message}"); + } + + } + + /// + /// 向所有客户端发送心跳 + /// + public void SendHeartBeat() + { + var clients = _service.SocketClients.GetClients(); + foreach (var item in clients) + { + _service.Send(item.Id,"heartbeat"); + } + } + } +} diff --git a/SlnMesnac.TouchSocket/TouchSocketSetup.cs b/SlnMesnac.TouchSocket/TouchSocketSetup.cs new file mode 100644 index 0000000..637d77f --- /dev/null +++ b/SlnMesnac.TouchSocket/TouchSocketSetup.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.AspNetCore.Builder; +using TouchSocket.Sockets; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.TouchSocket +* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-03-27 21:58:35 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.TouchSocket +{ + /// + /// 注册服务 + /// + public static class TouchSocketSetup + { + + public static IApplicationBuilder UseTouchSocketExtensions(this IApplicationBuilder app) + { + var _server = app.ApplicationServices.GetService(); + _server.Init(20108); + + var _apiServer = app.ApplicationServices.GetService(); + _apiServer.Init(); + return app; + } + } +} \ No newline at end of file diff --git a/SlnMesnac.TouchSocket/WebApiServer.cs b/SlnMesnac.TouchSocket/WebApiServer.cs new file mode 100644 index 0000000..7c85740 --- /dev/null +++ b/SlnMesnac.TouchSocket/WebApiServer.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc; +using TouchSocket.Sockets; +using TouchSocket.WebApi.Swagger; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:T14-GEN3-7895 +* 命名空间:SlnMesnac.TouchSocket +* 唯一标识:4e47989b-9d43-426e-b67a-529de3b1b0e8 +* +* 创建者:WenJY +* 电子邮箱: +* 创建时间:2024-09-04 10:51:29 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.TouchSocket +{ + public class WebApiServer + { + private ApiServer _apiServer; + + public WebApiServer(ApiServer apiServer) + { + _apiServer = apiServer; + } + + public void Init() + { + try + { + var service = new HttpService(); + service.Setup(new TouchSocketConfig() + .SetListenIPHosts(7789) + .ConfigureContainer(a => + { + a.AddRpcStore(store => + { + + store.RegisterServer(_apiServer);//注册服务 + }); + + a.AddCors(corsOption => + { + corsOption.Add("cors", corsBuilder => + { + corsBuilder.AllowAnyMethod() + .AllowAnyOrigin(); + }); + }); + + a.AddLogger(logger => + { + logger.AddConsoleLogger(); + logger.AddFileLogger(); + }); + }) + .ConfigurePlugins(a => + { + a.UseCheckClear(); + + a.Add(); + + a.UseWebApi() + .ConfigureConverter(converter => + { + converter.AddJsonSerializerFormatter(new Newtonsoft.Json.JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.None }); + }); + + a.UseSwagger();//使用Swagger页面 + //.UseLaunchBrowser(); + + a.UseDefaultHttpServicePlugin(); + })); + service.Start(); + + Console.WriteLine("以下连接用于测试webApi"); + Console.WriteLine($"使用:http://127.0.0.1:7789/swagger/index.html"); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + } + + //Console.ReadLine(); + } + } + + internal class AuthenticationPlugin : PluginBase, IHttpPlugin + { + public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e) + { + await e.InvokeNext(); + } + } +} diff --git a/SlnMesnac.WPF/App.xaml b/SlnMesnac.WPF/App.xaml new file mode 100644 index 0000000..05764b6 --- /dev/null +++ b/SlnMesnac.WPF/App.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SlnMesnac.WPF/App.xaml.cs b/SlnMesnac.WPF/App.xaml.cs new file mode 100644 index 0000000..72661c5 --- /dev/null +++ b/SlnMesnac.WPF/App.xaml.cs @@ -0,0 +1,155 @@ +using Lierda.WPFHelper; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using SlnMesnac.Config; +using System; +using System.Windows; +using Microsoft.Extensions.Configuration; +using SlnMesnac.Extensions; +using SlnMesnac.Serilog; +using System.Reflection; +using TouchSocket.Sockets; +using SlnMesnac.WPF.Attribute; +using SlnMesnac.WPF.Page.Login; + +namespace SlnMesnac.WPF +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + private System.Threading.Mutex? mutex = null; + private LierdaCracker cracker = new LierdaCracker(); + public static IServiceProvider? ServiceProvider = null; + + public new static App Current => (App)Application.Current; + + // Startup事件 + protected override async void OnStartup(StartupEventArgs e) + { + + this.DispatcherUnhandledException += App_DispatcherUnhandledException; //全局异常处理 + + #region 进程判断,避免重复开启 + bool ret; + mutex = new System.Threading.Mutex(true, System.Diagnostics.Process.GetCurrentProcess().ProcessName, out ret); + if (!ret) + { + MessageBox.Show("应用程序已开启,禁止重复运行"); + Environment.Exit(0); + } + #endregion + + cracker.Cracker(100); //设置GC回收间隔 + + base.OnStartup(e); + + // 设置ServiceCollection + var services = new ServiceCollection(); + ConfigureServices(services); // 配置服务 + + // 创建ServiceProvider + ServiceProvider = services.BuildServiceProvider(); + + // 配置Serilog和其他扩展 + ServiceProvider.UseSerilogExtensions(); + + var appConfig = ServiceProvider.GetService(); + Log.Information($"系统初始化完成,日志存放路径:{appConfig?.logPath}"); + + var loginWindow = ServiceProvider.GetRequiredService(); + loginWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; + loginWindow.Show(); + + } + + + /// + /// ConfigureServices + /// + /// + private void ConfigureServices(IServiceCollection services) + { + // 注册AppConfig + services.AddSingleton(provider => + { + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + IConfiguration configuration = configurationBuilder.Build(); + var ap = configuration.GetSection("AppConfig").Get(); + return ap; + }); + + services.AddSingleton(typeof(SerilogHelper)); + + Assembly[] assemblies = { + Assembly.LoadFrom("SlnMesnac.Repository.dll"), + Assembly.LoadFrom("SlnMesnac.Plc.dll"), + Assembly.LoadFrom("SlnMesnac.Rfid.dll"), + Assembly.LoadFrom("SlnMesnac.Common.dll"), + Assembly.LoadFrom("SlnMesnac.TouchSocket.dll"), + Assembly.LoadFrom("SlnMesnac.Business.dll"), + Assembly.LoadFrom("SlnMesnac.Generate.dll") + }; + + services.Scan(scan => scan.FromAssemblies(assemblies) + .AddClasses() + .AsImplementedInterfaces() + .AsSelf() + .WithTransientLifetime()); + services.AddSingleton(typeof(TcpService)); + services.AddLogging(x => x.AddSerilog()); + + services.Scan(scan => scan + .FromAssemblyOf() + .AddClasses(classes => classes.WithAttribute()).AsSelf().WithSingletonLifetime()); + services.Scan(scan => scan + .FromAssemblyOf() + .AddClasses(classes => classes.WithAttribute()).AsSelf().WithTransientLifetime()); + + + // 注册ORM + services.AddSqlSugarSetup(); + + // 注册PLC工厂 + //services.AddPlcFactorySetup(); + + //services.AddJob(); + + // 注册 EventBus 服务 + //services.AddEventBus(builder => + //{ + // // 注册 ToDo 事件订阅者 + // builder.AddSubscriber(); + //}); + + + + + } + + // Exit事件 + protected override void OnExit(ExitEventArgs e) + { + base.OnExit(e); + + Log.Information($"系统退出,当前时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); + // 释放资源 + // ... + } + + private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + { + // 处理异常 + var info = e.Exception; + MessageBox.Show(e.Exception.Message); + Log.Error($"全局异常:{e.Exception.Message}", e.Exception); + + // 防止默认的崩溃行为 + e.Handled = true; + } + + } +} diff --git a/SlnMesnac.WPF/AssemblyInfo.cs b/SlnMesnac.WPF/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/SlnMesnac.WPF/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/SlnMesnac.WPF/Attribute/RegisterAsSingletonAttribute.cs b/SlnMesnac.WPF/Attribute/RegisterAsSingletonAttribute.cs new file mode 100644 index 0000000..86eadf3 --- /dev/null +++ b/SlnMesnac.WPF/Attribute/RegisterAsSingletonAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SlnMesnac.WPF.Attribute +{ + public class RegisterAsSingletonAttribute:System.Attribute + { + } +} diff --git a/SlnMesnac.WPF/Attribute/RegisterAsTransientAttribute.cs b/SlnMesnac.WPF/Attribute/RegisterAsTransientAttribute.cs new file mode 100644 index 0000000..037555d --- /dev/null +++ b/SlnMesnac.WPF/Attribute/RegisterAsTransientAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SlnMesnac.WPF.Attribute +{ + public class RegisterAsTransientAttribute:System.Attribute + { + } +} diff --git a/SlnMesnac.WPF/Attribute/RequirePermissionAttribute.cs b/SlnMesnac.WPF/Attribute/RequirePermissionAttribute.cs new file mode 100644 index 0000000..aaefe90 --- /dev/null +++ b/SlnMesnac.WPF/Attribute/RequirePermissionAttribute.cs @@ -0,0 +1,109 @@ +using Microsoft.Extensions.DependencyInjection; +using Rougamo; +using Rougamo.Context; +using SlnMesnac.WPF.Page.Loading; +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.Threading; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:T14-GEN3-7895 +* 命名空间:SlnMesnac.WPF.Attribute +* 唯一标识:fff40cb6-18aa-47e0-917c-1fa653e6f978 +* +* 创建者:WenJY +* 电子邮箱: +* 创建时间:2024-12-30 10:19:41 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.WPF.Attribute +{ + /// + /// 权限过滤 + /// + public class RequirePermissionAttribute : MoAttribute + { + private LoadingWindow loadingWindow; + private string _permissionName; + + public RequirePermissionAttribute(string permissionName) + { + _permissionName = permissionName; + + + } + public override void OnEntry(MethodContext context) + { + Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint)); + newWindowThread.SetApartmentState(ApartmentState.STA); // 设置为 STA 模式 + newWindowThread.IsBackground = true; // 设置为后台线程 + newWindowThread.Start(); + + bool hasPermission = CheckPermission(_permissionName); + + if (!hasPermission) + { + // 如果用户没有权限,抛出异常或采取其他措施 + throw new UnauthorizedAccessException("User does not have the required permission."); + } + + base.OnEntry(context); + } + + + public override void OnExit(MethodContext context) + { + Thread.Sleep(200); + if(loadingWindow != null) + { + loadingWindow.Dispatcher.Invoke(new Action(() => + { + loadingWindow.Close(); // 关闭窗口 + })); + } + + + base.OnExit(context); + } + + /// + /// 判断权限 + /// + /// + /// + private bool CheckPermission(string permissionName) + { + return true; + } + + private void ThreadStartingPoint() + { + Dispatcher.CurrentDispatcher.Invoke(new Action(() => + { + loadingWindow = App.ServiceProvider.GetService(); + loadingWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; + loadingWindow.Topmost = true; + loadingWindow.Show(); + })); + + Dispatcher.Run(); + } + } +} diff --git a/SlnMesnac.WPF/Converter/Generate/RowToIndexConverter.cs b/SlnMesnac.WPF/Converter/Generate/RowToIndexConverter.cs new file mode 100644 index 0000000..bfed787 --- /dev/null +++ b/SlnMesnac.WPF/Converter/Generate/RowToIndexConverter.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Data; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:LAPTOP-E0N2L34V +* 命名空间:SlnMesnac.WPF.Converter.Generate +* 唯一标识:38e34c93-1c10-4a1c-83b0-c545affdc224 +* +* 创建者:WenJY +* 电子邮箱:wenjy@mesnac.com +* 创建时间:2024-04-11 10:27:10 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace SlnMesnac.WPF.Converter.Generate +{ + internal class RowToIndexConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + var item = values[0]; + var dataGrid = values[1] as DataGrid; + + if (item == null || dataGrid == null) + return null; + + var index = dataGrid.Items.IndexOf(item) + 1; + return index; + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/SlnMesnac.WPF/FodyWeavers.xml b/SlnMesnac.WPF/FodyWeavers.xml new file mode 100644 index 0000000..a6a2edf --- /dev/null +++ b/SlnMesnac.WPF/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/SlnMesnac.WPF/MainWindow.xaml b/SlnMesnac.WPF/MainWindow.xaml new file mode 100644 index 0000000..95bca2c --- /dev/null +++ b/SlnMesnac.WPF/MainWindow.xaml @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +