using Newtonsoft.Json; using ServiceCenter.Extensions; using ServiceCenter.Logs; using ServiceCenter.Redis; using ServiceCenter.SqlSugars; using SqlSugar; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using WCS.Core; using WCS.Entity; using WCS.WorkEngineering.Extensions; using WCS.WorkEngineering.Protocol.BCR; using WCS.WorkEngineering.Protocol.SRM; using WCS.WorkEngineering.Protocol.Station; using WCS.WorkEngineering.WebApi.Controllers; using WCS.WorkEngineering.Worlds; using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags; namespace WCS.WorkEngineering.Systems { /// /// 库尾入库 /// [BelongTo(typeof(MainWorld))] [Description("库尾入库")] public class 库尾入库 : DeviceSystem> { protected override bool ParallelDo => false; protected override bool SaveLogsToFile => true; private List devs = new List(); private List srms = new List(); public 库尾入库() { devs = Device.All.Where(v => v.HasFlag(DeviceFlags.入库)).Select(v => new Station(v, this.World)).ToList(); srms = Device.All.Where(v => v.HasProtocol(typeof(ISRM520))).Select(v => new SRM(v, this.World)).ToList(); } public override void Do(Device obj) { var key = $"WCS:Lock:出入库管制SRM"; try { if (RedisHub.Default.Get(key) != null) { throw new KnownException($"[{obj.Entity.Code}]--触发并发管控", LogLevelEnum.High); } RedisHub.Default.Set(key, obj.Entity.Code); obj.入库站点是否被禁止(); obj.入库站点是否满足执行条件(); if (obj.Data2.Request != 1.ToShort()) throw new KnownException("无请求", LogLevelEnum.Mid); if (!obj.Data3.Status.HasFlag(StationStatus.OT_Status)) throw new KnownException("无光电", LogLevelEnum.Mid); //开始读取条码 var bcr = obj.Data5.GetBCRCode(); World.Log($"扫码记录:条码:{bcr}"); WCS_TaskInfo task = null; List inlist = new List(); SqlSugarHelper.Do(_db => { var db = _db.Default; //找到对应任务 var taskInfo = db.Queryable().First(x => x.BarCode == bcr && x.Type == TaskType.EnterDepot && x.AddrFrom == "8277"); //未找到对应任务 if (taskInfo == null) { //向WMS申请入库任务 var res = WmsApi.I_WCS_GetInTask(bcr, obj.Entity.Code); if (res.ResCode != WebApi.Models.WMS.Response.ResponseStatusCodeEnum.Sucess) { if (res == null) throw new Exception($"向WMS申请入库任务失败" + res.ResMsg); } return; } //任务生成 if (taskInfo.Status == Entity.TaskStatus.WaitingToExecute) { // 开始获取堆垛机与可用站台信息 var res = WmsApi.GetTunnelPriorityList(taskInfo.ID); if (res == null) throw new Exception("未返回巷道"); var tunnelNo = res.ResData.Split(",") .Select(v => "SRM" + v) .ToList(); if (taskInfo.Floor == 10 && tunnelNo.Contains("SRM5")) { // 优化:直接在查询中完成条件判断,避免实例化不必要的对象 var srm5 = Device.All.FirstOrDefault(x => x.Code == "SRM5" && new Device(x, World).Data.AutoStatus == SrmAutoStatus.Automatic); if (srm5 != null) { // 如果任务在10楼且SRM5处于自动模式,则只保留SRM5 tunnelNo = new List { "SRM5" }; } } SRM srm = null; List stations = new List(); //成品库背面堆垛机取货点 stations = devs.Where(v => v.Entity.Code is "8271" or "8272" or "8273" or "8274" or "8275").ToList(); //筛选出可用站台c stations = stations.Where(v => v.Data3.Status.HasFlag(StationStatus.Auto))// v.Data.VoucherNo == v.Data2.VoucherNo && .Where(v => !v.Data3.Status.HasFlag(StationStatus.PH_Status) && !v.Data3.Status.HasFlag(StationStatus.OT_Status)) .Where(v => !v.Data3.Status.HasFlag(StationStatus.Run)).ToList(); // 筛选出可用站台 if (stations == null) { throw new KnownException($"{obj.Entity.Code}无可用放货站台", LogLevelEnum.High); } //World.Log($"可用站台信息[{count}]" + JsonConvert.SerializeObject(stations)); var srms = stations.Select(v => v.Entity.Targets).SelectMany(v => v).Where(v => v.IsTunnel()) //下一个地址是巷道的 .Select(v => v.Sources).SelectMany(v => v).Where(v => v.HasProtocol(typeof(ISRM520))) //筛选出堆垛机 .Select(v => new SRM(v, this.World)).ToList(); foreach (var device in srms) { try { var canusem = device.Data2.AutoStatus; inlist.Add(device); } catch (Exception) { continue; } } var tun = res.ResData.Split(","); var tasktunnelNo = db.Queryable().Where(p => tun.Contains(p.Tunnel) && p.AddrFrom == "8277").ToList().Select(p => p.Tunnel).Distinct().ToList(); if (tasktunnelNo.Any()) { var tunnelNo1 = res.ResData.Split(",").Except(tasktunnelNo).ToList(); World.Log($"Tunnel:taskid{obj.Data.TaskNumber}-" + $"tasktunnelNo{JsonConvert.SerializeObject(tasktunnelNo)}-" + $"tunnelNo1{JsonConvert.SerializeObject(tunnelNo1)}"); tunnelNo = tunnelNo1.Select(v => "SRM" + v).ToList(); } else { World.Log($"Tunnel:taskid{obj.Data.TaskNumber}-notunel-" + JsonConvert.SerializeObject(tunnelNo)); } //可用堆垛机 srm = inlist.Where(v => v != null && !v.Data2.Status.HasFlag(SrmStatus.Alarm) && v.Data2.AutoStatus == SrmAutoStatus.Automatic) //筛选出可用堆垛机 .Where(v => tunnelNo.Contains(v.Entity.Code)) //筛选出巷道优先级最高的堆垛机 .MinBy(v => tunnelNo.IndexOf(v.Entity.Code)); //按照巷道优先级排序 if (srm == null) { throw new Exception($"任务{taskInfo.ID}无可用堆垛机"); } inlist = null; //筛选出堆垛机的取货站台 var nextPos = stations.FirstOrDefault(v => v.Entity.Sources.Where(t => t.IsTunnel()).Select(t => t.Sources).SelectMany(v => v) //获取所有巷道 .Where(t => t.HasProtocol(typeof(ISRM520)))//筛选出堆垛机 .SelectMany(v => v.Sources).Any(t => t.Code == srm.Entity.Parent.Code)); if (nextPos == null) { throw new KnownException($"{obj.Entity.Code}没有可用的放货站台", LogLevelEnum.High); } var dev = devs.Find(v => v.Entity.Code == nextPos.Entity.Code); var nextCode = nextPos.Entity.Code; var taskout = db.Queryable().First(v => v.AddrTo == "8278" && v.Status > Entity.TaskStatus.WaitingToExecute && v.Status < Entity.TaskStatus.Finish && nextPos.Entity.Code == v.SrmStation && v.AddrNext == null); if (taskout != null) throw new KnownException($"{obj.Entity.Code}存在正在出库任务{taskout.ID},禁止入库!", LogLevelEnum.High); if (dev == null) throw new Exception($"找不到放货点"); //放货点有光电或任务号不下发任务 //if (obj.Data3.Status.HasFlag(StationStatus.OT_Status) || obj.Data2.TaskNumber > 0 || obj.Data3.Status.HasFlag(StationStatus.PH_Status)) //{ // throw new KnownException($"{obj.Entity.Code}有任务或光电", LogLevelEnum.High); //} //堆垛机的可用取货站台 var tasklist = db.Queryable().Where(x => x.Type == TaskType.OutDepot && x.AddrTo == "8278" && x.Device == srm.Entity.Code && x.Status >= Entity.TaskStatus.StackerExecution && x.Status< Entity.TaskStatus.Finish && x.AddrNext == null).ToList(); if (tasklist.Any()) { throw new KnownException($"[{srm.Entity.Code.GetLastDigit().ToString()}]巷道存在库尾执行的出库任务", LogLevelEnum.High); } taskInfo.SrmStation = nextPos.Entity.Code; taskInfo.AddrNext = nextPos.Entity.Sources.First().Code; taskInfo.Device = srm.Entity.Code; taskInfo.Tunnel = taskInfo.Device.GetLastDigit().ToString(); taskInfo.Status = Entity.TaskStatus.ConveyorExecution; taskInfo.EditWho = "WCS"; taskInfo.EditTime = DateTime.Now; db.Updateable(taskInfo).ExecuteCommand(); taskInfo.AddWCS_TASK_DTL(_db, obj.Entity.Code, taskInfo.AddrNext, $"完成巷道分配,分配至{taskInfo.Device}"); //taskInfo.updateRedisHash(); task = taskInfo; if (task == null) throw new KnownException($"[{obj.Entity.Code}]等待入库任务为空", LogLevelEnum.Mid); } }); if (task == null) return; obj.Data.TaskNumber = task.ID; obj.Data.GoodsStart = obj.Entity.Code.ToShort(); obj.Data.GoodsEnd = task.SrmStation.ToShort(); obj.Data.VoucherNo++; World.Log($"执行记录:taskid{obj.Data.TaskNumber}-" + $"GoodsStart{obj.Data.GoodsStart}-" + $"GoodsEnd{obj.Data.GoodsEnd}-" + $"VoucherNo{obj.Data.VoucherNo}"); } finally { RedisHub.Default.Del(key); } } public override bool Select(Device dev) { return dev.Code == "8277"; } } }