diff --git a/DOAN.Admin.WebApi/Controllers/PBL/StoragelocationController.cs b/DOAN.Admin.WebApi/Controllers/PBL/StoragelocationController.cs index 751abac..4aa7ae7 100644 --- a/DOAN.Admin.WebApi/Controllers/PBL/StoragelocationController.cs +++ b/DOAN.Admin.WebApi/Controllers/PBL/StoragelocationController.cs @@ -79,6 +79,8 @@ namespace DOAN.Admin.WebApi.Controllers.PBL public IActionResult UpdateStoragelocation([FromBody] StoragelocationDto parm) { var modal = parm.Adapt().ToUpdate(HttpContext); + + var response = _StoragelocationService.UpdateStoragelocation(modal); return ToResponse(response); diff --git a/DOAN.Admin.WebApi/Program.cs b/DOAN.Admin.WebApi/Program.cs index 6b29807..e0e6f92 100644 --- a/DOAN.Admin.WebApi/Program.cs +++ b/DOAN.Admin.WebApi/Program.cs @@ -165,7 +165,12 @@ app.UseSwagger(); app.UseIpRateLimiting(); app.UseRateLimiter(); //设置socket连接 -app.MapHub("/msgHub"); +//app.MapHub("/msgHub"); +app.UseEndpoints(endpoints => +{ + endpoints.MapHub("/msgHub"); // ChatHub 是你自定义的 Hub 类名 + endpoints.MapHub("/msgHub"); +}); app.MapControllerRoute( name: "default", diff --git a/DOAN.Admin.WebApi/appsettings.Development.json b/DOAN.Admin.WebApi/appsettings.Development.json index 3906e43..f32e150 100644 --- a/DOAN.Admin.WebApi/appsettings.Development.json +++ b/DOAN.Admin.WebApi/appsettings.Development.json @@ -11,7 +11,7 @@ { - "Conn": "Data Source=192.168.0.58;User ID=root;Password=123456;Initial Catalog=pbl_huaxiang;Port=3306", + "Conn": "Data Source=10.72.80.161;User ID=root;Password=doantech123;Initial Catalog=pbl_huaxiang_v2;Port=3306", "DbType": 0, //数据库类型 MySql = 0, SqlServer = 1, Oracle = 3,PgSql = 4 "ConfigId": "0", //多租户唯一标识 "IsAutoCloseConnection": true diff --git a/DOAN.Admin.WebApi/appsettings.Production.json b/DOAN.Admin.WebApi/appsettings.Production.json index 8334284..c7975d5 100644 --- a/DOAN.Admin.WebApi/appsettings.Production.json +++ b/DOAN.Admin.WebApi/appsettings.Production.json @@ -11,7 +11,7 @@ { - "Conn": "Data Source=10.72.80.161;User ID=root;Password=doantech123;Initial Catalog=pbl_huaxiang;Port=3306", + "Conn": "Data Source=10.72.80.161;User ID=root;Password=doantech123;Initial Catalog=pbl_huaxiang_v2;Port=3306", "DbType": 0, //数据库类型 MySql = 0, SqlServer = 1, Oracle = 3,PgSql = 4 "ConfigId": "0", //多租户唯一标识 "IsAutoCloseConnection": true diff --git a/DOAN.Model/PBL/PlcAddress.cs b/DOAN.Model/PBL/PlcAddress.cs new file mode 100644 index 0000000..3ac182e --- /dev/null +++ b/DOAN.Model/PBL/PlcAddress.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DOAN.Model.PBL +{ + /// + /// PLC地址 + /// + [SugarTable("plc_address_table")] + public class PlcAddressTable + { + + /// + /// + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = false)] + public int Id { get; set; } + + + /// + /// 料架层fk_id + /// + [SugarColumn(ColumnName = "fk_storage_id")] + public int FkStorageId { get; set; } + + + + /// + /// 料架号 + /// + [SugarColumn(ColumnName = "rock_code")] + public string RockCode { get; set; } + + + /// + /// 层号 + /// + [SugarColumn(ColumnName = "layer")] + public int Layer { get; set; } + + + /// + /// 方向 左/右 + /// + [SugarColumn(ColumnName = "direction")] + public string Direction { get; set; } + + + /// + /// 序号(123)其中合并料架为(123456) + /// + [SugarColumn(ColumnName = "index")] + public int Index { get; set; } + + + /// + /// plc地址 + /// + [SugarColumn(ColumnName = "plc_address")] + public string PlcAddress { get; set; } + + + /// + /// plc地址 (第几字节) + /// + [SugarColumn(ColumnName = "byte_num")] + public int ByteNum { get; set; } + + + + /// + /// plc地址 (第几位) + /// + [SugarColumn(ColumnName = "bit_num")] + public int BitNum { get; set; } + + + /// + /// 备注 + /// + [SugarColumn(ColumnName = "remark")] + public string Remark { get; set; } + + + + + + + } +} diff --git a/DOAN.Model/PBL/Storagelocation.cs b/DOAN.Model/PBL/Storagelocation.cs index 6127283..19fc64e 100644 --- a/DOAN.Model/PBL/Storagelocation.cs +++ b/DOAN.Model/PBL/Storagelocation.cs @@ -52,14 +52,14 @@ namespace DOAN.Model.PBL /// ///PLC地址(亮灯拣货) /// - [SugarColumn(ColumnName = "plc_address")] + [SugarColumn(ColumnName = "plc_light_address")] public string PlcAddress { get; set; } - /// - /// PLC地址(空箱补料) - /// - [SugarColumn(ColumnName = "plc_address_2")] - public string PlcAddress2 { get; set; } + ///// + ///// PLC地址(空箱补料) + ///// + //[SugarColumn(ColumnName = "plc_address_2")] + //public string PlcAddress2 { get; set; } /// /// 创建人 @@ -84,5 +84,8 @@ namespace DOAN.Model.PBL /// [SugarColumn(ColumnName = "uPDATED_TIME")] public DateTime? UpdatedTime { get; set; } + + [SugarColumn(ColumnName = "remark")] + public string Remark { get; set; } } } \ No newline at end of file diff --git a/DOAN.Service/PBL/MESInteractionServcie.cs b/DOAN.Service/PBL/MESInteractionServcie.cs index 0bc5015..36771de 100644 --- a/DOAN.Service/PBL/MESInteractionServcie.cs +++ b/DOAN.Service/PBL/MESInteractionServcie.cs @@ -2,8 +2,10 @@ using DOAN.Model.PBL; using DOAN.Model.PBL.Dto; using DOAN.Service.PBL.IService; +using DOAN.ServiceCore.Signalr; using Infrastructure.Attribute; using Mapster; +using Microsoft.AspNetCore.SignalR; using Newtonsoft.Json.Linq; @@ -15,6 +17,11 @@ namespace DOAN.Service.PBL [AppService(ServiceType = typeof(IMESInteractionServcie), ServiceLifetime = LifeTime.Transient)] public class MESInteractionServcie : BaseService, IMESInteractionServcie { + private readonly IHubContext notificationHubContext; + public MESInteractionServcie(IHubContext _notificationHubContext) { + + notificationHubContext= _notificationHubContext; + } public bool TestPLc(string address, PLCTool pLCTool) { bool isSucesss = pLCTool.ReadBit(address); @@ -40,14 +47,14 @@ namespace DOAN.Service.PBL // 2.根据总成零件号 ,版本 查询对应零件号,使得对应料架亮灯 // 同一个会有多个料架 - //镜壳 料架 + //镜壳 料架层 List MirrorshellShelfList = Context.Queryable().Where(it => it.Partnumber == - SqlFunc.Subqueryable().Where(It => It.Productcode == light.AssemblyPartNumber && It.Version == light.Version).Select(it => it.MirrorshellCode)).ToList(); + SqlFunc.Subqueryable().Where(It => It.Productcode == light.AssemblyPartNumber).Select(it => it.MirrorshellCode)).ToList(); //镜体 料架 // Storagelocation MirrorshellBody = Context.Queryable().Where(it => it.Partnumber == // SqlFunc.Subqueryable().Where(It => It.Productcode == light.AssemblyPartNumber && It.Version == light.Version).Select(it => it.MirrorbodyCode)).First(); - if (MirrorshellShelfList != null || MirrorshellShelfList.Count() > 0) + if (MirrorshellShelfList != null && MirrorshellShelfList.Count() > 0) { foreach (var item1 in MirrorshellShelfList) @@ -97,6 +104,11 @@ namespace DOAN.Service.PBL } else { + // 发送socket 通知 + + string message=$"MES产品编号{light.AssemblyPartNumber}或者版本{light.Version},在PBL中找不到。请维护PBL料架信息"; + notificationHubContext.Clients.All.SendAsync("PBL_bom_except", light); + return false; } @@ -121,7 +133,7 @@ namespace DOAN.Service.PBL Context.Insertable(item).ExecuteCommand(); //2 找到对应的库存最大料架 灭灯 - Storagelocation storagelocation = Context.Queryable().Where(it => it.Partnumber == scan_code).OrderByDescending(it => it.PackageNum).First(); + Storagelocation storagelocation = Context.Queryable().Where(it => it.Partnumber.Contains(scan_code)).OrderByDescending(it => it.PackageNum).First(); if (storagelocation != null) { @@ -132,14 +144,13 @@ namespace DOAN.Service.PBL { storagelocation.IsLight = 0; // storagelocation.PackageNum -= 1; - if (storagelocation.PackageNum < 0) - { - storagelocation.PackageNum = 0; - } - + //if (storagelocation.PackageNum < 0) + //{ + // storagelocation.PackageNum = 0; + //} //3 扣减对应的库存 // 合并货架的id - int[] ids = { 1, 2, 3, 4, 19, 20, 21, 22 }; + int[] ids = { 1, 2, 3, 4, 5, 6, 7, 8 }; if (ids.Contains(storagelocation.Id)) { Context.Updateable().SetColumns(it=>it.IsLight == 0).Where(it=>it.Partnumber == storagelocation.Partnumber).ExecuteCommand(); diff --git a/DOAN.ServiceCore/DoanBackgroundService.cs b/DOAN.ServiceCore/DoanBackgroundService.cs index f5f7e40..a7dd166 100644 --- a/DOAN.ServiceCore/DoanBackgroundService.cs +++ b/DOAN.ServiceCore/DoanBackgroundService.cs @@ -11,6 +11,10 @@ using SqlSugar.IOC; namespace DOAN.ServiceCore { + /// + /// 永驻线程 + /// 功能:检测传感器信号,判断箱子数 + /// public class DoanBackgroundService : IHostedService, IDisposable { private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); @@ -39,91 +43,219 @@ namespace DOAN.ServiceCore await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); } + private static bool GetInvertedBit(byte b, int position) + { + if (position < 0 || position > 7) + { + throw new ArgumentOutOfRangeException(nameof(position), "Position must be between 0 and 7."); + } + + // 创建一个掩码,其中只有要检查的那一位是1 + byte mask = (byte)(1 << position); + + // 使用按位与运算符(&)来检查该位是否为1 + bool isSet = (b & mask) != 0; + + // 返回取反后的值 + return !isSet; + } + + /// + /// 功能:检测传感器信号,判断箱子数 + /// + /// + /// private async Task ExecuteAsync(CancellationToken stoppingToken) { try { - int index = 1; - int indexMax = await DbScoped.SugarScope.CopyNew() - .Queryable().CountAsync(); - + //int index = 1; + //int indexMax = await DbScoped.SugarScope.CopyNew() + // .Queryable().CountAsync(); while (!stoppingToken.IsCancellationRequested) { - List storagelocationList = await DbScoped.SugarScope.CopyNew() - .Queryable().Where(it => it.Id == index).ToListAsync(); - if (storagelocationList.Count > 0) - { - foreach (var storagelocation in storagelocationList) + //读取PLC I/O状态 12个数组 + Byte[] getPLCValueByteArray=pLCTool.ReadAllValue("VB100",12); + //判断 每个料架每层的箱子数 + + //1. 获取所有料架层 合并的箱子 料架层翻倍 + List storagelocationList = await DbScoped.SugarScope.CopyNew().Queryable().ToListAsync(); + + + //2. 获取点位表 + List pointPositionList = await DbScoped.SugarScope.CopyNew().Queryable().ToListAsync(); + + List updateStoragelocationList=new List(); + List inventorylogs = new List(); + + if (storagelocationList.Count() > 0) { + + foreach (Storagelocation layerItem in storagelocationList) { + //2 获取这个料架层的点位表 + List thisLayItemPointPositionList= pointPositionList.Where(it => it.FkStorageId == layerItem.Id).ToList(); - //遮挡不亮 false - bool result = pLCTool.ReadBit(storagelocation.PlcAddress2); - // 写补料日志 - Inventorylog inventorylog = new Inventorylog(); - inventorylog.Id = SnowFlakeSingle.Instance.NextId().ToString(); - inventorylog.RackCode = storagelocation.RackCode; - // 合并货架的id - int[] ids = {1,2,3,4,19,20,21,22 }; - int PackageLine = 2; - //if (ids.Contains(storagelocation.Id)) - //{ - // PackageLine = 1; - //} - if (result) + //3 判断这个料架层箱子的个数 + if(thisLayItemPointPositionList!=null&& thisLayItemPointPositionList.Count()>0) { - //缺料,需要补料 - // 从满料到缺料 仓库库存修正 - if (storagelocation.PackageNum > PackageLine) + // 这一层箱子数 默认最小值为1 + int packNum = 1; + foreach(PlcAddressTable i in thisLayItemPointPositionList) { - storagelocation.PackageNum = PackageLine; - // 减少日志输出 -/* inventorylog.Operation = 1; - inventorylog.PackageNum = 1; - inventorylog.CreatedBy = "PLC-缺料"; - inventorylog.CreatedTime = DateTime.Now.ToLocalTime();*/ - await DbScoped.SugarScope.CopyNew().Updateable(storagelocation).ExecuteCommandAsync(); - //await DbScoped.SugarScope.CopyNew().Insertable(inventorylog).ExecuteCommandAsync(); + int row = i.ByteNum-100; + int col = i.BitNum - 1; + // Console.WriteLine($"row={row},col={col},PLCValueByteArray[row]={getPLCValueByteArray.Length}"); + packNum= packNum+( GetInvertedBit(getPLCValueByteArray[row], col) ? 1 : 0); + //Console.WriteLine($"row:{row}-col:{col} packNum:{packNum} "); } - } - else - { - // 从缺料到补料 仓库库存修正 - if (storagelocation.PackageNum <= PackageLine) + // 记录日志 + if(packNum> layerItem.PackageNum) { - //不需要补料 补料成功 - storagelocation.PackageNum = storagelocation.MaxCapacity; + Storagelocation storagelocation = layerItem; + + storagelocation.PackageNum = packNum; + storagelocation.UpdatedBy = "补料"; + storagelocation.UpdatedTime = DateTime.Now; + updateStoragelocationList.Add(storagelocation); + + + + Inventorylog inventorylog = new Inventorylog(); + //入库 + inventorylog.Id= SnowFlakeSingle.Instance.NextId().ToString(); inventorylog.Operation = 2; - inventorylog.PackageNum = storagelocation.MaxCapacity; - inventorylog.CreatedBy = "PLC-补料成功"; + inventorylog.PackageNum = packNum- layerItem.PackageNum; + inventorylog.CreatedBy = "补料"; inventorylog.CreatedTime = DateTime.Now.ToLocalTime(); - await DbScoped.SugarScope.CopyNew().Updateable(storagelocation).ExecuteCommandAsync(); - await DbScoped.SugarScope.CopyNew().Insertable(inventorylog).ExecuteCommandAsync(); + inventorylogs.Add(inventorylog); + } + else if(packNum < layerItem.PackageNum) + { + Storagelocation storagelocation = layerItem; + storagelocation.PackageNum = packNum; + storagelocation.UpdatedBy = "出料"; + storagelocation.UpdatedTime = DateTime.Now; + updateStoragelocationList.Add(storagelocation); + + //出库 + Inventorylog inventorylog = new Inventorylog(); + inventorylog.Id = SnowFlakeSingle.Instance.NextId().ToString(); + inventorylog.Operation = 1; + inventorylog.PackageNum =layerItem.PackageNum - packNum ; + inventorylog.CreatedBy = "出料"; + inventorylog.CreatedTime = DateTime.Now.ToLocalTime(); + inventorylogs.Add(inventorylog); + } + } + } - + //修正库存 + if (updateStoragelocationList.Count() > 0) + { + await DbScoped.SugarScope.CopyNew().Updateable(updateStoragelocationList).ExecuteCommandAsync(); + } + + //增加库存变更日志 + if(inventorylogs.Count()>0) + { + await DbScoped.SugarScope.CopyNew().Insertable(inventorylogs).ExecuteCommandAsync(); } - // Console.WriteLine("永驻线程,正在读取plc值 " + result + "地址:" + address[i]); - } - // await Task.Delay(500, stoppingToken); - index++; - if (index > indexMax) - { - index = 1; - } + + + + + + + + //List storagelocationList = await DbScoped.SugarScope.CopyNew() + //.Queryable().Where(it => it.Id == index).ToListAsync(); + //if (storagelocationList.Count > 0) + //{ + + // foreach (var storagelocation in storagelocationList) + // { + + // //遮挡不亮 false + // bool result = pLCTool.ReadBit(storagelocation.PlcAddress2); + // // 写补料日志 + // Inventorylog inventorylog = new Inventorylog(); + // inventorylog.Id = SnowFlakeSingle.Instance.NextId().ToString(); + // inventorylog.RackCode = storagelocation.RackCode; + // // 合并货架的id + // //int[] ids = {1,2,3,4,19,20,21,22 }; + // int PackageLine = 2; + // //if (ids.Contains(storagelocation.Id)) + // //{ + // // PackageLine = 1; + // //} + // if (result) + // { + // //缺料,需要补料 + // // 仓库库存修正 + // if (storagelocation.PackageNum > PackageLine) + // { + // storagelocation.PackageNum = PackageLine; + // /*inventorylog.Operation = 1; + // inventorylog.PackageNum = 1; + // inventorylog.CreatedBy = "PLC"; + // inventorylog.CreatedTime = DateTime.Now.ToLocalTime();*/ + // await DbScoped.SugarScope.CopyNew().Updateable(storagelocation).ExecuteCommandAsync(); + // //await DbScoped.SugarScope.CopyNew().Insertable(inventorylog).ExecuteCommandAsync(); + + + // } + // } + // else + // { + // // 仓库库存修正 + // if (storagelocation.PackageNum <= PackageLine) + // { + // //不需要补料 补料成功 + // storagelocation.PackageNum = storagelocation.MaxCapacity; + // inventorylog.Operation = 2; + // inventorylog.PackageNum = storagelocation.MaxCapacity; + // inventorylog.CreatedBy = "PLC"; + // inventorylog.CreatedTime = DateTime.Now.ToLocalTime(); + // await DbScoped.SugarScope.CopyNew().Updateable(storagelocation).ExecuteCommandAsync(); + // await DbScoped.SugarScope.CopyNew().Insertable(inventorylog).ExecuteCommandAsync(); + // } + + // } + // //Console.WriteLine("永驻线程,正在读取对射传感器plc值 " + result + "地址:" + storagelocation.PlcAddress2); + + // } + + + + + + //} + + + + //// await Task.Delay(500, stoppingToken); + + + //index++; + //if (index > indexMax) + //{ + // index = 1; + //} } } catch (Exception ex) { diff --git a/DOAN.ServiceCore/Filters/VerifyAttribute.cs b/DOAN.ServiceCore/Filters/VerifyAttribute.cs index 7958088..a0d7625 100644 --- a/DOAN.ServiceCore/Filters/VerifyAttribute.cs +++ b/DOAN.ServiceCore/Filters/VerifyAttribute.cs @@ -54,7 +54,7 @@ namespace DOAN.Admin.WebApi.Filters var nowTime = DateTime.UtcNow; TimeSpan ts = loginUser.ExpireTime - nowTime; - Console.WriteLine($"jwt到期剩余:{ts.TotalMinutes}分,{ts.TotalSeconds}秒"); + // Console.WriteLine($"jwt到期剩余:{ts.TotalMinutes}分,{ts.TotalSeconds}秒"); var CK = "token_" + loginUser.UserId; if (!CacheHelper.Exists(CK) && ts.TotalMinutes < 5) diff --git a/DOAN.ServiceCore/Signalr/PBLhub.cs b/DOAN.ServiceCore/Signalr/PBLhub.cs new file mode 100644 index 0000000..4027fc2 --- /dev/null +++ b/DOAN.ServiceCore/Signalr/PBLhub.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.SignalR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DOAN.ServiceCore.Signalr +{ + public class PBLhub : Hub + { + + + /// + /// 接受消息 + /// + /// + /// + public async Task SendNotification(string message) + { + // 向所有客户端发送通知 + await Clients.All.SendAsync("BOMExcept", message); + } + + public async Task PBL_bom_except(string message) + { + Console.WriteLine(message); + + } + + } +} diff --git a/Infrastructure/PLC/PLCTool.cs b/Infrastructure/PLC/PLCTool.cs index 510fb6d..6420e78 100644 --- a/Infrastructure/PLC/PLCTool.cs +++ b/Infrastructure/PLC/PLCTool.cs @@ -80,6 +80,71 @@ namespace DOAN.Infrastructure.PLC return M100_7; } + /// + /// 读多个连续的二进制数据 转为字节数组 + /// + /// + /// + /// + //public byte[,] ReadAllValue(string addr = "VB100", ushort length = 11) + //{ + // byte[,] data = new byte[length, 8]; + // //需要自行解析,length为地址个数 + // siemensTcpNet.ReadByte(addr); + // OperateResult result = siemensTcpNet.Read(addr, length); + // if (result.IsSuccess) + // { + + // if (result.Content.Length > 0) + // { + + // for (int i = 0; i < result.Content.Length; i++) + // { + + // int row = i / 8; + // int col = i % 8; + // data[row, col] = result.Content[i]; + + // } + // return data; + + + // } + + // } + // else + // { + // Console.WriteLine($"PLC IO 取值失败,地址为{addr},地址个数为{length}"); + // return null; + // } + //} + + /// + /// 读多个连续的二进制数据 转为字节数组 + /// + /// + /// + /// + public byte[] ReadAllValue(string addr = "VB100", ushort length = 12) + { + + //需要自行解析,length为地址个数 + siemensTcpNet.ReadByte(addr); + OperateResult result = siemensTcpNet.Read(addr, length); + if (result.IsSuccess) + { + + return result.Content; + + } + else + { + Console.WriteLine($"PLC IO 取值失败,地址为{addr},地址个数为{length}"); + return null; + } + } + + public void ConnectClose()