diff --git a/ProductionMgr/Tnb.ProductionMgr/RedisBackGround.cs b/ProductionMgr/Tnb.ProductionMgr/RedisBackGround.cs index 83fedbc8..bef33f31 100644 --- a/ProductionMgr/Tnb.ProductionMgr/RedisBackGround.cs +++ b/ProductionMgr/Tnb.ProductionMgr/RedisBackGround.cs @@ -1,22 +1,30 @@ using System; using System.Data; +using System.DirectoryServices.ActiveDirectory; using System.Dynamic; using System.Security.Policy; using System.Text; using Aop.Api.Domain; using JNPF; using JNPF.Common.Cache; +using JNPF.Common.Core.Manager; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Extension; using JNPF.FriendlyException; +using JNPF.Systems.Interfaces.System; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NetTaste; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.OpenXmlFormats; +using NPOI.SS.Formula.Eval; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X509.Qualified; using Qiniu.Util; using SqlSugar; +using Tnb.BasicData.Entities; using Tnb.Common.Extension; using Tnb.Common.Redis; using Tnb.Common.Utils; @@ -44,18 +52,29 @@ namespace Tnb.ProductionMgr private Timer? Floor2UpMachinecodetimer; // 二楼下升降机 private Timer? Floor2DownMachinecodetimer; + // 二楼料架配送 + private Timer? Floor2RackDeliverytimer; + + public static SemaphoreSlim s_taskExecuteRackDelivery = new(1); private readonly RedisData _redisData; private readonly IPrdInstockService _prdInstockService; private readonly ISqlSugarRepository _repository; private readonly IWmsPDAScanInStockService _wmsPDAScanInStock; + private readonly IUserManager _userManager; + private readonly IBillRullService _billRullService; + private readonly IWareHouseService _wareHouseService; private readonly ElevatorControlConfiguration _eleCtlCfg = App.Configuration.Build(); - public RedisBackGround(RedisData redisData, IPrdInstockService prdInstockService, ISqlSugarRepository repository, IWmsPDAScanInStockService wmsPDAScanInStock) + public RedisBackGround(RedisData redisData, IPrdInstockService prdInstockService, ISqlSugarRepository repository, IWmsPDAScanInStockService wmsPDAScanInStock + , IUserManager userManager, IBillRullService billRullService, IWareHouseService wareHouseService) { _redisData = redisData; _prdInstockService = prdInstockService; _repository = repository; _wmsPDAScanInStock = wmsPDAScanInStock; + _userManager = userManager; + _billRullService = billRullService; + _wareHouseService = wareHouseService; } //获取redis数据 private void GetRedisData(object state) @@ -318,7 +337,7 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA // 二楼料架补充 - protected ILogger LoggerFloor2RackSupplement => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/customFloor2RackSupplement{DateTime.Now:yyyyMMdd}.log", cfgOpts => + protected ILogger LoggerFloor2RackDelivery => LoggerFactory.Create(builder => builder.AddFile($"{AppContext.BaseDirectory}/logs/customFloor2RackDelivery{DateTime.Now:yyyyMMdd}.log", cfgOpts => { //cfgOpts.DateFormat = "yyyy-MM-dd HH:mm:ss.fff"; cfgOpts.MessageFormat = (logMsg) => @@ -448,6 +467,8 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA var DistaskH = _repository.AsSugarClient().Queryable().Where(p => p.carry_code == result && p.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID).OrderByDescending(p => p.create_time).First(); if (DistaskH != null) { + Logger.LogInformation($"【定时任务SSXcode】DistaskH != null putdic.Keys.Contains(DistaskH.startlocation_code):{putdic.Keys.Contains(DistaskH.startlocation_code)}"); + Dictionary dicCommand2 = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = key, @@ -467,6 +488,7 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA } else { + Logger.LogInformation($"【定时任务SSXcode】DistaskH == null {_repository.AsSugarClient().Queryable().Where(p => p.carry_code == result && p.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID).OrderByDescending(p => p.create_time).ToSqlString()}"); Dictionary dicCommand2 = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = key, @@ -500,24 +522,147 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA CheckGettimer?.Dispose(); Scantimer?.Dispose(); SSXcodetimer?.Dispose(); - + Floor2UpMachinecodetimer?.Dispose(); + Floor2DownMachinecodetimer?.Dispose(); + Floor2RackDeliverytimer.Dispose(); } - #region 二楼升降机 - + #region 二楼上升降机机械臂 // 上升降机 - private void Floor2UpMachinecode(object args) + private async void Floor2UpMachinecode(object args) { - // 补充料架 - //var DistaskH = _repository.AsSugarClient().Queryable().Where(p => p.carry_code == && p.status != WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID).OrderByDescending(p => p.create_time).First(); + using (var db = _repository.AsSugarClient().CopyNew()) + { + string barcode = Floor2UpDownMachinecode_GetTag(MechanicalArmConsts.上升降机条码).ToString(); + if (string.IsNullOrEmpty(barcode)) + { + LoggerFloor2UpDownMachine.LogError($@"【上升降机】未取到条码数据"); + return; + } + + // 读取上升降机的左右料架区配置 + string[] configs = new string[2] { "二楼上升降机机械臂左", "二楼上升降机机械臂右" }; + // 左右料架区配置 + List WmsMechanicalArmHs = db.Queryable() + .Where(r => configs.Contains(r.name) && r.mechanicalconfirm == 1).ToList(); + + // 是否可以放货 + if (WmsMechanicalArmHs.Count == 0) + { + LoggerFloor2UpDownMachine.LogWarning($@"【上升降机】目前没有可以放货的料架区"); + return; + } + + // 如果条码已被绑定 + if (WmsMechanicalArmHs.Where(r => !string.IsNullOrEmpty(r.barcodes) && r.barcodes.Contains(barcode)).Count() > 0) + { + LoggerFloor2UpDownMachine.LogWarning($@"【上升降机】条码{barcode}已被绑定"); + return; + } + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】扫描到有效条码 {barcode}"); + + // 获取下到输送线9和10的未完成的出库单 + List WmsEmptyOutstockHs = db.Queryable() + .InnerJoin((a, b) => a.id == b.bill_id) + .Where((a, b) => (a.location_id == "32609238573589" || a.location_id == "32609229889045") && a.bindrackcomplete != WmsWareHouseConst.BILLSTATUS_COMPLETE_ID + && b.carry_code == barcode).ToList(); + + if (WmsEmptyOutstockHs.Count() == 0) + { + LoggerFloor2UpDownMachine.LogWarning($@"【上升降机】未找到条码{barcode}的输送线为9、10的出库单"); + return; + } + // 出库单 + WmsEmptyOutstockH WmsEmptyOutstockH = WmsEmptyOutstockHs.OrderByDescending(r => r.create_time).First(); + + // 找到条码在的出库单 + string ckdCode = WmsEmptyOutstockH.bill_code; + int ckdRemainBindRackNum = (int)(WmsEmptyOutstockH.remainbindracknum != null ? WmsEmptyOutstockH.remainbindracknum : 0); + + //扫描到的料箱 a.对应出库单的b.码垛计数未达到满托数量的料架区 + IEnumerable targetConfigs = WmsMechanicalArmHs.Where(r => r.outbill == ckdCode && r.stackingcount < r.maxnum); + + WmsMechanicalArmH target; + await db.Ado.BeginTranAsync(); + try + { + // 找不到对应的料架 + if (targetConfigs.Count() == 0) + { + // 有空闲料架区且绑定了料架时 + targetConfigs = WmsMechanicalArmHs.Where(r => string.IsNullOrEmpty(r.outbill)).OrderBy(r => r.id); + if (targetConfigs.Count() > 0) + { + target = targetConfigs.First(); + + // 计算当前料架区的满托数量 + int? maxnum = ckdRemainBindRackNum > target.maxracknum ? ckdRemainBindRackNum % target.maxracknum : ckdRemainBindRackNum; + + // 更新 出库单、满托数量 + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】为条码 {barcode} 所在的出库单 {ckdCode} 占用了一个空闲料架"); + await db.Updateable().SetColumns(r => new WmsMechanicalArmH + { + outbill = ckdCode, + maxnum = maxnum + }).Where(r => r.id == target.id).ExecuteCommandAsync(); + + bool result = await Floor2UpDownMachinecode_SetTag($"上升降机满托{target.stackingposition}数量", maxnum.ToString()); + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】设定升降机满托{target.stackingposition}满托数量为 {maxnum} 结果为 {result}"); + } + else + { + LoggerFloor2UpDownMachine.LogError($@"【上升降机】条码{barcode}找不到绑定出库单{ckdCode}的料架区,且没有空闲的料架区可以用于绑定此出库单!"); + await db.Ado.RollbackTranAsync(); + return; + } + } + + //如有多个料架绑定同个出库单则取第一个未满托的料架 + target = targetConfigs.First(); + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】当前条码目标料架区为 {JsonConvert.SerializeObject(target)}"); + + // 判断《上升降机空托1/2送到》是否为true + string tag_上升降机空托送到 = $@"上升降机空托{target.stackingposition}送到"; + + bool 上升降机空托送到 = (bool)Floor2UpDownMachinecode_GetTag(tag_上升降机空托送到); + + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】取值 {tag_上升降机空托送到} 结果为 {上升降机空托送到}"); + if (上升降机空托送到) + { + // 开始码垛 + bool result = await Floor2UpDownMachinecode_SetTag(MechanicalArmConsts.上升降机当前码垛位, target.stackingposition.ToString()); + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】码垛结果 {result}"); + // 回写料箱条码、码垛计数 + await db.Updateable().SetColumns(r => new WmsMechanicalArmH + { + barcodes = $"{target.barcodes},{barcode}".Trim(','), + stackingcount = r.stackingcount + 1 + }).Where(r => r.id == target.id).ExecuteCommandAsync(); + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】回写料箱条码、码垛计数"); + + // 回写出库单的剩余可绑定料架数量 + await db.Updateable().SetColumns(r => new WmsEmptyOutstockH + { + remainbindracknum = r.remainbindracknum - 1 + }).Where(r => r.id == WmsEmptyOutstockH.id).ExecuteCommandAsync(); + LoggerFloor2UpDownMachine.LogInformation($@"【上升降机】回写出库单的剩余可绑定料架数量"); + } + else + { + LoggerFloor2UpDownMachine.LogError($@"【上升降机】料架未送到 料架区{target.stackingposition}"); + } + await db.Ado.CommitTranAsync(); - // MechanicalArmConsts.上升降机满托2数量 - - // 扫码分配码垛位 - - + } + catch (Exception ex) + { + LoggerFloor2UpDownMachine.LogError(ex.ToString()); + LoggerFloor2UpDownMachine.LogError(ex.StackTrace); + await db.Ado.RollbackTranAsync(); + } + } } // 下升降机 @@ -525,33 +670,365 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA { // 补充料架 - // 扫码分配拆垛位 } + /// + /// 检查机械臂料架区信号(上升降机空托1送到) + /// + /// + public async Task 检查机械臂料架区信号_上升降机空托1送到() + { + using (var db = _repository.AsSugarClient().CopyNew()) + { + string[] configs_upMachine = new string[2] { "二楼上升降机机械臂左", "二楼上升降机机械臂右" }; + + // 找到AGV已到货,没有机械臂确认的数据 + ISugarQueryable WmsMechanicalArmHsuagar = db.Queryable() + .Where(r => r.agvconfirm == 1 && r.mechanicalconfirm == 0 && configs_upMachine.Contains(r.name)); + + foreach (WmsMechanicalArmH wmsMechanicalArmH in WmsMechanicalArmHsuagar.ToList()) + { + bool 上升降机请求送空托 = (bool)Floor2UpDownMachinecode_GetTag($"上升降机请求送空托{wmsMechanicalArmH.stackingposition}"); + + string data = _redisData.GetHash("东面提升机输送线", $"上升降机空托{wmsMechanicalArmH.stackingposition}送到").Result; + JObject? res = JsonConvert.DeserializeObject(data); + bool result = res != null && res["Value"] != null ? res.Value("Value") : false; + LoggerFloor2RackDelivery.LogInformation($"【送空托到上升降区】 上升降机空托{wmsMechanicalArmH.stackingposition}送到 结果为{result}"); + if (result) + { + // 绑定料架 + await db.Updateable().SetColumns(r => new WmsMechanicalArmH + { + mechanicalconfirm = 1 + }).Where(r => r.id == wmsMechanicalArmH.id).ExecuteCommandAsync(); + } + } + + return true; + } + } + + /// + /// 送空托到上升降区 + /// + /// + public async Task 送空托到上升降区() + { + using (var db = _repository.AsSugarClient().CopyNew()) + { + string[] configs_upMachine = new string[2] { "二楼上升降机机械臂左", "二楼上升降机机械臂右" }; + + // 找到没有绑定料架的且点位未锁定的料架区 + ISugarQueryable WmsMechanicalArmHsuagar = _repository.AsSugarClient().Queryable(). + InnerJoin((a, b) => a.point_id == b.id) + .Where((a, b) => string.IsNullOrEmpty(a.rackcode) && b.is_lock == 0 && configs_upMachine.Contains(a.name)); + + List WmsMechanicalArmHs = WmsMechanicalArmHsuagar.ToList(); + + if (WmsMechanicalArmHs.Count() == 0) + { + LoggerFloor2RackDelivery.LogWarning($"【送空托到上升降区】 无需补充料架区 {WmsMechanicalArmHsuagar.ToSqlString()}"); + return false; + } + + // 料架区 + WmsMechanicalArmH wmsMechanicalArmH = WmsMechanicalArmHs[0]; + + bool 上升降机请求送空托 = (bool)Floor2UpDownMachinecode_GetTag($"上升降机请求送空托{wmsMechanicalArmH.stackingposition}"); + if (!上升降机请求送空托) + { + LoggerFloor2RackDelivery.LogWarning($"【送空托到上升降区】 料架区 {wmsMechanicalArmH.name}{wmsMechanicalArmH.stackingposition} 上升降机请求送空托{wmsMechanicalArmH.stackingposition}信号不为true"); + return false; + } + + LoggerFloor2RackDelivery.LogInformation($"【送空托到上升降区】 即将补充料架区{wmsMechanicalArmH.name}"); + + + // 找到占用且未锁定的库位上的空料架 + ISugarQueryable rackStartLocations = + _repository.AsSugarClient().Queryable() + .InnerJoin((a, b) => a.id == b.location_id) + .LeftJoin((a, b, c) => b.id == c.carrybind_id) + .Where((a, b, c) => a.wh_id == "33780009364245" && a.is_use == "1" && a.is_lock == 0 && string.IsNullOrEmpty(c.id) + && b.carrystd_id == WmsWareHouseConst.CARRY_LJSTD_ID).OrderBy(a => a.id).Take(1); + + if (rackStartLocations.Count() == 0) + { + LoggerFloor2RackDelivery.LogWarning($"【送空托到上升降区】 暂存仓中没有可用的空料架 {rackStartLocations.ToSqlString()}"); + return false; + } + + BasLocation startLocation = rackStartLocations.First(); + + List startPoints = _repository.AsSugarClient().Queryable().Where(r => r.location_id == startLocation.id).ToList(); + + if (startPoints.Count == 0) + { + LoggerFloor2RackDelivery.LogError($"【送空托到上升降区】 起始库位{startLocation.location_code}未在点位表维护对应的点位"); + return false; + } + + List endPoints = _repository.AsSugarClient().Queryable().Where(r => r.id == wmsMechanicalArmH.point_id).ToList(); + + if (endPoints.Count == 0) + { + LoggerFloor2RackDelivery.LogError($"【送空托到上升降区】 终点{wmsMechanicalArmH.point_id} {wmsMechanicalArmH.point_code}未在点位表维护对应的点位"); + return false; + } + + List wmsCarryHs = _repository.AsSugarClient().Queryable().Where(r => r.location_id == startLocation.id).ToList(); + if (wmsCarryHs.Count == 0) + { + LoggerFloor2RackDelivery.LogError($"【送空托到上升降区】 起点{startLocation.id} {startLocation.location_code}上找不到料架"); + return false; + } + + if (wmsCarryHs.Count > 1) + { + LoggerFloor2RackDelivery.LogError($"【送空托到上升降区】 起点{startLocation.id} {startLocation.location_code}上存在多个料架"); + return false; + } + + // 空料架 + WmsCarryH targetCarry = wmsCarryHs[0]; + + WmsPointH startPoint = startPoints.First(); + WmsPointH endPoint = endPoints.First(); + + await _repository.AsSugarClient().Updateable().SetColumns(r => new BasLocation + { + is_lock = 1 + }).Where(r => r.id == startLocation.id).ExecuteCommandAsync(); + await _repository.AsSugarClient().Updateable().SetColumns(r => new WmsPointH + { + is_lock = 1 + }).Where(r => r.id == endPoint.id).ExecuteCommandAsync(); + + + LoggerFloor2RackDelivery.LogInformation($"【送空托到上升降区】 开始生成预任务 起点{startPoint.point_code} 终点{endPoint.point_code} 料架 {targetCarry.carry_code}"); + List points = new List(); + points.Add(startPoint); + points.Add(endPoint); + + bool isOk = await Floor2UpDownMachinecode_createPretask(points, targetCarry.id, targetCarry.carry_code); + if (!isOk) + { + throw new Exception("【送空托到上升降区】 未成功生成预任务"); + } + + return true; + } + } + + /// + /// 移走上升降区未生成预任务且满托的料架 + /// + /// + public async Task 移走上升降区未生成预任务且满托的料架() + { + using (var db = _repository.AsSugarClient().CopyNew()) + { + string[] configs_upMachine = new string[2] { "二楼上升降机机械臂左", "二楼上升降机机械臂右" }; + // 读取上升降机的左右料架区配置 + + List WmsMechanicalArmHs = _repository.AsSugarClient().Queryable().Where(r => r.stackingcount == r.maxnum && r.maxnum != 0 && !string.IsNullOrEmpty(r.rackcode) && r.iscreatepretask == 0 && configs_upMachine.Contains(r.name)).ToList(); + + foreach (WmsMechanicalArmH wmsMechanicalArmH in WmsMechanicalArmHs) + { + try + { + // 判断是否 上升降机请求取满托 + bool 上升降机请求取满托 = (bool)Floor2UpDownMachinecode_GetTag($"上升降机请求取满托{wmsMechanicalArmH.stackingposition}"); + if (!上升降机请求取满托) + { + LoggerFloor2RackDelivery.LogError($"【移走上升降区满托的料架】上升降机请求取满托{wmsMechanicalArmH.stackingposition}"); + return false; + } + + await _repository.AsSugarClient().Updateable().SetColumns(r => new WmsMechanicalArmH + { + iscreatepretask = 1 + }).Where(r => r.id == wmsMechanicalArmH.id).ExecuteCommandAsync(); + + List points = new List(); + + List startPoints = _repository.AsSugarClient().Queryable().Where(r => r.id == wmsMechanicalArmH.point_id).ToList(); + + if (startPoints.Count == 0) + { + LoggerFloor2RackDelivery.LogError($"【移走上升降区满托的料架】 起点{wmsMechanicalArmH.point_id} {wmsMechanicalArmH.point_code}未在点位表维护对应的点位"); + return false; + } + + WmsPointH startPoint = startPoints.First(); + points.Add(startPoint); + + // 找到未占用且未锁定的库位 + ISugarQueryable rackEndLocations = + _repository.AsSugarClient().Queryable() + .Where(r => r.wh_id == "33780009364245" && r.is_use == "0" && r.is_lock == 0).OrderBy(a => a.id).Take(1); + + if (rackEndLocations.Count() == 0) + { + LoggerFloor2RackDelivery.LogWarning($"【移走上升降区满托的料架】 暂存仓中没有可用的空库位 {rackEndLocations.ToSqlString()}"); + return false; + } + + BasLocation endLocation = rackEndLocations.First(); + + List endPoints = _repository.AsSugarClient().Queryable().Where(r => r.location_id == endLocation.id).ToList(); + + if (endPoints.Count == 0) + { + LoggerFloor2RackDelivery.LogError($"【移走上升降区满托的料架】 终点库位{endLocation.location_code}未在点位表维护对应的点位"); + return false; + } + WmsPointH endPoint = endPoints.First(); + points.Add(endPoint); + + + LoggerFloor2RackDelivery.LogInformation($"开始执行预任务生成: 料架区为{wmsMechanicalArmH.name}{wmsMechanicalArmH.stackingposition} 料架为{wmsMechanicalArmH.rackcode}"); + + bool isOk = await Floor2UpDownMachinecode_createPretask(points, wmsMechanicalArmH.rackid, wmsMechanicalArmH.rackcode); + if (!isOk) + { + throw new Exception("未成功生成预任务"); + } + } + catch (Exception ex) + { + LoggerFloor2RackDelivery.LogError(ex.ToString()); + LoggerFloor2RackDelivery.LogError(ex.StackTrace); + } + } + return true; + } + } + + // 料架配送 + private async void Floor2RackDelivery(object args) + { + var db = _repository.AsSugarClient().CopyNew(); + await s_taskExecuteRackDelivery.WaitAsync(); + try + { + + // 检查机械臂料架区信号(上升降机空托1送到) + await 检查机械臂料架区信号_上升降机空托1送到(); + + // 送空托到上升降区 + await 送空托到上升降区(); + + // 移走上升降区未生成预任务且满托的料架 + await 移走上升降区未生成预任务且满托的料架(); + + _ = _wareHouseService.GenTaskExecute(); + + } + catch (Exception ex) + { + LoggerFloor2RackDelivery.LogError(ex.ToString()); + LoggerFloor2RackDelivery.LogError(ex.StackTrace); + } + + s_taskExecuteRackDelivery.Release(); + } + + // 上下升降机生成预任务(补充料架、上升降机取货到料架、上升降机满托运走,下升降机拿货到输送线、下升降机空托运走) - private void Floor2UpDownMachinecode_createPretask() + private async Task Floor2UpDownMachinecode_createPretask(List points, string carry_id, string carry_code) { + //根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序) + List preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it => + { + WmsPointH? sPoint = it.FirstOrDefault(); + WmsPointH? ePoint = it.LastOrDefault(); + WmsPretaskH preTask = new() + { + org_id = "", + startlocation_id = sPoint?.location_id!, + startlocation_code = sPoint?.location_code!, + endlocation_id = ePoint?.location_id!, + endlocation_code = ePoint?.location_code!, + start_floor = sPoint?.floor.ToString(), + end_floor = ePoint?.floor.ToString(), + startpoint_id = sPoint?.id!, + startpoint_code = sPoint?.point_code!, + endpoint_id = ePoint?.id!, + endpoint_code = ePoint?.point_code!, + bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(), + status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID, + biz_type = "", + task_type = "", + carry_id = carry_id, + carry_code = carry_code, + area_id = sPoint?.area_id!, + area_code = it.Key, + require_id = "", + require_code = "", + create_id = "", + create_time = DateTime.Now + }; + + return preTask; + }).ToList(); + //更新页面 + //赋值签收状态 + + bool result = await _wareHouseService.GenPreTask(preTasks, null!); + if (result) + { + LoggerFloor2RackDelivery.LogInformation($"成功生成预任务:{preTasks.First().bill_code}"); + return true; + } + return false; } - // 上下升降机生成任务执行 - private void Floor2UpDownMachinecode_createDistask() + private object Floor2UpDownMachinecode_GetTag(string tag) { - + string key = "东面提升机输送线"; + string data = _redisData.GetHash(key, tag.ToString()).Result; + if (data == null) + { + LoggerFloor2UpDownMachine.LogError($@"{key} {tag} 未取到数值!"); + return ""; + } + JObject? res = JsonConvert.DeserializeObject(data); + switch (typeof(T).ToString()) + { + case "System.Boolean": + { + bool result = res != null && res["Value"] != null ? res.Value("Value") : false; + return result; + } + case "System.String": + { + string? result = res != null && res["Value"] != null ? res.Value("Value") : ""; + return result; + } + } + return "wrong type"; } - private Tuple Floor2UpDownMachinecode_GetTag(MechanicalArmConsts tag) + private async Task Floor2UpDownMachinecode_SetTag(string tag, string value) { - //string key = "东面提升机输送线"; - //string data = _redisData.GetHash(key, tag.ToString()).Result; - //JObject? res = JsonConvert.DeserializeObject(data); - //T result = res != null && res["Value"] != null ? res.Value("Value") : false; - //return new Tuple(result, res.Value("Value")); - return new Tuple(false, default(T)); + string DevName = "东面提升机输送线"; + Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) + { + ["DevName"] = DevName, + ["token"] = _eleCtlCfg.token, + ["TagName"] = tag, + ["Value"] = value, + }; + string result = await HttpClientHelper.GetRequestAsync(_eleCtlCfg.WriteTagUrl, dicCommand); + // TODO 测试 + //string result = "Ok"; + return result.Contains("Ok"); } /// @@ -604,12 +1081,6 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA } } - private void Floor2UpDownMachinecode_SetTag() - { - string key = "东面提升机输送线"; - - } - #endregion @@ -618,12 +1089,14 @@ where carry_code = '{coderesult}' and status = '{WmsWareHouseConst.TASK_BILL_STA Readtimer = new Timer(GetRedisData, null, TimeSpan.Zero, TimeSpan.FromSeconds(300)); CheckGettimer = new Timer(CheckGet, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); Scantimer = new Timer(ScanInStock, null, TimeSpan.Zero, TimeSpan.FromSeconds(60)); - SSXcodetimer= new Timer(SSXcode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); + SSXcodetimer = new Timer(SSXcode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); // 二楼上升降机 - Floor2UpMachinecodetimer = new Timer(Floor2UpMachinecode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); + Floor2UpMachinecodetimer = new Timer(Floor2UpMachinecode, null, TimeSpan.Zero, TimeSpan.FromSeconds(20)); // 二楼下升降机 - Floor2DownMachinecodetimer = new Timer(Floor2DownMachinecode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); + //Floor2DownMachinecodetimer = new Timer(Floor2DownMachinecode, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); + // 二楼料架配送 + Floor2RackDeliverytimer = new Timer(Floor2RackDelivery, null, TimeSpan.Zero, TimeSpan.FromSeconds(60)); return Task.CompletedTask; } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/MechanicalArmConsts.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/MechanicalArmConsts.cs index d74fe2d0..e10b9f08 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/MechanicalArmConsts.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/MechanicalArmConsts.cs @@ -68,6 +68,11 @@ namespace Tnb.WarehouseMgr.Entities.Consts /// public const string 下升降机当前码垛位 = "下升降机当前码垛位"; + /// + /// + /// + public const string 上升降机条码 = "上升降机条码"; + } } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsEmptyOutstockH.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsEmptyOutstockH.cs index 5f311737..d144b722 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsEmptyOutstockH.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsEmptyOutstockH.cs @@ -84,4 +84,15 @@ public partial class WmsEmptyOutstockH : BaseEntity /// public DateTime? timestamp { get; set; } + /// + /// 二楼机械臂剩余绑定料架数量 + /// + public int? remainbindracknum { get; set; } + + /// + /// 二楼机械臂料箱绑定完成 + /// + public string? bindrackcomplete { get; set; } + + } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmD.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmD.cs deleted file mode 100644 index 071db2f7..00000000 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmD.cs +++ /dev/null @@ -1,19 +0,0 @@ -using JNPF.Common.Contracts; -using JNPF.Common.Security; -using SqlSugar; - -namespace Tnb.WarehouseMgr.Entities; - -/// -/// 机械臂主表 -/// -[SugarTable("wms_mechanicalArm_d")] -public partial class WmsMechanicalArmD : BaseEntity -{ - public WmsMechanicalArmD() - { - id = SnowflakeIdHelper.NextId(); - } - - -} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmH.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmH.cs index 8b52523e..157c4d33 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmH.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsMechanicalArmH.cs @@ -7,11 +7,81 @@ namespace Tnb.WarehouseMgr.Entities; /// /// 机械臂主表 /// -[SugarTable("wms_mechanicalArm_h")] +[SugarTable("wms_mechanicalarm_h")] public partial class WmsMechanicalArmH : BaseEntity { public WmsMechanicalArmH() { id = SnowflakeIdHelper.NextId(); } + + /// + /// 说明 + /// + public string? name { get; set; } + + /// + /// 码垛位 + /// + public int? stackingposition { get; set; } + + /// + /// 码垛计数 + /// + public int? stackingcount { get; set; } + + /// + /// 料架上的条码 + /// + public string? barcodes { get; set; } + + /// + /// 料架最大盛放数量 + /// + public int? maxracknum { get; set; } + + /// + /// 出库单 + /// + public string? outbill { get; set; } + + /// + /// 满托数量 + /// + public int? maxnum { get; set; } + + /// + /// 是否生成预任务 + /// + public int? iscreatepretask { get; set; } + + /// + /// 料架id + /// + public string? rackid { get; set; } + + /// + /// 料架编号 + /// + public string? rackcode { get; set; } + + /// + /// 点位id + /// + public string? point_id { get; set; } + + /// + /// 点位编号 + /// + public string? point_code { get; set; } + + /// + /// 取放货确认 + /// + public int? agvconfirm { get; set; } + + /// + /// 取放货确认 + /// + public int? mechanicalconfirm { get; set; } } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWareHouseService.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWareHouseService.cs index 56c470ed..77886b53 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWareHouseService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWareHouseService.cs @@ -77,5 +77,10 @@ namespace Tnb.WarehouseMgr.Interfaces Task SsxControl(WmsDistaskH disTask, string action); Func AddUnExecuteTask { get; set; } Task Check(string code, string action); + /// + /// // 二楼机械臂 + /// + /// + Task Floor2MechanicalComplete(WmsDistaskH disTask, string action); } } diff --git a/WarehouseMgr/Tnb.WarehouseMgr/DeviceProviderService.cs b/WarehouseMgr/Tnb.WarehouseMgr/DeviceProviderService.cs index 0cdb68e1..45d2e74d 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/DeviceProviderService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/DeviceProviderService.cs @@ -486,7 +486,7 @@ namespace Tnb.WarehouseMgr } else { - Logger.Information($"【TaskCallback】sourceName不符合条件 {input.sourceName}"); + //Logger.Information($"【TaskCallback】电梯sourceName不符合条件 {input.sourceName}"); } @@ -505,6 +505,8 @@ namespace Tnb.WarehouseMgr else { await _wareHouseService.SsxControl(disTask, "LOAD"); + // 二楼机械臂 + await _wareHouseService.Floor2MechanicalComplete(disTask, "LOAD"); } } else if (input.action == "UNLOAD") @@ -517,6 +519,8 @@ namespace Tnb.WarehouseMgr Logger.Information($"taskCompleUpInput json parameter:{JsonConvert.SerializeObject(taskCompleUpInput)}"); await _wareHouseService.TaskComplate(taskCompleUpInput); await _wareHouseService.SsxControl(disTask, "UNLOAD"); + // 二楼机械臂 + await _wareHouseService.Floor2MechanicalComplete(disTask, "UNLOAD"); } } catch (Exception ex) diff --git a/WarehouseMgr/Tnb.WarehouseMgr/ElevatorControlService.cs b/WarehouseMgr/Tnb.WarehouseMgr/ElevatorControlService.cs index 7ec321ec..b337e7c3 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/ElevatorControlService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/ElevatorControlService.cs @@ -201,6 +201,12 @@ namespace Tnb.WarehouseMgr var eleStatusMap = await RedisHelper.HGetAllAsync(devName); try { + (int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) = await GetElevatorStatus(devName, CancellationToken.None);//elevator.elevator_code + Logger.Information($"【UnloadConfirm】 电梯当前状态->系统状态:{sysStatus.ToEnum()},运行状态:{runStatus},门状态:{doorStatus},Agv状态:{agvStatus},当前楼层:{floorNo}"); + //判断Agv电梯是否进入状态 + if (agvStatus != (int)EnumAgvStatus.AGV运行状态) + _ = await WriteTagAsync(devName, ElevatorConsts.AGVControl, 1); + Logger.Information($"【SendOpenCloseCmd】 向系统发送开关门指令 {_elevatorCtlCfg.WriteTagUrl} {JsonConvert.SerializeObject(dicCommand)}"); var res = await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); Logger.Information($"【SendOpenCloseCmd】 向系统发送开关门指令 结果:{res}"); diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs index 52cd40d2..b4d59a77 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs @@ -434,6 +434,70 @@ namespace Tnb.WarehouseMgr } + /// + /// // 二楼机械臂 + /// + /// + public async Task Floor2MechanicalComplete(WmsDistaskH disTask, string action) + { + if (disTask.area_code == "E") + { + Logger.Information($"【二楼机械臂Floor2MechanicalComplete】收到到货完成信号 传入参数: {disTask.bill_code} {action}"); + SqlSugarClient db = _db.CopyNew(); + + if (action == "UNLOAD") + { + ISugarQueryable WmsMechanicalArmHs = db.Queryable().Where(r => r.point_code == disTask.endpoint_code); + if (WmsMechanicalArmHs.Count() == 0) + { + Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行终点{disTask.endpoint_code} 与料架区的点位不匹配"); + return false; + } + WmsMechanicalArmH target = WmsMechanicalArmHs.First(); + + // 回写料架和AGV确认 + await db.Updateable().SetColumns(r => new WmsMechanicalArmH + { + agvconfirm = 1, + rackid = disTask.carry_id, + rackcode = disTask.carry_code + }).Where(r => r.id == target.id).ExecuteCommandAsync(); + Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV已到货"); + } + else + { + ISugarQueryable WmsMechanicalArmHs = db.Queryable().Where(r => r.point_code == disTask.startpoint_code); + if (WmsMechanicalArmHs.Count() == 0) + { + Logger.Information($"【二楼机械臂Floor2MechanicalComplete】 任务执行起点{disTask.endpoint_code} 与料架区的点位不匹配"); + return false; + } + WmsMechanicalArmH target = WmsMechanicalArmHs.First(); + + //回写出库单状态 + await db.Updateable().SetColumns(r=>new WmsEmptyOutstockH + { + bindrackcomplete = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID + }).Where(r => r.bill_code == target.outbill).ExecuteCommandAsync(); + + // 重置料架区 + await db.Updateable().SetColumns(r => new WmsMechanicalArmH + { + stackingcount = 0, + barcodes = "", + outbill = "", + maxnum = 0, + iscreatepretask = 0, + rackcode = "", + rackid = "", + agvconfirm = 0, + mechanicalconfirm = 0 + }).Where(r => r.id == target.id).ExecuteCommandAsync(); + Logger.Information($"【二楼机械臂Floor2MechanicalComplete】{disTask.bill_code} AGV已到货"); + } + } + return true; + } /// /// 生成任务执行 @@ -1223,7 +1287,7 @@ namespace Tnb.WarehouseMgr { tuple = await _elevatorControlService.GetElevatorStatus(devName, tags, CancellationToken.None); await Task.Delay(1000); - } while (tuple.sysStatus != 3 && tuple.runStatus != 0); + } while (tuple.sysStatus != 3 || tuple.runStatus != 0); Logger.Information($"sysStatus:{tuple.sysStatus},runStatus:{tuple.runStatus},floorNo:{tuple.floorNo},disTask.end_floor={disTask.end_floor}"); @@ -1448,6 +1512,9 @@ namespace Tnb.WarehouseMgr locIts.Add(loc); } + + Logger.Information($@"TaskComplate 更新carryIts: {JsonConvert.SerializeObject(carryIts)}"); + Logger.Information($@"TaskComplate 更新carryCodeIts: {JsonConvert.SerializeObject(carryCodeIts)}"); _ = await _db.Updateable(carryIts).UpdateColumns(it => new { it.is_lock, it.location_id, it.location_code }).ExecuteCommandAsync(); //更新条码的库位和仓库信息 _ = await _db.Updateable(carryCodeIts).UpdateColumns(it => new { it.warehouse_id, it.location_id, it.location_code }).Where(it => multiList.Select(x => x.carry_id).Contains(it.carry_id)).ExecuteCommandAsync(); diff --git a/common/Tnb.Common/Utils/HttpClientHelper.cs b/common/Tnb.Common/Utils/HttpClientHelper.cs index 290e4b51..84f4536d 100644 --- a/common/Tnb.Common/Utils/HttpClientHelper.cs +++ b/common/Tnb.Common/Utils/HttpClientHelper.cs @@ -98,6 +98,7 @@ namespace Tnb.Common.Utils } return respJson; } + public static async Task GetRequestAsync(string url, Dictionary pars = null) { Log.Information($"开始请求 {url} 请求参数: {JsonConvert.SerializeObject(pars)}"); @@ -116,23 +117,26 @@ namespace Tnb.Common.Utils public static async Task GetAsync(string url, Dictionary headers = null, Dictionary pars = null) { - var reqUri = url; - if (pars?.Count > 0) + using (var client = new HttpClient()) { - reqUri = QueryHelpers.AddQueryString(url, pars); - //await Console.Out.WriteLineAsync(reqUri); - } - if (headers?.Count > 0) - { - foreach (var (k, v) in headers) + var reqUri = url; + if (pars?.Count > 0) { - HttpClient.DefaultRequestHeaders.Add(k, v); + reqUri = QueryHelpers.AddQueryString(url, pars); + //await Console.Out.WriteLineAsync(reqUri); } + if (headers?.Count > 0) + { + foreach (var (k, v) in headers) + { + client.DefaultRequestHeaders.Add(k, v); + } + } + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + var respBody = await client.GetAsync(reqUri); + var result = await respBody.Content.ReadAsStringAsync(); + return result; } - HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - var respBody = await HttpClient.GetAsync(reqUri); - var result = await respBody.Content.ReadAsStringAsync(); - return result; }