.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/06d8e01f-6afb-4384-90b8-31f0488cd604.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/21a5a3a3-5cdb-4cd3-a5e2-25be17fb4dfe.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/49ec3933-2a6b-4835-ab77-24f5cfc05e26.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/67e4ef9b-7188-43f4-a60f-46c9a1d6bd44.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/72178599-9865-468a-a3b6-7e0cf3fce2a8.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/848a02bc-1e77-4a4d-8129-5fd396f4d138.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/c30fdd47-6615-4811-b8bd-dfc4b98d2d2f.vsidxBinary files differ
.vs/HH.WCS.Mobox3.DSZSH/FileContentIndex/f1cb2527-5e7a-4ff5-bd94-7e85a024df58.vsidxBinary files differ
HH.WCS.Mobox3.DSZSH.csproj
@@ -236,13 +236,16 @@ <Compile Include="core\WCSCore.cs" /> <Compile Include="core\WMSCore.cs" /> <Compile Include="device\TcpClientHelper.cs" /> <Compile Include="models\TN_RelocationList_Detail.cs" /> <Compile Include="models\TN_Relocation_List.cs" /> <Compile Include="models\TN_SpotCheck_Detail.cs" /> <Compile Include="models\TN_Spot_Check.cs" /> <Compile Include="process\TaskProcess.cs" /> <Compile Include="util\SqlHelper.cs" /> <Compile Include="models\TN_Container_Item.cs" /> <Compile Include="models\TN_Check_Detail.cs" /> <Compile Include="models\TN_Check_Order.cs" /> <Compile Include="models\TN_Inbound_Order.cs" /> <Compile Include="models\TN_Order_Task.cs" /> <Compile Include="models\TN_Outbound_Order.cs" /> <Compile Include="models\TN_Outbound_Detail.cs" /> <Compile Include="models\TN_Shift_Detail.cs" /> Models/TN_CG_Detail.cs
@@ -69,10 +69,10 @@ /// </summary> public string S_QUALITY_GRADE { get; set; } = string.Empty; /// <summary> /// 产线号 /// </summary> public int N_PRODUCT_LINE { get; set; } = 0; // NOTE 后续MES可能会提供,先创建 ///// <summary> ///// 产线号 ///// </summary> //public int N_PRODUCT_LINE { get; set; } = 0; // NOTE 后续MES可能会提供,先创建 // ---------------- Models/TN_Order_Task.cs
File was deleted Program.cs
@@ -26,6 +26,9 @@ // 4.0 开启Modbus //StartModbus(); // TCP测试 //TcpClientHelper.Link("127.0.0.1", 8550); // 5.0 开启线程 var rc = HostFactory.Run(x => { x.Service<WorkThread>(s => { @@ -52,7 +55,7 @@ Console.WriteLine("Startup ApiController"); Task.Run(() => { var url = Settings.WebApiUrl; // 运行时修改 config.json 无效 var url = Settings.WebApiUrl; Console.WriteLine(url); using (WebApp.Start<Startup>(url)) { @@ -67,10 +70,12 @@ /// </summary> private static void StartTcp() { var tcpServerIP = Settings.TcpServerIp; // 运行时修改 config.json 无效 var tcpServerPort = Settings.TcpServerPort; // 运行时修改 config.json 无效 var tcpServerIP = Settings.TcpServerIp; var tcpServerPort = Settings.TcpServerPort; new TcpServer(tcpServerIP, tcpServerPort); //var res = TcpClientHelper.Init(tcpServerIP, tcpServerPort); //var res = TcpClientHelper.Init(tcpServerIP, 8550); //LogHelper.Info($"TcpClient连接" + (res ? "成功" : "失败")); } /// <summary> @@ -97,7 +102,7 @@ private static void StartModbus() { // 所有的Modbus设备 var allPLCDevice = Settings.ProductionLines; // 运行时修改 config.json 无效 var allPLCDevice = Settings.ProductionLines; if (allPLCDevice.Count > 0) { foreach (var item in allPLCDevice) { @@ -115,6 +120,9 @@ tasks.Add(GetTask(WCSCore.Dispatch)); // 测试:托盘下线 tasks.Add(GetTask(Monitor.CheckInbound)); // 轮询:出库单状态 tasks.Add(GetTask(Monitor.CheckOutboundOrder)); api/ApiHelper.cs
@@ -45,6 +45,7 @@ var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == model.StartLoc) // 指定:起点货位号 .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 0) // 起点绑定前没有容器 .First(); if (startLoc == null) { @@ -59,12 +60,6 @@ S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_CNTR_TYPE = "好运箱", }; if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { info = $"插入货位容器关系失败:" + JsonConvert.SerializeObject(locCntrRel); LogHelper.Info(info); return NewSimpleResult(4, info); } // TODO 满箱入库算法待优化 var endLoc = db.Queryable<TN_Location>() @@ -87,6 +82,13 @@ LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { info = $"插入货位容器关系失败:" + JsonConvert.SerializeObject(locCntrRel); tran.RollbackTran(); LogHelper.Info(info); return NewSimpleResult(4, info); } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, @@ -266,7 +268,9 @@ // TODO 暂定选择最低层按区位顺序入库,后面待修改 var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.空托存放区].Contains(a.S_AREA_CODE)) .Where(l => Settings.AreaMap[AreaName.空托存放区].Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) .OrderBy(l => l.N_LAYER) .First(); @@ -361,9 +365,11 @@ // TODO 暂定选择最低层按区位顺序入库,后面待修改 var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.空箱存放区].Contains(a.S_AREA_CODE)) .OrderBy(l => l.N_LAYER) .OrderBy(l => l.S_AREA_CODE).First(); .Where(l => Settings.AreaMap[AreaName.空箱存放区].Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) .OrderBy(l => new { l.N_LAYER }) .First(); if (endLoc == null) { return NewSimpleResult(4, $"暂时没有符合条件的终点放货位"); @@ -451,10 +457,10 @@ } var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.包装区].Contains(a.S_AREA_CODE)) .Where(l => Settings.AreaMap[AreaName.包装区].Contains(l.S_AREA_CODE)) .Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 0) // 筛选:空货位 .First(); if (endLoc == null) { @@ -542,10 +548,10 @@ } var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.包装区].Contains(a.S_AREA_CODE)) .Where(l => Settings.AreaMap[AreaName.包装区].Contains(l.S_AREA_CODE)) .Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 0) .First(); if (endLoc == null) { @@ -707,7 +713,8 @@ var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == locCntrRel.S_LOC_CODE) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 1) .First(); if (startLoc == null) { @@ -719,16 +726,16 @@ var endLoc = new TN_Location(); if (locCntrRel.S_CNTR_TYPE == "托盘") { endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.满托存放区].Contains(a.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 .Where(l => Settings.AreaMap[AreaName.满托存放区].Contains(l.S_AREA_CODE)) .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 0) // 筛选:空货位 .First(); } else if (locCntrRel.S_CNTR_TYPE == "好运箱") { endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.满箱存放区].Contains(a.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) .Where(l => Settings.AreaMap[AreaName.满箱存放区].Contains(l.S_AREA_CODE)) .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 0) .First(); } else { @@ -827,7 +834,8 @@ var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == locCntrRel.S_LOC_CODE) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 1) .First(); if (startLoc == null) { @@ -839,7 +847,8 @@ var endLoc = db.Queryable<TN_Location>() .Where(l => l.S_AREA_CODE == model.EndArea) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0).First(); .Where(a => a.N_CURRENT_NUM == 0) .First(); if (endLoc == null) { return NewSimpleResult(3, "查询:没有找到合适的终点货位"); @@ -915,6 +924,7 @@ var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == model.StartLoc) .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 1) .First(); var locCntrRel = db.Queryable<TN_Loc_Container>() config/config.json
@@ -128,7 +128,7 @@ "Id": "2", "Name": "托盘产线2", "PlcIp": "127.0.0.1", "PlcPort": 502, "PlcPort": 503, "SlaveId": 2, "OnLoc": [ "CX21" @@ -141,7 +141,7 @@ "Id": "3", "Name": "好运箱产线1", "PlcIp": "127.0.0.1", "PlcPort": 502, "PlcPort": 504, "SlaveId": 3, "OnLoc": [ "CX31" @@ -154,7 +154,7 @@ "Id": "4", "Name": "好运箱产线2", "PlcIp": "127.0.0.1", "PlcPort": 502, "PlcPort": 505, "SlaveId": 4, "OnLoc": [ "CX41" @@ -163,5 +163,39 @@ "CX42" ] } ], "ProdAgvSite": [ { "Code": "work111", "ProdId": 0 }, { "Code": "work112", "ProdId": 0 }, { "Code": "work121", "ProdId": 1 }, { "Code": "work122", "ProdId": 1 }, { "Code": "work131", "ProdId": 2 }, { "Code": "work132", "ProdId": 2 }, { "Code": "work141", "ProdId": 3 }, { "Code": "work142", "ProdId": 3 } ] } core/Monitor.cs
@@ -4,37 +4,167 @@ using System.Text; using System.Threading.Tasks; using HH.WCS.Mobox3.DSZSH.device; using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.util; using HH.WCS.Mobox3.DSZSH.wms; using Microsoft.Win32; using Newtonsoft.Json; namespace HH.WCS.Mobox3.DSZSH.core { public class Monitor { public class ItemData { public string item_code { get; set; } public string batch_no { get; set;} public string cntr_code { get; set; } } public static void CheckInbound() { var taskName = TaskName.托盘_满托下线入库; var db = new SqlHelper<object>().GetInstance(); var info = ""; try { // 查产线是否有物料信息 foreach (var prod in Settings.ProductionLines) { if (int.Parse(prod.Id) > 1) break; // TEST var itemCode = ""; var batchNo = ""; var cntrCode = ""; var startLocCode = ""; //var prodDevice = new ProductionLineDevice(prod); // TODO 待需求确定后再处理 //TcpClientHelper.Link("127.0.0.1", 8550); // 用于测试 TcpClientHelper.Link(prod.PlcIp, prod.PlcPort); var cgDetail = new TN_CG_Detail { S_ITEM_CODE = itemCode, S_BATCH_NO = batchNo, S_CNTR_CODE = cntrCode, }; // TCPClient传递信息的时候,不要用断点阻塞程序 // {"item_code":"CG1001","batch_no":"BN1001","cntr_code":"CN2505111"} if (!TcpClientHelper.TryReadProductionLine(out byte[] read)) { info = $"测试{prod.Id}号产线{prod.PlcIp}:{prod.PlcPort}:读取产线信息失败"; LogHelper.Info(info); continue; } var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == startLocCode) // 指定:起点货位号 .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .First(); // 3. 将寄存器值转换为字节数组 //byte[] bytes = TcpClientHelper.ConvertRegistersToBytes(registers); // 4. 将字节数组转换为字符串 string result = TcpClientHelper.ConvertBytesToString(read); //var itemData = BitConverter.ToString(read); LogHelper.Info($"读取的产线信息{result}"); var data = JsonConvert.DeserializeObject<ItemData>(result); LogHelper.Info(JsonConvert.SerializeObject(data)); var itemCode = data.item_code; var batchNo = data.batch_no; var cntrCode = data.cntr_code; var startLocCode = prod.OffLoc[0]; // 用于测试 //var startLocCode = "CX01"; // 用于测试 var cgDetail = new TN_CG_Detail { S_ITEM_CODE = itemCode, S_BATCH_NO = batchNo, S_CNTR_CODE = cntrCode, }; var startLoc = db.Queryable<TN_Location>() .Where(l => l.S_CODE == startLocCode) // 指定:起点货位号 .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 0) .First(); if (startLoc == null) { info = $"起点位置 '{startLocCode}' 不存在或不具备取货要求"; LogHelper.Info(info); continue; //return; } // 绑定货位和容器号 var locCntrRel = new TN_Loc_Container { S_LOC_CODE = startLocCode, S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_CNTR_TYPE = "托盘", }; //if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { // info = $"插入货位容器关系失败:" + JsonConvert.SerializeObject(locCntrRel); // LogHelper.Info(info); // continue; // //return; //} // TODO 满箱入库算法待优化 var endLoc = db.Queryable<TN_Location>() .Where(a => Settings.AreaMap[AreaName.空托存放区].Contains(a.S_AREA_CODE)) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 .OrderBy(l => l.N_LAYER) .First(); if (endLoc == null) { info = "空托入库暂时没有合适的货位可以入库"; LogHelper.Info(info); continue; } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Insertable<TN_CG_Detail>(cgDetail).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"插入容器货品信息表失败:物料编码{cgDetail.S_ITEM_CODE},容器编码{cgDetail.S_CNTR_CODE}"; LogHelper.Info(info); continue; } if (db.Insertable<TN_Loc_Container>(locCntrRel).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"插入货位容器关系表失败:货位编码{locCntrRel.S_LOC_CODE},容器编码{locCntrRel.S_CNTR_CODE}"; LogHelper.Info(info); continue; } if (db.Updateable<TN_Location>(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; LogHelper.Info(info); continue; } if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY }).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; LogHelper.Info(info); continue; } if (db.Insertable<TN_Task>(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"生成任务'{taskName}'失败,容器号{cntId},起点{startLoc.S_CODE},终点货架{endLoc.S_CODE}"; LogHelper.Info(info); continue; } tran.CommitTran(); info = $"生成任务'{taskName}'成功,容器号{cntId},起点{startLoc.S_CODE},终点货架{endLoc.S_CODE}"; LogHelper.Info(info); continue; } } } catch (Exception ex) { @@ -107,6 +237,8 @@ var startLoc = db.Queryable<TN_Location>() .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 1) .First(); if (startLoc == null) { @@ -190,7 +322,7 @@ var info = ""; try { var orderList = db.Queryable<TN_Check_Order>() var orderList = db.Queryable<TN_Spot_Check>() .Where(c => c.N_B_STATE == 1) .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) .ToList(); @@ -200,22 +332,22 @@ return; } var detailList = new List<TN_Check_Detail>(); var detailList = new List<TN_SpotCheck_Detail>(); foreach (var order in orderList) { var doingCount = db.Queryable<TN_Check_Detail>() .Count(d => d.S_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_Check_Detail>() .Count(d => d.S_NO == order.S_NO); var doingCount = db.Queryable<TN_SpotCheck_Detail>() .Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_SpotCheck_Detail>() .Count(d => d.S_OO_NO == order.S_NO); LogHelper.Info($"轮询--{taskName}--统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); if (doingCount == allCount) { order.N_B_STATE = 2; // 所有任务都已执行 db.Updateable<TN_Check_Order>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); db.Updateable<TN_Spot_Check>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); continue; } var checkDetailList = db.Queryable<TN_Check_Detail>() .Where(a => a.S_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 var checkDetailList = db.Queryable<TN_SpotCheck_Detail>() .Where(a => a.S_OO_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 .ToList(); if (checkDetailList.Count == 0) { @@ -258,7 +390,7 @@ LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Check_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { if (db.Updateable<TN_SpotCheck_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"轮询--{taskName}:修改{taskName}单明细表状态为完成--失败!"); continue; @@ -312,7 +444,7 @@ var db = new SqlHelper<object>().GetInstance(); var info = ""; try { var orderList = db.Queryable<TN_Shift_Order>() var orderList = db.Queryable<TN_Relocation_List>() .Where(c => c.N_B_STATE == 1) .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) .ToList(); @@ -322,22 +454,22 @@ return; } var detailList = new List<TN_Shift_Detail>(); var detailList = new List<TN_RelocationList_Detail>(); foreach (var order in orderList) { var doingCount = db.Queryable<TN_Shift_Detail>() .Count(d => d.S_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_Shift_Detail>() .Count(d => d.S_NO == order.S_NO); var doingCount = db.Queryable<TN_RelocationList_Detail>() .Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 var allCount = db.Queryable<TN_RelocationList_Detail>() .Count(d => d.S_OO_NO == order.S_NO); LogHelper.Info($"轮询--{taskName}--统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); if (doingCount == allCount) { order.N_B_STATE = 2; // 所有任务都已执行 db.Updateable<TN_Shift_Order>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); db.Updateable<TN_Relocation_List>(order).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand(); continue; } var checkDetailList = db.Queryable<TN_Shift_Detail>() .Where(a => a.S_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 var checkDetailList = db.Queryable<TN_RelocationList_Detail>() .Where(a => a.S_OO_NO == order.S_NO && a.N_B_STATE == 1) // 已下发 .ToList(); if (checkDetailList.Count == 0) { @@ -354,6 +486,8 @@ var startLoc = db.Queryable<TN_Location>() .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 .Where(l => l.N_CURRENT_NUM == 1) .First(); if (startLoc == null) { @@ -380,7 +514,7 @@ LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 using (var tran = db.Ado.UseTran()) { if (db.Updateable<TN_Shift_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { if (db.Updateable<TN_RelocationList_Detail>(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { tran.RollbackTran(); LogHelper.Info($"轮询--{taskName}:修改{taskName}单明细表状态为完成--失败!"); continue; core/WCSCore.cs
@@ -127,9 +127,19 @@ try { ModbusHelper.Relink(); var prodLineInfo = Settings.ProductionLines[0]; //var loc = db.Queryable<TN_Location>() // .Where(l => l.S_AGV_SITE == model.station_name && Settings.AreaMap[AreaName.包装区].Contains(l.S_AREA_CODE)) // .First(); var prodLineDevice = new ProductionLineDevice(prodLineInfo.PlcIp, prodLineInfo.PlcPort); if (!Settings.AgvSite_ProdLineCodeMap.TryGetValue(model.station_name, out int prodIndex)) { info = $"AGV 站点{model.station_name}不是合法的产线接驳位站点"; LogHelper.Info(info); return NewReturnResult(1, info); } var prodLineInfo = Settings.ProductionLines[prodIndex]; var prodLineDevice = new ProductionLineDevice(prodLineInfo); if (!prodLineDevice.LoadDeviceStateOk()) { info = "与产线设备通讯失败"; LogHelper.Info(info); @@ -155,7 +165,7 @@ return NewReturnResult(3, info); } if (model.apply_code == "5") { if (model.apply_code == "5") { // 请求取货 if (prodLineDevice.FullOffline != 1) { info = $"当前输送线满料下线信号不为1,无法取货"; LogHelper.Info(info); @@ -173,7 +183,7 @@ return NewReturnResult(0, info); } else if (model.apply_code == "1") { else if (model.apply_code == "1") { // 请求卸货 if (prodLineDevice.AllowAgvPlacePallet != 1) { info = $"当前输送线允许放托盘信号不为1,无法放货"; LogHelper.Info(info); @@ -191,7 +201,7 @@ return NewReturnResult(0, info); } else { info = $"当前输送线允许"; info = $"当前AGV请求码不为 5取货 或 1卸货"; LogHelper.Info(info); return NewReturnResult(8, info); } device/ProductionLineDevice.cs
@@ -22,10 +22,14 @@ Port = port; Id = id; } public ProductionLineDevice(Config.ProductionLine line) { Ip = line.PlcIp; Port = line.PlcPort; Id = line.Id; } public string Id { get; set; } /// <summary> /// 系统状态:0本地 1联动(AGV模式) 2故障 device/TcpClientHelper.cs
@@ -64,7 +64,6 @@ lock (_linkLock) { try { // 若Socket存在但实际已断开,强制清理 if (_clientSocket != null && (_clientSocket.Poll(0, SelectMode.SelectRead) && _clientSocket.Available == 0)) { SafeCloseSocket(); @@ -72,13 +71,18 @@ // 原有逻辑 if (_clientSocket != null && _clientSocket.Connected) { LogHelper.Info($"电梯已连接,无需重连,IP:{ip},端口:{port}"); return false; //if (ip == _ip && port == _port) { LogHelper.Info($"产线已连接,无需重连,IP:{ip},端口:{port}"); return false; //} //LogHelper.Info($"oldIP={_ip};newIP={ip};oldPort={_port};newPort={port}"); //SafeCloseSocket(); } return Init(ip, port); } catch (Exception ex) { LogHelper.Error($"电梯重连失败,IP:{ip},端口:{port},异常:{ex.Message}", ex); LogHelper.Error($"产线重连失败,IP:{ip},端口:{port},异常:{ex.Message}", ex); return false; } } @@ -210,6 +214,77 @@ } } /// <summary> /// {\"item_code\":\"CG1001\",\"batch_no\":\"BN1001\",\"cntr_code\":\"CN2505111\"}<br/> /// {"item_code":"CG1001","batch_no":"BN1001","cntr_code":"CN2505111"} /// </summary> /// <param name="read"></param> /// <returns></returns> public static bool TryReadProductionLine(out byte[] read) { read = null; try { if (_clientSocket != null && _clientSocket?.Connected == true) { if (!_receivedDataQueue.TryGetValue($"{_ip}:{_port}", out byte[] result)) { LogHelper.Info($"读产线托盘下线数据失败"); //read = result; return false; } LogHelper.Info($"读产线托盘下线数据成功:{BitConverter.ToString(result)}"); read = result; return true; } else { //LogHelper.Info($"_clientSocket={_clientSocket} connected={_clientSocket?.Connected}"); Link(_ip, _port); LogHelper.Info($"读产线托盘下线数据失败(未连接),准备重连"); return false; } } catch (Exception ex) { //LogHelper.Error($"读产线托盘下线数据失败(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); LogHelper.InfoEx(ex); return false; /* 异常处理 */ } //return false; } /// <summary> /// 将Modbus寄存器数组转换为字节数组 /// </summary> /// <param name="registers">Modbus寄存器数组</param> /// <returns>字节数组</returns> public static byte[] ConvertRegistersToBytes(ushort[] registers) { // 每个寄存器是16位(2字节),所以总字节数是寄存器数量的2倍 byte[] bytes = new byte[registers.Length * 2]; for (int i = 0; i < registers.Length; i++) { // Modbus使用大端序,高位字节在前 bytes[i * 2] = (byte)(registers[i] >> 8); // 高位字节 bytes[i * 2 + 1] = (byte)(registers[i] & 0xFF); // 低位字节 } return bytes; } /// <summary> /// 将字节数组转换为字符串 /// </summary> /// <param name="bytes">字节数组</param> /// <returns>转换后的字符串</returns> public static string ConvertBytesToString(byte[] bytes) { // 查找第一个0x00字节(字符串结束符)的位置 int length = Array.IndexOf(bytes, (byte)0); if (length < 0) length = bytes.Length; // 如果没有结束符,使用全部字节 // 根据设备使用的编码转换(常见的有ASCII或UTF-8) // 这里使用ASCII编码作为示例,实际应根据设备文档确定编码方式 return Encoding.ASCII.GetString(bytes, 0, length); // 如果是UTF-8编码,使用下面这行代替上面那行 // return Encoding.UTF8.GetString(bytes, 0, length); } public static bool WriteElevatorDownOk(byte[] sends) { try { models/TN_RelocationList_Detail.cs
New file @@ -0,0 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.models { public class TN_RelocationList_Detail : BaseModel { public string S_OO_NO { get; set; } public string S_ITEM_CODE { get; set; } public string S_ITEM_NAME { get; set; } //public string S_LOC_CODE { get; set; } public string S_CNTR_CODE { get; set; } public string S_BATCH_NO { get; set; } public string S_END_AREA { get; set; } /// <summary> /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 /// </summary> public int N_B_STATE { get; set; } = 1; // 创建即执行 } } models/TN_Relocation_List.cs
New file @@ -0,0 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HH.WCS.Mobox3.DSZSH.models { public class TN_Relocation_List : BaseModel { public string S_NO { get; set; } //public string S_ITEM_CODE { get; set; } //public string S_ITEM_NAME { get; set; } //public string S_BATCH_NO { get; set; } //public int N_COUNT { get; set; } public string S_END_AREA { get; set; } /// <summary> /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 /// </summary> public int N_B_STATE { get; set; } = 0; // 创建后需要确认执行 } } models/TN_SpotCheck_Detail.cs
New file @@ -0,0 +1,30 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 抽检单明细 /// </summary> [SugarTable("TN_SpotCheck_Detail")] public class TN_SpotCheck_Detail : BaseModel { public string S_OO_NO { get; set; } public string S_ITEM_CODE { get; set; } public string S_ITEM_NAME { get; set; } //public string S_LOC_CODE { get; set; } public string S_CNTR_CODE { get; set; } public string S_BATCH_NO { get; set; } public string S_END_AREA { get; set; } /// <summary> /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 /// </summary> public int N_B_STATE { get; set; } = 1; // 创建即执行 } } models/TN_Spot_Check.cs
New file @@ -0,0 +1,26 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using SqlSugar; namespace HH.WCS.Mobox3.DSZSH.models { /// <summary> /// 抽检单 /// </summary> [SugarTable("TN_Spot_Check")] public class TN_Spot_Check : BaseModel { public string S_NO { get; set; } //public string S_ITEM_CODE { get; set; } //public string S_ITEM_NAME { get; set; } //public string S_BATCH_NO { get; set; } //public int N_COUNT { get; set; } public string S_END_AREA { get; set; } /// <summary> /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 /// </summary> public int N_B_STATE { get; set; } = 0; // 创建后需要确认执行 } } process/TaskProcess.cs
@@ -7,6 +7,7 @@ using HH.WCS.Mobox3.DSZSH.models; using HH.WCS.Mobox3.DSZSH.wms; using HH.WCS.Mobox3.DSZSH; using HH.WCS.Mobox3.DSZSH.util; namespace HH.WCS.Mobox3.DSZSH.process { internal class TaskProcess { @@ -111,6 +112,9 @@ var result = false; var start = "0"; var end = "0"; var taskType = mst.S_TYPE.Trim(); //var db = new SqlHelper<object>().GetInstance(); if (mst.N_B_STATE == 0) { start = LocationHelper.GetAgvSite(mst.S_START_LOC); end = LocationHelper.GetAgvSite(mst.S_END_LOC); @@ -119,6 +123,18 @@ // end = LocationHelper.GetAgvSite(mst.S_END_LOC, true); //} // 任务下发后,无论AGV是否接受,state 都是2了,就算暂停无济于事 // 如果后续需要让暂停的任务不再分发,那么必须改变现有的state判断机制 //if (mst.S_TYPE == TaskName.移库) { // var detail = db.Queryable<TN_RelocationList_Detail>() // .Where(d => d.S_CNTR_CODE == mst.S_CNTR_CODE).First(); // if (detail == null) { // } //} LogHelper.Info($"NDC推送任务 {mst.S_CODE};" + "start=" + start + "end= " + end); var startLoc = LocationHelper.GetLoc(mst.S_START_LOC); var endLoc = LocationHelper.GetLoc(mst.S_END_LOC); util/Settings.cs
@@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using HH.WCS.Mobox3.DSZSH.util; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -16,7 +18,7 @@ public static List<Config.Area> Areas { get; set; } = new List<Config.Area>(); public static List<Config.Task> Tasks { get; set; } = new List<Config.Task>(); public static List<Config.ProductionLine> ProductionLines { get; set; } = new List<Config.ProductionLine>(); public static List<Config.ProdAgvSite> ProdAgvSites { get; set; } = new List<Config.ProdAgvSite>(); /// <summary> /// 库区字典(加载后就不变) /// </summary> @@ -61,6 +63,11 @@ Tasks = root.Tasks; ProductionLines = root.ProductionLines; ProdAgvSites = root.ProdAgvSite; foreach (var item in ProdAgvSites) { AgvSite_ProdLineCodeMap.Add(item.Code, item.ProdId); } } catch (FileNotFoundException) { LogHelper.Info("JSON 文件未找到"); @@ -87,12 +94,16 @@ } private static void LoadProdLines() { foreach (var prod in ProductionLines) { } //var db = new SqlHelper<object>().GetInstance(); //for (int i = 0; i < ProductionLines.Count; i++) { // var line = ProductionLines[i]; // // 通过OnLoc OffLoc找到AGVsite然后写入字典 //} } } // [Convert JSON to C# Classes Online - Json2CSharp Toolkit](https://json2csharp.com/) public class Config { @@ -100,6 +111,11 @@ public class Area { public string Name { get; set; } public List<string> Codes { get; set; } } public class ProdAgvSite { public string Code { get; set; } public int ProdId { get; set; } } public class ProductionLine { @@ -121,6 +137,7 @@ public List<Area> Areas { get; set; } public List<Task> Tasks { get; set; } public List<ProductionLine> ProductionLines { get; set; } public List<ProdAgvSite> ProdAgvSite { get; set; } } public class Task { @@ -128,6 +145,8 @@ public List<string> StartAreas { get; set; } public List<string> EndAreas { get; set; } } } public class AreaName {