Explorar el Código

优化出货策略

林豪 左 hace 3 años
padre
commit
fee070e482

+ 15 - 0
Projects/永冠OPP/WCS.Service/DeviceExtentions.cs

@@ -50,6 +50,21 @@ namespace WCS.Service
             return q.FirstOrDefault();
         }
 
+        /// <summary>
+        /// 获取从source到endaddr的路径中的第一个位置
+        /// </summary>
+        /// <param name="source">起始位置</param>
+        /// <param name="endAddr">目标位置</param>
+        /// <param name="condition">路径筛选条件</param>
+        /// <returns></returns>
+        public static WCS_DEVICE GetPath(this WCS_DEVICE source, string endAddr)
+        {
+            var q = source.PATHS.Where(v => v.START == source && v.END.CODE.Contains(endAddr.ToUpper()))
+                .Select(v => v.PATH.Split('-').Select(v => Device.Find(v)).ToList());
+
+            return q.FirstOrDefault().FirstOrDefault();
+        }
+
         public static WCS_DEVICE GetNext(this WCS_DEVICE source, string endAddr)
         {
             return source.GetNext(endAddr, null);

+ 14 - 0
Projects/永冠OPP/WCS.Service/Exception.cs

@@ -15,4 +15,18 @@ namespace WCS.Service
         {
         }
     }
+
+    /// <summary>
+    /// 执行记录
+    /// </summary>
+    public class DoException : Exception
+    {
+        /// <summary>
+        /// 警告异常
+        /// </summary>
+        /// <param name="message"></param>
+        public DoException(string message) : base(message)
+        {
+        }
+    }
 }

+ 159 - 33
Projects/永冠OPP/WCS.Service/Extensions/DeviceExtension.cs

@@ -30,6 +30,10 @@ namespace WCS.Service.Extensions
         {
         }
 
+        /// <summary>
+        /// 执行输送机设备组任务 单例锁
+        /// </summary>
+        /// <param name="act"></param>
         public void EX(Action<StationDeviceGroup> act)
         {
             try
@@ -38,9 +42,15 @@ namespace WCS.Service.Extensions
                 AddExDevice(Entity.CODE);
                 act(this);
             }
+            catch (DoException ex)
+            {
+                InfoLog.INFO_INFO($"[{Entity.CODE}]--{ex.Message}");
+            }
             catch (WarnException ex)
             {
+                Ltc.Log(ex.GetBaseException().Message);
                 InfoLog.INFO_WARN($"[{Entity.CODE}]--{ex.Message}");
+                LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());
             }
             catch (Exception ex)
             {
@@ -235,6 +245,10 @@ namespace WCS.Service.Extensions
             return false;
         }
 
+        /// <summary>
+        /// 执行输送机任务 单例锁
+        /// </summary>
+        /// <param name="act"></param>
         public void EX(Action<StationDevice> act)
         {
             try
@@ -243,9 +257,15 @@ namespace WCS.Service.Extensions
                 AddExDevice(Entity.CODE);
                 act(this);
             }
+            catch (DoException ex)
+            {
+                InfoLog.INFO_INFO($"[{Entity.CODE}]--{ex.Message}");
+            }
             catch (WarnException ex)
             {
+                Ltc.Log(ex.GetBaseException().Message);
                 InfoLog.INFO_WARN($"[{Entity.CODE}]--{ex.Message}");
+                LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());
             }
             catch (Exception ex)
             {
@@ -324,6 +344,40 @@ namespace WCS.Service.Extensions
             }
         }
 
+        /// <summary>
+        /// 执行RGV任务 单例锁
+        /// </summary>
+        /// <param name="act"></param>
+        public void EX(Action<RGVDevice> act)
+        {
+            try
+            {
+                if (ExDevice.Any(v => v == Entity.CODE)) return;
+                AddExDevice(Entity.CODE);
+                act(this);
+            }
+            catch (DoException ex)
+            {
+                InfoLog.INFO_INFO($"[{Entity.CODE}]--{ex.Message}");
+            }
+            catch (WarnException ex)
+            {
+                Ltc.Log(ex.GetBaseException().Message);
+                InfoLog.INFO_WARN($"[{Entity.CODE}]--{ex.Message}");
+                LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());
+            }
+            catch (Exception ex)
+            {
+                Ltc.Log(ex.GetBaseException().Message);
+                InfoLog.INFO_ERROR($"[{Entity.CODE}]--{ex.Message}--{ex.StackTrace}");
+                LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());
+            }
+            finally
+            {
+                RemoveExDevice(Entity.CODE);
+            }
+        }
+
         /// <summary>
         /// 前一个RGV
         /// </summary>
@@ -497,7 +551,7 @@ namespace WCS.Service.Extensions
                     var ELine = i == 0 ? Data.ELine_1.ToString() : Data.ELine_2.ToString();
                     task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);
                     if (task.STATUS != TaskStatus.堆垛机执行)
-                        throw new Exception(LogHelper.SpliceLogMessage($"堆垛机已完成任务[{task.ID}]但WCS状态为[{task.STATUS}],应为[{TaskStatus.堆垛机执行}]", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                        throw new Exception($"堆垛机已完成任务[{task.ID}]但WCS状态为[{task.STATUS}],应为[{TaskStatus.堆垛机执行}]");
 
                     if (task.TYPE == TaskType.入库)
                     {
@@ -538,34 +592,26 @@ namespace WCS.Service.Extensions
         }
 
         /// <summary>
-        /// 执行出库任务
+        /// 执行堆垛机任务 单例锁
         /// </summary>
         /// <param name="act"></param>
-        public void EXOutStock(Action<SRMDevice> act)
+        public void EX(Action<SRMDevice> act)
         {
             try
             {
                 if (ExDevice.Any(v => v == Entity.CODE)) return;
-                if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4")
-                {
-                    AddExDevice("SRM3");
-                    AddExDevice("SRM4");
-                }
-                if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6")
-                {
-                    AddExDevice("SRM5");
-                    AddExDevice("SRM6");
-                }
-                if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8")
-                {
-                    AddExDevice("SRM7");
-                    AddExDevice("SRM8");
-                }
+                AddExDevice(Entity.CODE);
                 act(this);
             }
+            catch (DoException ex)
+            {
+                InfoLog.INFO_INFO($"[{Entity.CODE}]--{ex.Message}");
+            }
             catch (WarnException ex)
             {
+                Ltc.Log(ex.GetBaseException().Message);
                 InfoLog.INFO_WARN($"[{Entity.CODE}]--{ex.Message}");
+                LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());
             }
             catch (Exception ex)
             {
@@ -575,23 +621,103 @@ namespace WCS.Service.Extensions
             }
             finally
             {
-                if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4")
-                {
-                    RemoveExDevice("SRM3");
-                    RemoveExDevice("SRM4");
-                }
-                if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6")
-                {
-                    RemoveExDevice("SRM5");
-                    RemoveExDevice("SRM6");
-                }
-                if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8")
-                {
-                    RemoveExDevice("SRM7");
-                    RemoveExDevice("SRM8");
-                }
+                RemoveExDevice(Entity.CODE);
             }
         }
+
+        /// <summary>
+        /// 执行出库任务 出库单例锁
+        /// </summary>
+        /// <param name="act"></param>
+        public void EXOutStock(Action<SRMDevice> act)
+        {
+            try
+            {
+                if (ExDevice.Any(v => v == Entity.CODE)) return;
+                if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4") AddExDevice("SRM3-SRM4-Out");
+                if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6") AddExDevice("SRM5-SRM6-Out");
+                if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8") AddExDevice("SRM7-SRM8-Out");
+                act(this);
+            }
+            finally
+            {
+                if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4") AddExDevice("SRM3-SRM4-Out");
+                if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6") AddExDevice("SRM5-SRM6-Out");
+                if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8") AddExDevice("SRM7-SRM8-Out");
+            }
+        }
+
+        /// <summary>
+        /// 一工位写任务
+        /// </summary>
+        /// <param name="task"></param>
+        public void WriteTask1(Task task)
+        {
+            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]1工位-开始:[{Data.TaskID_1}][{Data.SLine_1}][{Data.SCol_1}][{Data.SLayer_1}][{Data.ELine_1}][{Data.VoucherNo_1}]");
+            Data.TaskID_1 = task.ID;
+            Data.SLine_1 = task.Line;
+            Data.SCol_1 = task.Col;
+            Data.SLayer_1 = task.Layer;
+            Data.ELine_1 = task.SRMSTATION.ToShort();
+            Data.ECol_1 = 0;
+            Data.ELayer_1 = 0;
+            Data.VoucherNo_1++;
+            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]1工位-结束:[{Data.TaskID_1}][{Data.SLine_1}][{Data.SCol_1}][{Data.SLayer_1}][{Data.ELine_1}][{Data.VoucherNo_1}]");
+        }
+
+        /// <summary>
+        /// 二工位写任务
+        /// </summary>
+        /// <param name="task"></param>
+        public void WriteTask2(Task task)
+        {
+            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]2工位-开始:[{Data.TaskID_2}][{Data.SLine_2}][{Data.SCol_2}][{Data.SLayer_2}][{Data.ELine_2}][{Data.VoucherNo_2}]");
+            Data.TaskID_2 = task.ID;
+            Data.SLine_2 = task.Line;
+            Data.SCol_2 = task.Col;
+            Data.SLayer_2 = task.Layer;
+            Data.ELine_2 = task.SRMSTATION.ToShort();
+            Data.ECol_2 = 0;
+            Data.ELayer_2 = 0;
+            Data.VoucherNo_2++;
+            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]2工位-结束:[{Data.TaskID_2}][{Data.SLine_2}][{Data.SCol_2}][{Data.SLayer_2}][{Data.ELine_2}][{Data.VoucherNo_2}]");
+        }
+
+        /// <summary>
+        /// 获取任务对应的货叉
+        /// </summary>
+        /// <param name="task">任务信息</param>
+        /// <param name="index">任务在下发任务集合中的索引</param>
+        /// <returns></returns>
+        public SrmFork GetFork(Task task, int index)
+        {
+            short maxCol = (short)(Entity.CODE == "SRM1" ? 112 : 102);
+            short min = 1;
+            if (index > 1) throw new WarnException("一次最多下发两个任务");
+            //如果索引是1,直接返回货叉2
+            if (index == 1) return SrmFork.货叉2;
+
+            //判断任务列是多少
+            return task.Col switch
+            {
+                102 => Entity.CODE switch
+                {
+                    "SRM1" => SrmFork.货叉1,
+                    _ => SrmFork.货叉2,
+                },
+                112 => SrmFork.货叉2,
+                _ => SrmFork.货叉1,
+            };
+        }
+    }
+
+    /// <summary>
+    /// 堆垛机货叉/工位
+    /// </summary>
+    public enum SrmFork
+    {
+        货叉1 = 0,
+        货叉2 = 1,
     }
 
     /// <summary>

+ 41 - 4
Projects/永冠OPP/WCS.Service/Extensions/TaskExtension.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using WCS.Core;
 using WCS.Entity;
 
 namespace WCS.Service.Extensions
@@ -10,7 +11,7 @@ namespace WCS.Service.Extensions
     /// </summary>
     public static class TaskExtension
     {
-        public static T Create<T>(WCS_TASK source)
+        public static T Create<T>(this WCS_TASK source)
         {
             return (T)Activator.CreateInstance(typeof(T), source);
         }
@@ -22,15 +23,49 @@ namespace WCS.Service.Extensions
         /// <returns></returns>
         public static Task[] GetOutTask(this List<WCS_TASK> tasks)
         {
-            return tasks.Select(v => Create<Task>(v))
+            return tasks.Select(v => v.Create<Task>())
                                .OrderBy(v => v.Line)
                                .ThenBy(v => v.Layer)
                                .ThenBy(v => v.Col)
                                .Take(2)
-                               .DistinctBy(v => v.Col).DistinctBy(v => v.SRMSTATION).ToArray();
+                               .DistinctBy(v => v.Col).OrderBy(v => v.Col).ToArray();
+        }
+
+        /// <summary>
+        /// 获取出库任务的站台号及下一个地址
+        /// </summary>
+        /// <param name="task">任务</param>
+        /// <param name="srmFork">货叉</param>
+        public static void GetSrmStationAndaddNext(this WCS_TASK task, SrmFork srmFork)
+        {
+            //取任务巷道到达目标地址的下一个地址,即任务堆垛机的站台对应的设备组
+            var stations = Device.Where(v => v.DEVICEGROUP.Any(p => p.MEMBER == Device.Find(task.TUNNEL).GetPath(task.ADDRTO.Replace("G", ""))))
+                                 .Select(v => v.Create<StationDeviceGroup>())
+                                 .FirstOrDefault().Items
+                                 .OrderByDescending(v => v.Entity.CODE)
+                                 .ToArray();
+            //一工位放较大的站台号
+            switch (srmFork)
+            {
+                case SrmFork.货叉1:
+                    task.SRMSTATION = stations[0].Entity.CODE;
+                    task.ADDRNEXT = stations[0].Entity.GetPath(task.ADDRTO).CODE;
+                    break;
+
+                case SrmFork.货叉2:
+                    task.SRMSTATION = stations[1].Entity.CODE;
+                    task.ADDRNEXT = stations[1].Entity.GetPath(task.ADDRTO).CODE;
+                    break;
+            }
         }
     }
 
+    public enum SrmIndex
+    {
+        工位一 = 0,
+        工位二 = 1,
+    }
+
     public class Task : WCS_TASK
     {
         /// <summary>
@@ -52,7 +87,9 @@ namespace WCS.Service.Extensions
         {
             var addrFrom = task.ADDRFROM.Split("-");
             ADDRTO = task.ADDRTO;
-            SRMSTATION = task.SRMSTATION;
+            TUNNEL = task.TUNNEL;
+            DEVICE = task.DEVICE;
+
             ID = task.ID;
             Line = addrFrom[0].ToShort();
             Col = addrFrom[1].ToShort();

+ 2 - 2
Projects/永冠OPP/WCS.Service/Log/InfoLog.cs

@@ -57,7 +57,7 @@ namespace WCS.Service.Log
         }
 
         /// <summary>
-        /// 系统执行信息
+        /// 系统执行信息  基本检查条件不满足时记录
         /// </summary>
         /// <param name="msg"></param>
         public static void INFO_INFO(string msg)
@@ -75,7 +75,7 @@ namespace WCS.Service.Log
         }
 
         /// <summary>
-        /// 系统执行警告
+        /// 系统执行警告 所有一直错误都归类为警告
         /// </summary>
         /// <param name="msg"></param>
         public static void INFO_WARN(string msg)

+ 14 - 16
Projects/永冠OPP/WCS.Service/WebApi/APICaller.cs

@@ -1,27 +1,26 @@
-using FreeRedis;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
-using System.Linq;
 using System.Net;
 using System.Text;
 using System.Threading.Tasks;
-using WCS.Core;
 
 namespace WCS.Service
 {
     public class APICaller
     {
-        class Result
+        private class Result
         {
             public bool Succsess;
             public string Exception;
             public object Data;
-        } 
-        static ConcurrentDictionary<string, Result> Results = new ConcurrentDictionary<string, Result>();
+        }
+
+        private static ConcurrentDictionary<string, Result> Results = new ConcurrentDictionary<string, Result>();
+
         public static T CallApi2<T>(string url, object parameter, string type = "POST")
         {
             var content = JsonConvert.SerializeObject(parameter);
@@ -30,14 +29,14 @@ namespace WCS.Service
         }
 
         public static T CallApi<T>(string url, object parameter, string type = "Post")
-        { 
-            var content = JsonConvert.SerializeObject(parameter) ;
+        {
+            var content = JsonConvert.SerializeObject(parameter);
             var key = url + content;
             if (Results.ContainsKey(key))
             {
                 var res = Results[key];
                 if (res == null)
-                    throw new Exception("接口调用中");
+                    throw new WarnException("接口调用中");
                 try
                 {
                     if (!res.Succsess)
@@ -77,20 +76,19 @@ namespace WCS.Service
                 }
                 else
                 {
-                    throw new Exception("接口调用中");
+                    throw new WarnException("接口调用中");
                 }
-
             }
         }
 
-        static string HttpApi(string url, string jsonstr, string type)
+        private static string HttpApi(string url, string jsonstr, string type)
         {
             var sw = new Stopwatch();
             sw.Start();
             Encoding encoding = Encoding.UTF8;
             HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);//webrequest请求api地址
             request.Timeout = 60000;//连接超时
-            request.ReadWriteTimeout = 3600000;//读写超时 
+            request.ReadWriteTimeout = 3600000;//读写超时
             request.Accept = "text/html,application/xhtml+xml,*/*";
             request.ContentType = "application/json";
             request.Method = type.ToUpper().ToString();//get或者post
@@ -100,7 +98,7 @@ namespace WCS.Service
             HttpWebResponse response = (HttpWebResponse)request.GetResponse();
             using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
             {
-                var res= reader.ReadToEnd();
+                var res = reader.ReadToEnd();
                 sw.Stop();
                 if (sw.ElapsedMilliseconds > 500)
                     Console.WriteLine($"耗时:{sw.ElapsedMilliseconds},{url}");
@@ -108,4 +106,4 @@ namespace WCS.Service
             }
         }
     }
-}
+}

+ 26 - 28
Projects/永冠OPP/WCS.Service/WebApi/WCSApi.cs

@@ -3,11 +3,9 @@ using Microsoft.AspNetCore.Mvc;
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using WCS.Core;
 using WCS.Entity;
 using WCS.Entity.Protocol;
 using WCS.Service.Entity;
-using WCS.Service.Extensions;
 
 namespace WCS.Service.WebApi
 {
@@ -74,32 +72,32 @@ namespace WCS.Service.WebApi
                                 ADDRNEXT = obj.EndLocation
                             };
 
-                            //当前货物可以使用的放货点
-                            var deliveryPoints = Device.Find(task.DEVICE).Create<SRMDevice>().GetDeliveryPoint();
-                            //确定放货站台 通过设备组关联 此时一定是一组设备组
-                            //结果为堆垛机放货设备组
-                            var group = Device.Where(v => v.ROUTES.Any(p => p.NEXT.CODE == task.ADDRTO)).SelectMany(v => v.DEVICEGROUP).Select(v => v.MEMBER);
-                            //结果为当前堆垛机可用设备 此时会是两个单独的设备
-                            deliveryPoints = deliveryPoints.Where(v => group.Contains(v.Entity)).OrderByDescending(v => v.Entity.CODE).ToList();
-
-                            var addrTo = Device.Find(task.ADDRTO).Create<StationDeviceGroup>().Items.ToArray();
-
-                            //判断是否可以到达
-                            //确定当前工位的货物是一工位还是二工位
-                            if (obj.StartCol.ToShort().OddNumberOrEven())
-                            {
-                                //一工位 也是设备在堆垛机放货后的第一个地点
-                                task.SRMSTATION = deliveryPoints[0].Entity.CODE;
-                                if (deliveryPoints[0].Entity.PATHS.Any(v => v.END == addrTo[0].Entity)) task.ADDRTO = addrTo[0].Entity.CODE;
-                                else task.ADDRNEXT = addrTo[0].Entity.CODE;
-                            }
-                            else
-                            {
-                                //二工位
-                                task.SRMSTATION = deliveryPoints[1].Entity.CODE;
-                                if (deliveryPoints[1].Entity.PATHS.Any(v => v.END == addrTo[0].Entity)) task.ADDRTO = addrTo[0].Entity.CODE;
-                                else task.ADDRNEXT = addrTo[1].Entity.CODE;
-                            }
+                            ////当前货物可以使用的放货点
+                            //var deliveryPoints = Device.Find(task.DEVICE).Create<SRMDevice>().GetDeliveryPoint();
+                            ////确定放货站台 通过设备组关联 此时一定是一组设备组
+                            ////结果为堆垛机放货设备组
+                            //var group = Device.Where(v => v.ROUTES.Any(p => p.NEXT.CODE == task.ADDRTO)).SelectMany(v => v.DEVICEGROUP).Select(v => v.MEMBER);
+                            ////结果为当前堆垛机可用设备 此时会是两个单独的设备
+                            //deliveryPoints = deliveryPoints.Where(v => group.Contains(v.Entity)).OrderByDescending(v => v.Entity.CODE).ToList();
+
+                            //var addrTo = Device.Find(task.ADDRTO).Create<StationDeviceGroup>().Items.ToArray();
+
+                            ////判断是否可以到达
+                            ////确定当前工位的货物是一工位还是二工位
+                            //if (obj.StartCol.ToShort().OddNumberOrEven())
+                            //{
+                            //    //一工位 也是设备在堆垛机放货后的第一个地点
+                            //    task.SRMSTATION = deliveryPoints[0].Entity.CODE;
+                            //    if (deliveryPoints[0].Entity.PATHS.Any(v => v.END == addrTo[0].Entity)) task.ADDRTO = addrTo[0].Entity.CODE;
+                            //    else task.ADDRNEXT = addrTo[0].Entity.CODE;
+                            //}
+                            //else
+                            //{
+                            //    //二工位
+                            //    task.SRMSTATION = deliveryPoints[1].Entity.CODE;
+                            //    if (deliveryPoints[1].Entity.PATHS.Any(v => v.END == addrTo[0].Entity)) task.ADDRTO = addrTo[0].Entity.CODE;
+                            //    else task.ADDRNEXT = addrTo[1].Entity.CODE;
+                            //}
 
                             db.Default.Add(task);
                             db.Default.SaveChanges();

+ 2 - 0
Projects/永冠OPP/WCS.Service/Worker.cs

@@ -100,6 +100,8 @@ namespace WCS.Service
                 Device.AddFlag(DF.SRM放货, "1520", "1521", "1522", "1523", "1545", "1546", "1451", "1453");
                 Device.AddFlag(DF.一楼SRM取货, "1040", "1041", "1042", "1043", "1049", "1050", "1051", "1052");
                 Device.AddFlag(DF.一楼SRM取货, "1058", "1059", "1060", "1061", "1067", "1068");
+                Device.AddFlag(DF.涂布RGV, "RGV9", "RGV10", "RGV11", "RGV12", "RGV13", "RGV14");
+                Device.AddFlag(DF.拉膜RGV, "RGV1", "RGV2", "RGV3", "RGV4", "RGV5", "RGV6", "RGV7");
 
                 #endregion 设备扩展数据配置
 

+ 105 - 39
Projects/永冠OPP/WCS.Service/Works/RGV/RGVWorks.cs

@@ -17,52 +17,55 @@ namespace WCS.Service.Works.RGV
 
         protected override void Do(RGVDevice rgv)
         {
-            //RGV是自动且空闲的
-            if (rgv.Data2.WorkMode != WCS.Entity.Protocol.RGV.RGVMode.自动) return;
-            if (rgv.Data2.SystemStatus != WCS.Entity.Protocol.RGV.RGVRunStatus.空闲) return;
+            rgv.EX(rgv =>
+            {
+                //RGV是自动且空闲的
+                if (rgv.Data2.WorkMode != WCS.Entity.Protocol.RGV.RGVMode.自动) return;
+                if (rgv.Data2.SystemStatus != WCS.Entity.Protocol.RGV.RGVRunStatus.空闲) return;
 
-            var obj = Device.Find(ConvGroup_1030).Create<StationDeviceGroup>();
+                var obj = Device.Find(ConvGroup_1030).Create<StationDeviceGroup>();
 
-            if (obj.WhetherToExecute()) return;
+                if (obj.WhetherToExecute()) return;
 
-            //筛选出有任务号和起始及目标地址的设备
-            var dev = obj.RGVGetTaskedDevice() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", rgv.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                //筛选出有任务号和起始及目标地址的设备
+                var dev = obj.RGVGetTaskedDevice() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", rgv.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
 
-            DB.Do(db =>
-            {
-                var taskids = dev.Select(v => v.Data2.Tasknum);
-                var tasks = db.Default.Set<WCS_TASK>().Where(p => taskids.Contains(p.ID));
-                if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1)
-                    throw new Exception(LogHelper.SpliceLogMessage("任务组ID不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
-                if (tasks.GroupBy(p => p.TaskGroupKey).Count() == 0)
-                    throw new Exception(LogHelper.SpliceLogMessage("无任务组ID", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
-                var gw1 = obj.Items.ToArray()[0];
-                var gw2 = obj.Items.ToArray()[1];
-                if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0)
-                {
-                    if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new Exception(LogHelper.SpliceLogMessage($"{obj.Entity.Code}目标地址不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
-                }
-                rgv.Data.TaskID_1 = gw1.Data2.Tasknum;
-                rgv.Data.TaskID_2 = gw2.Data2.Tasknum;
-                if (gw1.Data2.Tasknum != 0)
-                {
-                    rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
-                    rgv.Data.DestPosition_1 = gw1.Data2.Goodsend;
-                }
-                else
+                DB.Do(db =>
                 {
-                    rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
-                    rgv.Data.DestPosition_1 = gw2.Data2.Goodsend;
-                }
-                rgv.Data.Trigger_1++;
+                    var taskids = dev.Select(v => v.Data2.Tasknum);
+                    var tasks = db.Default.Set<WCS_TASK>().Where(p => taskids.Contains(p.ID));
+                    if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1)
+                        throw new Exception(LogHelper.SpliceLogMessage("任务组ID不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                    if (tasks.GroupBy(p => p.TaskGroupKey).Count() == 0)
+                        throw new Exception(LogHelper.SpliceLogMessage("无任务组ID", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                    var gw1 = obj.Items.ToArray()[0];
+                    var gw2 = obj.Items.ToArray()[1];
+                    if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0)
+                    {
+                        if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new Exception(LogHelper.SpliceLogMessage($"{obj.Entity.Code}目标地址不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                    }
+                    rgv.Data.TaskID_1 = gw1.Data2.Tasknum;
+                    rgv.Data.TaskID_2 = gw2.Data2.Tasknum;
+                    if (gw1.Data2.Tasknum != 0)
+                    {
+                        rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
+                        rgv.Data.DestPosition_1 = gw1.Data2.Goodsend;
+                    }
+                    else
+                    {
+                        rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
+                        rgv.Data.DestPosition_1 = gw2.Data2.Goodsend;
+                    }
+                    rgv.Data.Trigger_1++;
 
-                foreach (var task in tasks)
-                {
-                    var msg = $"下达从{rgv.Data.StartPosition_1}移动至{ rgv.Data.DestPosition_1}的RGV PLC指令。";
-                    msg += $"[{ task.ID}][{rgv.Data.StartPosition_1}][{rgv.Data.DestPosition_1}[{ rgv.Data.Trigger_1}]";
+                    foreach (var task in tasks)
+                    {
+                        var msg = $"下达从{rgv.Data.StartPosition_1}移动至{ rgv.Data.DestPosition_1}的RGV PLC指令。";
+                        msg += $"[{ task.ID}][{rgv.Data.StartPosition_1}][{rgv.Data.DestPosition_1}[{ rgv.Data.Trigger_1}]";
 
-                    task.CreateStatusLog(db, msg, this.GetType());
-                }
+                        task.CreateStatusLog(db, msg, this.GetType());
+                    }
+                });
             });
         }
 
@@ -71,4 +74,67 @@ namespace WCS.Service.Works.RGV
             return dev.CODE == RGV8;
         }
     }
+
+    //[WorkTitle(typeof(RGVHandler), "直穿RGV")]
+    //public class 直穿RGV : DeviceWork<RGVDevice>
+    //{
+    //    private readonly string ConvGroup_1030 = "G1030";
+    //    private readonly string RGV8 = "RGV8";
+
+    //    protected override void Do(RGVDevice rgv)
+    //    {
+    //        //RGV是自动且空闲的
+    //        if (rgv.Data2.WorkMode != WCS.Entity.Protocol.RGV.RGVMode.自动) return;
+    //        if (rgv.Data2.SystemStatus != WCS.Entity.Protocol.RGV.RGVRunStatus.空闲) return;
+
+    //        var obj = Device.Find(ConvGroup_1030).Create<StationDeviceGroup>();
+
+    //        if (obj.WhetherToExecute()) return;
+
+    //        //筛选出有任务号和起始及目标地址的设备
+    //        var dev = obj.RGVGetTaskedDevice() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", rgv.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+
+    //        DB.Do(db =>
+    //        {
+    //            var taskids = dev.Select(v => v.Data2.Tasknum);
+    //            var tasks = db.Default.Set<WCS_TASK>().Where(p => taskids.Contains(p.ID));
+    //            if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1)
+    //                throw new Exception(LogHelper.SpliceLogMessage("任务组ID不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+    //            if (tasks.GroupBy(p => p.TaskGroupKey).Count() == 0)
+    //                throw new Exception(LogHelper.SpliceLogMessage("无任务组ID", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+    //            var gw1 = obj.Items.ToArray()[0];
+    //            var gw2 = obj.Items.ToArray()[1];
+    //            if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0)
+    //            {
+    //                if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new Exception(LogHelper.SpliceLogMessage($"{obj.Entity.Code}目标地址不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+    //            }
+    //            rgv.Data.TaskID_1 = gw1.Data2.Tasknum;
+    //            rgv.Data.TaskID_2 = gw2.Data2.Tasknum;
+    //            if (gw1.Data2.Tasknum != 0)
+    //            {
+    //                rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
+    //                rgv.Data.DestPosition_1 = gw1.Data2.Goodsend;
+    //            }
+    //            else
+    //            {
+    //                rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
+    //                rgv.Data.DestPosition_1 = gw2.Data2.Goodsend;
+    //            }
+    //            rgv.Data.Trigger_1++;
+
+    //            foreach (var task in tasks)
+    //            {
+    //                var msg = $"下达从{rgv.Data.StartPosition_1}移动至{ rgv.Data.DestPosition_1}的RGV PLC指令。";
+    //                msg += $"[{ task.ID}][{rgv.Data.StartPosition_1}][{rgv.Data.DestPosition_1}[{ rgv.Data.Trigger_1}]";
+
+    //                task.CreateStatusLog(db, msg, this.GetType());
+    //            }
+    //        });
+    //    }
+
+    //    protected override bool SelectDevice(WCS_DEVICE dev)
+    //    {
+    //        return dev.CODE == RGV8;
+    //    }
+    //}
 }

+ 292 - 309
Projects/永冠OPP/WCS.Service/Works/SRM/SRMWork.cs

@@ -30,352 +30,335 @@ namespace WCS.Service.Works.SRM
 
         protected override void Do(SRMDevice obj)
         {
-            var deviceCode = obj.Entity.CODE;
-            //先检查堆垛机是否报警
-            if (obj.Data3.SCAlarm != 0)
+            obj.EX(obj =>
             {
-                if (obj.Entity.WakeupOn(5000)) WMS.DevInfo(obj.Entity.CODE, obj.Data3.SCAlarm.ToString());
-                InfoLog.INFO_SRMALARM($"{obj.Entity.CODE}-{obj.Data3.SCAlarm}");
-                return;
-            }
-            if (obj.Data.FinishedACK_1 == 1 || obj.Data.FinishedACK_2 == 1)
-                throw new Exception(LogHelper.SpliceLogMessage($"堆垛机完成任务WCS反馈信号未清除", deviceCode, WCS_EXCEPTIONTYPE.设备异常, GetType()));
-            if (obj.Data2.VoucherNo_1 != obj.Data.VoucherNo_1 || obj.Data2.VoucherNo_2 != obj.Data.VoucherNo_2)
-                throw new Exception(LogHelper.SpliceLogMessage($"等待执行{obj.Data.TaskID_1}-{obj.Data.TaskID_2}", deviceCode, WCS_EXCEPTIONTYPE.设备异常, GetType()));
-
-            //处理堆垛机已完成的任务
-            if (obj.Data2.FinishedTask_1 != 0 || obj.Data2.FinishedTask_2 != 0)
-            {
-                obj.FinishedTaskHandle();
-                return;
-            }
-
-            if (obj.Data2.Mode_1 != SCMode.远程) return;
+                var deviceCode = obj.Entity.CODE;
+                //先检查堆垛机是否报警
+                if (obj.Data3.SCAlarm != 0)
+                {
+                    if (obj.Entity.WakeupOn(5000)) WMS.DevInfo(obj.Entity.CODE, obj.Data3.SCAlarm.ToString());
+                    InfoLog.INFO_SRMALARM($"{obj.Entity.CODE}-{obj.Data3.SCAlarm}");
+                    return;
+                }
+                if (obj.Data.FinishedACK_1 == 1 || obj.Data.FinishedACK_2 == 1)
+                    throw new Exception(LogHelper.SpliceLogMessage($"堆垛机完成任务WCS反馈信号未清除", deviceCode, WCS_EXCEPTIONTYPE.设备异常, GetType()));
+                if (obj.Data2.VoucherNo_1 != obj.Data.VoucherNo_1 || obj.Data2.VoucherNo_2 != obj.Data.VoucherNo_2)
+                    throw new Exception(LogHelper.SpliceLogMessage($"等待执行{obj.Data.TaskID_1}-{obj.Data.TaskID_2}", deviceCode, WCS_EXCEPTIONTYPE.设备异常, GetType()));
 
-            if (obj.Data2.Status_1 != SCRunStatus.空闲) return;
+                //处理堆垛机已完成的任务
+                if (obj.Data2.FinishedTask_1 != 0 || obj.Data2.FinishedTask_2 != 0)
+                {
+                    obj.FinishedTaskHandle();
+                    return;
+                }
 
-            var isTransfer = new List<WCS_TASK>();
-            WCS_TASK enterPriority = new WCS_TASK(), outPriority = new WCS_TASK();
-            //再检查是否有等待执行的货物
-            DB.Do(db =>
-            {
-                var task = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE).Where(v => v.STATUS == TaskStatus.堆垛机执行).FirstOrDefault();
-                if (task != null) throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的任务:[{task.ID}]", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
-                //属于当前堆垛机未执行的移库任务
-                isTransfer = db.Default.Set<WCS_TASK>().AsNoTracking().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行).ToList();
-                //判断是否存在调整优先级任务,存在初始化isTransfer值 让本次执行优先任务
-                if (db.Default.Set<WCS_TASK>().AsNoTracking().Any(v => v.DEVICE == obj.Entity.CODE && v.TYPE != TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行 && v.Priority > 0))
-                    isTransfer = new List<WCS_TASK>();
-                enterPriority = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.入库 && v.STATUS < TaskStatus.堆垛机执行)
-                                                             .OrderByDescending(v => v.Priority).FirstOrDefault();
-                outPriority = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.出库 && v.STATUS < TaskStatus.堆垛机执行)
-                                                              .OrderByDescending(v => v.Priority).FirstOrDefault();
-            });
+                if (obj.Data2.Mode_1 != SCMode.远程) return;
 
-            var LastIsOut = obj.Entity.Get<bool>("LastIsOut");
-            obj.Entity.Set("LastIsOut", !LastIsOut);
-            if (isTransfer.Count > 0) //防止因为无当前堆垛机移库任务导致无法执行其他类型任务
-            {
-                #region 移库
+                if (obj.Data2.Status_1 != SCRunStatus.空闲) return;
 
+                var isTransfer = new List<WCS_TASK>();
+                WCS_TASK enterPriority = new WCS_TASK(), outPriority = new WCS_TASK();
+                //再检查是否有等待执行的货物
                 DB.Do(db =>
                 {
-                    //获取当前堆垛机未执行的任务的组ID
-                    var taskGroupKey = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行).OrderBy(p => p.CREATETIME).FirstOrDefault().TaskGroupKey;
-                    //通过任务的组ID找到本组的所有任务
-                    var tasks = db.Default.Set<WCS_TASK>().Where(v => v.TaskGroupKey == taskGroupKey);
+                    var task = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE).Where(v => v.STATUS == TaskStatus.堆垛机执行).FirstOrDefault();
+                    if (task != null) throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的任务:[{task.ID}]", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                    //属于当前堆垛机未执行的移库任务
+                    isTransfer = db.Default.Set<WCS_TASK>().AsNoTracking().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行).ToList();
+                    //判断是否存在调整优先级任务,存在初始化isTransfer值 让本次执行优先任务
+                    if (db.Default.Set<WCS_TASK>().AsNoTracking().Any(v => v.DEVICE == obj.Entity.CODE && v.TYPE != TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行 && v.Priority > 0))
+                        isTransfer = new List<WCS_TASK>();
+                    enterPriority = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.入库 && v.STATUS < TaskStatus.堆垛机执行)
+                                                                 .OrderByDescending(v => v.Priority).FirstOrDefault();
+                    outPriority = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.出库 && v.STATUS < TaskStatus.堆垛机执行)
+                                                                  .OrderByDescending(v => v.Priority).FirstOrDefault();
+                });
 
-                    //双工位  货架列单数为一工位取放点  货架列双数为二工位取放点
-                    foreach (var task in tasks)
-                    {
-                        var addrFrom = task.ADDRFROM.Split("-");
-                        var addrTo = task.ADDRTO.Split("-");
+                //最后一个是否是出库任务
+                var LastIsOut = obj.Entity.Get<bool>("LastIsOut");
+                obj.Entity.Set("LastIsOut", !LastIsOut);
+                if (isTransfer.Count > 0) //防止因为无当前堆垛机移库任务导致无法执行其他类型任务
+                {
+                    #region 移库
 
-                        var oldTaskSTATUS = task.STATUS;
-                        task.STARTTIME = DateTime.Now;
-                        task.UPDATETIME = DateTime.Now;
-                        task.STATUS = WCS.Entity.TaskStatus.堆垛机执行;
-                        task.DEVICE = obj.Entity.CODE;
-                        db.Default.SaveChanges();
-                        Uploader.Upload(db);
-                        task.CreateStatusLog(db, $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}]", this.GetType());
+                    DB.Do(db =>
+                    {
+                        //获取当前堆垛机未执行的任务的组ID
+                        var taskGroupKey = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行).OrderBy(p => p.CREATETIME).FirstOrDefault().TaskGroupKey;
+                        //通过任务的组ID找到本组的所有任务
+                        var tasks = db.Default.Set<WCS_TASK>().Where(v => v.TaskGroupKey == taskGroupKey);
 
-                        if (addrFrom[2].ToShort().OddNumberOrEven())
-                        {
-                            obj.Data.TaskID_1 = task.ID;
-                            obj.Data.SLine_1 = addrFrom[0].ToShort();
-                            obj.Data.SCol_1 = addrFrom[1].ToShort();
-                            obj.Data.SLayer_1 = addrFrom[2].ToShort();
-                            obj.Data.ELine_1 = addrTo[0].ToShort();
-                            obj.Data.ECol_1 = addrTo[1].ToShort();
-                            obj.Data.ELayer_1 = addrTo[2].ToShort();
-                            obj.Data.VoucherNo_1++;
-                        }
-                        else
+                        //双工位  货架列单数为一工位取放点  货架列双数为二工位取放点
+                        foreach (var task in tasks)
                         {
-                            obj.Data.TaskID_2 = task.ID;
-                            obj.Data.SLine_2 = addrFrom[0].ToShort();
-                            obj.Data.SCol_2 = addrFrom[1].ToShort();
-                            obj.Data.SLayer_2 = addrFrom[2].ToShort();
-                            obj.Data.ELine_2 = addrTo[0].ToShort();
-                            obj.Data.ECol_2 = addrTo[1].ToShort();
-                            obj.Data.ELayer_2 = addrTo[2].ToShort();
-                            obj.Data.VoucherNo_2++;
-                        }
-                    }
-                });
-
-                #endregion 移库
-            }
-            else if (LastIsOut)
-            {
-                #region 入库
-
-                if (outPriority?.Priority > enterPriority?.Priority) return;
-                //获取所有取货点
-                var arrIn = obj.GetPickPoint()
-                               .Where(v => Device.Where(d => d.IsConv())
-                                                 .Select(d => d.Device<IStation521>())
-                                                 .Where(d => d.Data.Goodsend == v.Entity.Code())
-                                                 .Any()).ToList();
-                if (!arrIn.Any()) return; //当前堆垛机无入库任务
+                            var addrFrom = task.ADDRFROM.Split("-");
+                            var addrTo = task.ADDRTO.Split("-");
 
-                //入库口设备信息 找一个有任务有光电且不在运行状态位的取货点 如果找不到代表任务还在输送途中
-                var st = arrIn.OrderBy(v => v.Data2.Tasknum > 0 && v.Data2.Status.HasFlag(IstationStatus.光电状态) && !v.Data3.Status.HasFlag(StationStatus.运行状态位) ? 0 : 1)
-                              .ThenBy(v => v.UpdateTime)
-                              .FirstOrDefault() ?? throw new Exception($"[{deviceCode}]等待入库任务输送到位");
+                            var oldTaskSTATUS = task.STATUS;
+                            task.STARTTIME = DateTime.Now;
+                            task.UPDATETIME = DateTime.Now;
+                            task.STATUS = WCS.Entity.TaskStatus.堆垛机执行;
+                            task.DEVICE = obj.Entity.CODE;
+                            db.Default.SaveChanges();
+                            Uploader.Upload(db);
+                            task.CreateStatusLog(db, $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}]", this.GetType());
 
-                //根据上述筛选条件筛选出来的入库任务 找到对应的设备组
-                var item = Device.Where(v => v.DEVICEGROUP.Any(p => p.MEMBER.CODE == st.Entity.CODE)).Single();
-                //对数据进行排序,根据CAD图纸规划,取货点两个设备中设备号较大的一个一定对应到堆垛机的一工位货叉
-                //因此按照降序进行排序,可以保证数组中第一个一定是放到堆垛机一工位的数据
-                var devs = item.DEVICEGROUP.Select(v => v.MEMBER)
-                                           .Select(v => v.Create<StationDevice>())
-                                           .OrderByDescending(v => v.Entity.CODE)
-                                           .ToArray();
-                //取巷道
+                            if (addrFrom[2].ToShort().OddNumberOrEven())
+                            {
+                                obj.Data.TaskID_1 = task.ID;
+                                obj.Data.SLine_1 = addrFrom[0].ToShort();
+                                obj.Data.SCol_1 = addrFrom[1].ToShort();
+                                obj.Data.SLayer_1 = addrFrom[2].ToShort();
+                                obj.Data.ELine_1 = addrTo[0].ToShort();
+                                obj.Data.ECol_1 = addrTo[1].ToShort();
+                                obj.Data.ELayer_1 = addrTo[2].ToShort();
+                                obj.Data.VoucherNo_1++;
+                            }
+                            else
+                            {
+                                obj.Data.TaskID_2 = task.ID;
+                                obj.Data.SLine_2 = addrFrom[0].ToShort();
+                                obj.Data.SCol_2 = addrFrom[1].ToShort();
+                                obj.Data.SLayer_2 = addrFrom[2].ToShort();
+                                obj.Data.ELine_2 = addrTo[0].ToShort();
+                                obj.Data.ECol_2 = addrTo[1].ToShort();
+                                obj.Data.ELayer_2 = addrTo[2].ToShort();
+                                obj.Data.VoucherNo_2++;
+                            }
+                        }
+                    });
 
-                DB.Do(db =>
+                    #endregion 移库
+                }
+                else if (LastIsOut)
                 {
-                    var dev1 = devs[0];
-                    var dev2 = devs[1];
-                    var dev1IsThereATask = dev1.Data2.Tasknum > 0 && dev1.Data2.Status.HasFlag(IstationStatus.光电状态) && !dev1.Data3.Status.HasFlag(StationStatus.运行状态位);
-                    var dev2IsThereATask = dev2.Data2.Tasknum > 0 && dev2.Data2.Status.HasFlag(IstationStatus.光电状态) && !dev2.Data3.Status.HasFlag(StationStatus.运行状态位);
-                    //处理一工位
-                    if (dev1IsThereATask)
-                    {
-                        var tunnel = dev1.Entity.ROUTES.First().NEXT.CODE;
-                        var task1 = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.STATUS < TaskStatus.堆垛机执行 && v.ID == dev1.Data2.Tasknum);
-                        if (task1 == null)
-                            throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev1.Data2.Tasknum}", dev1.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
-                        var loc = WMS.GetLocalIn(task1.WMSTASK, tunnel, dev1.Entity.CODE, Entity.WareCellForkNum.货叉1);
-                        var locno = string.Format("{0}-{1}-{2}", loc.Row, loc.Colomn, loc.Layer);
-                        var oldTask = task1.STATUS;
-                        task1.UPDATETIME = DateTime.Now;
-                        task1.STATUS = TaskStatus.堆垛机执行;
-                        task1.ADDRTO = locno;
-                        task1.DEVICE = obj.Entity.CODE;
-                        task1.TUNNEL = tunnel;
-                        db.Default.SaveChanges();
-                        Uploader.Upload(db);
-                        task1.CreateStatusLog(db, $"状态由{oldTask}变更至{task1.STATUS}", this.GetType());
-
-                        obj.Data.TaskID_1 = task1.ID;
-                        obj.Data.SLine_1 = dev1.Entity.CODE.ToShort();
-                        obj.Data.SCol_1 = 0;
-                        obj.Data.SLayer_1 = 0;
-                        obj.Data.ELine_1 = loc.Row;
-                        obj.Data.ECol_1 = loc.Colomn;
-                        obj.Data.ELayer_1 = loc.Layer;
-                    }
-                    //处理二工位
-                    if (dev2IsThereATask)
-                    {
-                        var tunnel = dev2.Entity.ROUTES.First().NEXT.CODE;
-                        var task2 = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.STATUS < TaskStatus.堆垛机执行 && v.ID == dev2.Data2.Tasknum);
-                        if (task2 == null) throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev2.Data2.Tasknum}", dev2.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
-                        var loc = WMS.GetLocalIn(task2.WMSTASK, tunnel, dev2.Entity.CODE, Entity.WareCellForkNum.货叉2);
-                        var locno = string.Format("{0}-{1}-{2}", loc.Row, loc.Colomn, loc.Layer);
-                        var oldTask = task2.STATUS;
-                        task2.UPDATETIME = DateTime.Now;
-                        task2.STATUS = TaskStatus.堆垛机执行;
-                        task2.ADDRTO = locno;
-                        task2.DEVICE = obj.Entity.CODE;
-                        task2.TUNNEL = tunnel;
-                        db.Default.SaveChanges();
-                        Uploader.Upload(db);
-                        task2.CreateStatusLog(db, $"状态由{oldTask}变更至{task2.STATUS}", this.GetType());
+                    #region 入库
 
-                        obj.Data.TaskID_2 = task2.ID;
-                        obj.Data.SLine_2 = dev2.Entity.CODE.ToShort();
-                        obj.Data.SCol_2 = 0;
-                        obj.Data.SLayer_2 = 0;
-                        obj.Data.ELine_2 = loc.Row;
-                        obj.Data.ECol_2 = loc.Colomn;
-                        obj.Data.ELayer_2 = loc.Layer;
-                    }
-                    if (dev1IsThereATask) obj.Data.VoucherNo_1++;
-                    if (dev2IsThereATask) obj.Data.VoucherNo_2++;
-                });
+                    if (outPriority?.Priority > enterPriority?.Priority) return;
+                    //获取所有取货点
+                    var arrIn = obj.GetPickPoint()
+                                   .Where(v => Device.Where(d => d.IsConv())
+                                                     .Select(d => d.Device<IStation521>())
+                                                     .Where(d => d.Data.Goodsend == v.Entity.Code())
+                                                     .Any()).ToList();
+                    if (!arrIn.Any()) return; //当前堆垛机无入库任务
 
-                #endregion 入库
-            }
-            else
-            {
-                #region 出库
+                    //入库口设备信息 找一个有任务有光电且不在运行状态位的取货点 如果找不到代表任务还在输送途中
+                    var st = arrIn.OrderBy(v => v.Data2.Tasknum > 0 && v.Data2.Status.HasFlag(IstationStatus.光电状态) && !v.Data3.Status.HasFlag(StationStatus.运行状态位) ? 0 : 1)
+                                  .ThenBy(v => v.UpdateTime)
+                                  .FirstOrDefault() ?? throw new Exception($"[{deviceCode}]等待入库任务输送到位");
 
-                var floor = obj.Entity.Get<int>("LastFloor");
-                floor = floor % 2 + 1;
-                obj.Entity.Set("LastFloor", floor);
-                if (enterPriority?.Priority > outPriority?.Priority) return;
-                obj.EXOutStock(obj =>
-                {
-                    //获取当前堆垛机所有的放货点
-                    var list = obj.GetDeliveryPoint();
+                    //根据上述筛选条件筛选出来的入库任务 找到对应的设备组
+                    var item = Device.Where(v => v.DEVICEGROUP.Any(p => p.MEMBER.CODE == st.Entity.CODE)).Single();
+                    //对数据进行排序,根据CAD图纸规划,取货点两个设备中设备号较大的一个一定对应到堆垛机的一工位货叉
+                    //因此按照降序进行排序,可以保证数组中第一个一定是放到堆垛机一工位的数据
+                    var devs = item.DEVICEGROUP.Select(v => v.MEMBER)
+                                               .Select(v => v.Create<StationDevice>())
+                                               .OrderByDescending(v => v.Entity.CODE)
+                                               .ToArray();
+                    //取巷道
 
-                    list = list.Where(v =>
+                    DB.Do(db =>
                     {
-                        //true:满足条件  false:不满足条件
-                        //返回结果为无货的设备  默认无货
-                        var res = true;
-                        //放货点是否有货
-                        if (v.Data.VoucherNo != v.Data2.VoucherNo) res = false;
-                        else if (v.Data3.Status.HasFlag(StationStatus.运行状态位)) res = false;
-                        else if (v.Data2.Status.HasFlag(IstationStatus.光电状态)) res = false;
-                        else if (v.Data2.Request == IstationRequest.堆垛机放货完成请求目标地址) res = false;
-                        else if (v.Data2.Tasknum > 10000) res = false;
-                        //TODO:因放货设备过短且无动力,因此需要占用对应旋转台   后续考虑优化方式
-                        if (res)
+                        var dev1 = devs[0];
+                        var dev2 = devs[1];
+                        var dev1IsThereATask = dev1.Data2.Tasknum > 0 && dev1.Data2.Status.HasFlag(IstationStatus.光电状态) && !dev1.Data3.Status.HasFlag(StationStatus.运行状态位);
+                        var dev2IsThereATask = dev2.Data2.Tasknum > 0 && dev2.Data2.Status.HasFlag(IstationStatus.光电状态) && !dev2.Data3.Status.HasFlag(StationStatus.运行状态位);
+                        //处理一工位
+                        if (dev1IsThereATask)
                         {
-                            List<StationDevice> moveDevs = null;
-                            if (v.Entity.CODE is "1473" or "1474" or "1475" or "1476")
-                                moveDevs = Device.Find("1471", "1472").Select(p => p.Create<StationDevice>()).ToList();
-                            else if (v.Entity.CODE is "1491" or "1492" or "1493" or "1494")
-                                moveDevs = Device.Find("1489", "1490").Select(p => p.Create<StationDevice>()).ToList();
-                            else if (v.Entity.CODE is "1520" or "1521" or "1522" or "1523")
-                                moveDevs = Device.Find("1518", "1519").Select(p => p.Create<StationDevice>()).ToList();
-                            else if (v.Entity.CODE is "1545" or "1546")
-                                moveDevs = Device.Find("1543", "1544").Select(p => p.Create<StationDevice>()).ToList();
-                            else if (v.Entity.CODE is "1555" or "1556")
-                                moveDevs = Device.Find("1551", "1553").Select(p => p.Create<StationDevice>()).ToList();
-                            //如果放货点有移动设备 旋转台的两个设备必须都以停止运行 并无任务及请求
-                            if (moveDevs != null)
-                            {
-                                if (moveDevs.Any(p => p.Data.VoucherNo != p.Data2.VoucherNo)) res = false;
-                                else if (moveDevs.Any(p => p.Data3.Status.HasFlag(StationStatus.有货状态位))) res = false;
-                                else if (moveDevs.Any(p => p.Data2.Status.HasFlag(IstationStatus.光电状态))) res = false;
-                                else if (moveDevs.Any(p => p.Data2.Tasknum > 10000)) res = false;
-                            }
+                            var tunnel = dev1.Entity.ROUTES.First().NEXT.CODE;
+                            var task1 = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.STATUS < TaskStatus.堆垛机执行 && v.ID == dev1.Data2.Tasknum);
+                            if (task1 == null)
+                                throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev1.Data2.Tasknum}", dev1.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
+                            var loc = WMS.GetLocalIn(task1.WMSTASK, tunnel, dev1.Entity.CODE, Entity.WareCellForkNum.货叉1);
+                            var locno = string.Format("{0}-{1}-{2}", loc.Row, loc.Colomn, loc.Layer);
+                            var oldTask = task1.STATUS;
+                            task1.UPDATETIME = DateTime.Now;
+                            task1.STATUS = TaskStatus.堆垛机执行;
+                            task1.ADDRTO = locno;
+                            task1.DEVICE = obj.Entity.CODE;
+                            task1.TUNNEL = tunnel;
+                            db.Default.SaveChanges();
+                            Uploader.Upload(db);
+                            task1.CreateStatusLog(db, $"状态由{oldTask}变更至{task1.STATUS}", this.GetType());
+
+                            obj.Data.TaskID_1 = task1.ID;
+                            obj.Data.SLine_1 = dev1.Entity.CODE.ToShort();
+                            obj.Data.SCol_1 = 0;
+                            obj.Data.SLayer_1 = 0;
+                            obj.Data.ELine_1 = loc.Row;
+                            obj.Data.ECol_1 = loc.Colomn;
+                            obj.Data.ELayer_1 = loc.Layer;
+                        }
+                        //处理二工位
+                        if (dev2IsThereATask)
+                        {
+                            var tunnel = dev2.Entity.ROUTES.First().NEXT.CODE;
+                            var task2 = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.STATUS < TaskStatus.堆垛机执行 && v.ID == dev2.Data2.Tasknum);
+                            if (task2 == null) throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev2.Data2.Tasknum}", dev2.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
+                            var loc = WMS.GetLocalIn(task2.WMSTASK, tunnel, dev2.Entity.CODE, Entity.WareCellForkNum.货叉2);
+                            var locno = string.Format("{0}-{1}-{2}", loc.Row, loc.Colomn, loc.Layer);
+                            var oldTask = task2.STATUS;
+                            task2.UPDATETIME = DateTime.Now;
+                            task2.STATUS = TaskStatus.堆垛机执行;
+                            task2.ADDRTO = locno;
+                            task2.DEVICE = obj.Entity.CODE;
+                            task2.TUNNEL = tunnel;
+                            db.Default.SaveChanges();
+                            Uploader.Upload(db);
+                            task2.CreateStatusLog(db, $"状态由{oldTask}变更至{task2.STATUS}", this.GetType());
+
+                            obj.Data.TaskID_2 = task2.ID;
+                            obj.Data.SLine_2 = dev2.Entity.CODE.ToShort();
+                            obj.Data.SCol_2 = 0;
+                            obj.Data.SLayer_2 = 0;
+                            obj.Data.ELine_2 = loc.Row;
+                            obj.Data.ECol_2 = loc.Colomn;
+                            obj.Data.ELayer_2 = loc.Layer;
                         }
-                        return res;
-                    }).ToList();
+                        if (dev1IsThereATask) obj.Data.VoucherNo_1++;
+                        if (dev2IsThereATask) obj.Data.VoucherNo_2++;
+                    });
 
-                    //没有可用货位
-                    if (list.Count == 0) return;
+                    #endregion 入库
+                }
+                else
+                {
+                    #region 出库
 
-                    //可用设备的编号组
-                    var empties = list.Select(v => v.Entity.CODE).ToArray();
-                    //月台所有设备当前有的任务号
-                    var taskidList = DockDevs.Select(v => v.Data2.Tasknum).Where(v => v > 10000).ToList();
-                    //堆垛机设备
-                    var sc = obj.Entity.CODE;
-                    DB.Do(db =>
+                    var floor = obj.Entity.Get<int>("LastFloor");
+                    floor = floor % 2 + 1;
+                    obj.Entity.Set("LastFloor", floor);
+                    if (enterPriority?.Priority > outPriority?.Priority) return;
+                    obj.EXOutStock(obj =>
                     {
-                        //堆垛机当前是否有正在执行的任务
-                        if (db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行))
-                            throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的出库任务", deviceCode, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
-                        //找出等待执行的出库任务
-                        var q = db.Default.Set<WCS_TASK>().Where(v => v.STATUS == TaskStatus.新建)
-                                                          .Where(v => v.DEVICE == sc)
-                                                          .Where(v => v.TYPE == TaskType.出库)
-                                                          .Where(v => !db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行)).ToList();
-                        //同一个目标地址同时只能有4(双工位,每一节设备可以存放两个任务)个正在执行的任务
-                        //考虑到有可能出现一次只发一个任务的情况,因此判断条件为3
-                        //连续两次只发一个任务的情况暂时不考虑
-                        //同时对结果进行排序,分组后取第一组任务
-                        //TODO:暂时不确定排序后进行分组是否会完全打乱排序,先按照这种按时执行,后续有异常再更改
-                        //TODO:暂时维考虑二楼环穿
-                        var outDepot = q.Where(v => db.Default.Set<WCS_TASK>()
-                                            .Where(d => d.TYPE == TaskType.出库)
-                                            .Where(d => d.STATUS > TaskStatus.新建)
-                                            .Where(d => d.STATUS < TaskStatus.已完成 || taskidList.Contains(d.ID))
-                                            .Where(d => d.ADDRTO == v.ADDRTO && d.FLOOR == v.FLOOR)
-                                            .Count() < 3)
-                                    .OrderByDescending(v => v.Priority)
-                                    .ThenBy(v => v.FLOOR == floor ? 0 : 1)
-                                    .ThenBy(v => v.CREATETIME)
-                                    .GroupBy(v => v.ADDRTO)
-                                    .FirstOrDefault();
+                        //获取当前堆垛机所有的放货点
+                        var list = obj.GetDeliveryPoint();
 
-                        if (outDepot == null)
+                        list = list.Where(v =>
                         {
-                            Ltc.Log($"{deviceCode}无出库任务可执行");
-                            return;
-                        }
-                        //获取两个个可执行任务,此时这两个任务的目标地址是一致的
-                        var tasks = outDepot.Select(v => v).ToList().GetOutTask();
+                            //true:满足条件  false:不满足条件
+                            //返回结果为无货的设备  默认无货
+                            var res = true;
+                            //放货点是否有货
+                            if (v.Data.VoucherNo != v.Data2.VoucherNo) res = false;
+                            else if (v.Data3.Status.HasFlag(StationStatus.运行状态位)) res = false;
+                            else if (v.Data2.Status.HasFlag(IstationStatus.光电状态)) res = false;
+                            else if (v.Data2.Request == IstationRequest.堆垛机放货完成请求目标地址) res = false;
+                            else if (v.Data2.Tasknum > 10000) res = false;
+                            //TODO:因放货设备过短且无动力,因此需要占用对应旋转台   后续考虑优化方式
+                            if (res)
+                            {
+                                List<StationDevice> moveDevs = null;
+                                if (v.Entity.CODE is "1473" or "1474" or "1475" or "1476")
+                                    moveDevs = Device.Find("1471", "1472").Select(p => p.Create<StationDevice>()).ToList();
+                                else if (v.Entity.CODE is "1491" or "1492" or "1493" or "1494")
+                                    moveDevs = Device.Find("1489", "1490").Select(p => p.Create<StationDevice>()).ToList();
+                                else if (v.Entity.CODE is "1520" or "1521" or "1522" or "1523")
+                                    moveDevs = Device.Find("1518", "1519").Select(p => p.Create<StationDevice>()).ToList();
+                                else if (v.Entity.CODE is "1545" or "1546")
+                                    moveDevs = Device.Find("1543", "1544").Select(p => p.Create<StationDevice>()).ToList();
+                                else if (v.Entity.CODE is "1555" or "1556")
+                                    moveDevs = Device.Find("1551", "1553").Select(p => p.Create<StationDevice>()).ToList();
+                                //如果放货点有移动设备 旋转台的两个设备必须都以停止运行 并无任务及请求
+                                if (moveDevs != null)
+                                {
+                                    if (moveDevs.Any(p => p.Data.VoucherNo != p.Data2.VoucherNo)) res = false;
+                                    else if (moveDevs.Any(p => p.Data3.Status.HasFlag(StationStatus.有货状态位))) res = false;
+                                    else if (moveDevs.Any(p => p.Data2.Status.HasFlag(IstationStatus.光电状态))) res = false;
+                                    else if (moveDevs.Any(p => p.Data2.Tasknum > 10000)) res = false;
+                                }
+                            }
+                            return res;
+                        }).ToList();
 
-                        //根据任务的目标地址获取对应的设备组
-                        var devs = Device.Find($"{tasks.OrderBy(v => v.ADDRTO).FirstOrDefault().ADDRTO}").Create<StationDeviceGroup>().Items.OrderByDescending(v => v.Entity.CODE).ToArray();
-                        var dev1 = devs[0];
-                        var dev2 = devs[1];
+                        //没有可用货位
+                        if (list.Count == 0) return;
 
-                        for (int i = 0; i < tasks.Length; i++)
+                        //可用设备的编号组
+                        var empties = list.Select(v => v.Entity.CODE).ToArray();
+                        //月台所有设备当前有的任务号
+                        var taskidList = DockDevs.Select(v => v.Data2.Tasknum).Where(v => v > 10000).ToList();
+                        //堆垛机设备
+                        var sc = obj.Entity.CODE;
+                        DB.Do(db =>
                         {
-                            var item = tasks[i];
-                            var task = db.Default.Set<WCS_TASK>().Find(item.ID);
-                            //找到所有可用到达目的地的取货点,必定是一个设备组
-                            var a = Device.Where(v => v.ROUTES.Any(p => p.NEXT.CODE == task.ADDRTO));
-                            var oldTaskSTATUS = task.STATUS;
-                            task.STARTTIME = DateTime.Now;
-                            task.UPDATETIME = DateTime.Now;
-                            task.STATUS = WCS.Entity.TaskStatus.堆垛机执行;
-                            task.DEVICE = obj.Entity.CODE;
-                            //获取到站台的下一个地址
-                            if (Device.Find(task.SRMSTATION).ROUTES.Any(v => v.NEXT == dev1.Entity)) task.ADDRNEXT = dev1.Entity.CODE;
-                            else task.ADDRNEXT = dev2.Entity.CODE;
-                            db.Default.SaveChanges();
-                            Uploader.Upload(db);
-                            var msg = "";
-                            if (item.Col.OddNumberOrEven())
-                                msg = $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}][{obj.Data.SLine_1}-{obj.Data.SCol_1}-{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]";
-                            else
-                                msg = $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}][{obj.Data.SLine_2}-{obj.Data.SCol_2}-{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]";
-                            task.CreateStatusLog(db, msg, this.GetType());
+                            //堆垛机当前是否有正在执行的任务
+                            if (db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行))
+                                throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的出库任务", deviceCode, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                            //找出等待执行的出库任务
+                            var q = db.Default.Set<WCS_TASK>().Where(v => v.STATUS == TaskStatus.新建)
+                                                              .Where(v => v.DEVICE == sc)
+                                                              .Where(v => v.TYPE == TaskType.出库)
+                                                              .Where(v => !db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行)).ToList();
+                            //同一个目标地址同时只能有4(双工位,每一节设备可以存放两个任务)个正在执行的任务
+                            //考虑到有可能出现一次只发一个任务的情况,因此判断条件为3
+                            //连续两次只发一个任务的情况暂时不考虑
+                            //同时对结果进行排序,分组后取第一组任务
+                            //TODO:暂时不确定排序后进行分组是否会完全打乱排序,先按照这种按时执行,后续有异常再更改
+                            //TODO:暂时维考虑二楼环穿
+                            var outDepot = q.Where(v => db.Default.Set<WCS_TASK>()
+                                                .Where(d => d.TYPE == TaskType.出库)
+                                                .Where(d => d.STATUS > TaskStatus.新建)
+                                                .Where(d => d.STATUS < TaskStatus.已完成 || taskidList.Contains(d.ID))
+                                                .Where(d => d.ADDRTO == v.ADDRTO && d.FLOOR == v.FLOOR)
+                                                .Count() < 3)
+                                        .OrderByDescending(v => v.Priority)
+                                        .ThenBy(v => v.FLOOR == floor ? 0 : 1)
+                                        .ThenBy(v => v.CREATETIME)
+                                        .GroupBy(v => v.ADDRTO)
+                                        .FirstOrDefault();
 
-                            //判断当前任务为二工位还是一工位
-                            if (item.Col.OddNumberOrEven())
+                            if (outDepot == null)
                             {
-                                InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]1工位-开始:[{obj.Data.TaskID_1}][{obj.Data.SLine_1}][{obj.Data.SCol_1}][{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]");
-                                obj.Data.TaskID_1 = item.ID;
-                                obj.Data.SLine_1 = item.Line;
-                                obj.Data.SCol_1 = item.Col;
-                                obj.Data.SLayer_1 = item.Layer;
-                                obj.Data.ELine_1 = task.SRMSTATION.ToShort();
-                                obj.Data.ECol_1 = 0;
-                                obj.Data.ELayer_1 = 0;
-                                obj.Data.VoucherNo_1++;
-                                InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]1工位-结束:[{obj.Data.TaskID_1}][{obj.Data.SLine_1}][{obj.Data.SCol_1}][{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]");
+                                Ltc.Log($"{deviceCode}无出库任务可执行");
+                                return;
                             }
-                            else
+                            //获取两个个可执行任务,此时这两个任务的目标地址是一致的
+                            var tasks = outDepot.Select(v => v).ToList().GetOutTask();
+
+                            //根据任务的目标地址获取对应的设备组
+                            var devs = Device.Find($"{tasks.OrderBy(v => v.ADDRTO).FirstOrDefault().ADDRTO}").Create<StationDeviceGroup>().Items.OrderByDescending(v => v.Entity.CODE).ToArray();
+                            var dev1 = devs[0];
+                            var dev2 = devs[1];
+
+                            for (int i = 0; i < tasks.Length; i++)
                             {
-                                InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]2工位-开始:[{obj.Data.TaskID_2}][{obj.Data.SLine_2}][{obj.Data.SCol_2}][{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]");
-                                obj.Data.TaskID_2 = item.ID;
-                                obj.Data.SLine_2 = item.Line;
-                                obj.Data.SCol_2 = item.Col;
-                                obj.Data.SLayer_2 = item.Layer;
-                                obj.Data.ELine_2 = task.SRMSTATION.ToShort();
-                                obj.Data.ECol_2 = 0;
-                                obj.Data.ELayer_2 = 0;
-                                obj.Data.VoucherNo_2++;
-                                InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]2工位-结束:[{obj.Data.TaskID_2}][{obj.Data.SLine_2}][{obj.Data.SCol_2}][{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]");
+                                var item = tasks[i];
+                                var task = db.Default.Set<WCS_TASK>().Find(item.ID);
+                                var oldTaskSTATUS = task.STATUS;
+                                task.STARTTIME = DateTime.Now;
+                                task.UPDATETIME = DateTime.Now;
+                                task.STATUS = WCS.Entity.TaskStatus.堆垛机执行;
+                                task.DEVICE = obj.Entity.CODE;
+                                var fork = obj.GetFork(item, i);
+                                //获取站台及下一个地址
+                                task.GetSrmStationAndaddNext(fork);
+                                db.Default.SaveChanges();
+                                Uploader.Upload(db);
+                                var msg = "";
+                                if (fork == SrmFork.货叉1)
+                                    msg = $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}][{obj.Data.SLine_1}-{obj.Data.SCol_1}-{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]";
+                                else
+                                    msg = $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}][{obj.Data.SLine_2}-{obj.Data.SCol_2}-{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]";
+                                task.CreateStatusLog(db, msg, this.GetType());
+                                item.SRMSTATION = task.SRMSTATION;
+                                if (fork == SrmFork.货叉1) // 列数较小的放一工位
+                                {
+                                    obj.WriteTask1(item);
+                                }
+                                else if (fork == SrmFork.货叉2) //列数较大的放二工位
+                                {
+                                    obj.WriteTask2(item);
+                                }
                             }
-                        }
+                        });
                     });
-                });
 
-                #endregion 出库
-            }
+                    #endregion 出库
+                }
+            });
         }
 
         protected override bool SelectDevice(WCS_DEVICE dev)

+ 40 - 37
Projects/永冠OPP/WCS.Service/Works/Station/一楼入库.cs

@@ -27,15 +27,15 @@ namespace WCS.Service.Works.Station
             {
                 var code = dev.Entity.CODE;
                 if (dev.Data.VoucherNo != dev.Data2.VoucherNo)
-                    throw new Exception($"等待任务[{dev.Data2.Tasknum}]执行--凭证号不一致[{dev.Data.VoucherNo}][{dev.Data2.VoucherNo}]");
-                if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) throw new WarnException("无光电");
-                if (dev.Data3.Status.HasFlag(StationStatus.运行状态位)) throw new WarnException("设备运行中");
-                if (dev.Data2.Request != IstationRequest.扫码入库) throw new Exception("有光电无请求");
-                if (dev.Data2.Tasknum > 10000) throw new Exception("有光电有请求,但已生产任务");
+                    throw new WarnException($"等待任务[{dev.Data2.Tasknum}]执行--凭证号不一致[{dev.Data.VoucherNo}][{dev.Data2.VoucherNo}]");
+                if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) throw new DoException("无光电");
+                if (dev.Data3.Status.HasFlag(StationStatus.运行状态位)) throw new DoException("设备运行中");
+                if (dev.Data2.Request != IstationRequest.扫码入库) throw new WarnException("有光电无请求");
+                if (dev.Data2.Tasknum > 10000) throw new WarnException("有光电有请求,但已生产任务");
 
                 var bcr = dev.Entity.BCR();
                 var barcode = bcr.Content.Trim('\r');
-                if (barcode == "") throw new Exception("扫码失败");
+                if (barcode == "") throw new WarnException("扫码失败");
 
                 var info = WMS.I_WCS_GetInTask(barcode, dev.Entity.CODE);
                 var next = dev.Entity.CODE == Conv_1028 ? "1030" : "1031";
@@ -92,12 +92,12 @@ namespace WCS.Service.Works.Station
                 foreach (var item in obj.Items)
                 {
                     var dev = Device.Find(item.Entity.CODE).Create<StationDevice>();
-                    if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) throw new WarnException("无光电");
+                    if (!dev.Data2.Status.HasFlag(IstationStatus.光电状态)) throw new DoException("无光电");
                     if (dev.Data.VoucherNo != dev.Data2.VoucherNo)
-                        throw new Exception($"等待任务[{dev.Data2.Tasknum}]执行--凭证号不一致[{dev.Data.VoucherNo}][{dev.Data2.VoucherNo}]");
+                        throw new WarnException($"等待任务[{dev.Data2.Tasknum}]执行--凭证号不一致[{dev.Data.VoucherNo}][{dev.Data2.VoucherNo}]");
                     if (dev.Data3.Status.HasFlag(StationStatus.运行状态位)) throw new WarnException("设备运行中");
                     if (dev.Data2.Tasknum > 10000 && dev.Data2.Request != IstationRequest.请求分配目标地址)
-                        throw new Exception("有任务无请求");
+                        throw new WarnException("有任务无请求");
                 }
 
                 //获取需要进行巷道分配的设备
@@ -108,7 +108,7 @@ namespace WCS.Service.Works.Station
                     var taskIds = devs.Select(p => p.Data2.Tasknum);
                     var tasks = db.Default.Set<WCS_TASK>().Where(p => taskIds.Any(v => v == p.ID)).ToList();
                     var res = WMS.GetTunnelList(tasks.Select(v => v.WMSTASK.ToString()).ToList(), code);
-                    if (string.IsNullOrEmpty(res.TunnelNum)) throw new Exception($"WMS未返回巷道");
+                    if (string.IsNullOrEmpty(res.TunnelNum)) throw new WarnException($"WMS未返回巷道");
                     var tunnelNo = res.TunnelNum.Split(',').Select(v => "TY" + v).ToList();
 
                     var tunnels = Device.Where(v => tunnelNo.Contains(v.CODE)).ToList();
@@ -140,7 +140,7 @@ namespace WCS.Service.Works.Station
                     var tunnelInfo = tunnelInfos.Where(v => { try { return v.SRM.Data3.SCAlarm == 0 && v.SRM.Data2.SRMMode == SCMode.远程 && v.SRM.Data2.SRMStatus == SCRunStatus.空闲; } catch { return false; } })
                                                 .Where(v => !db.Default.Set<WCS_TASK>().Any(p => p.Priority > 0 && p.DEVICE == v.SRM.Entity.CODE && p.STATUS < TaskStatus.堆垛机完成))
                                                 .OrderBy(v => tunnelNo.IndexOf(v.Tunnel.CODE)).FirstOrDefault();
-                    if (tunnelInfo == null) throw new Exception("无可用巷道");
+                    if (tunnelInfo == null) throw new WarnException("无可用巷道");
 
                     //开始向设备中写入任务信息
                     foreach (var item in devs)
@@ -176,36 +176,39 @@ namespace WCS.Service.Works.Station
     {
         protected override void Do(StationDevice obj)
         {
-            var code = obj.Entity.CODE;
-            if (obj.WhetherToExecute(IstationRequest.请求分配目标地址)) return;
-
-            DB.Do(db =>
+            obj.EX(obj =>
             {
-                var task = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.ID == obj.Data2.Tasknum);
-                switch (task.ADDRFROM)
+                var code = obj.Entity.CODE;
+                if (obj.WhetherToExecute(IstationRequest.请求分配目标地址)) return;
+
+                DB.Do(db =>
                 {
-                    case "1028":
-                        break;
+                    var task = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.ID == obj.Data2.Tasknum);
+                    switch (task.ADDRFROM)
+                    {
+                        case "1028":
+                            break;
 
-                    case "1029":
-                        break;
+                        case "1029":
+                            break;
 
-                    default:
-                        break;
-                }
-                var next = obj.Entity.GetPath(task.ADDRTO);
-
-                task.ADDRNEXT = next.FirstOrDefault().CODE;
-                db.Default.SaveChanges();
-                var msg = $"下达从{obj.Data.Goodsstart}移动至{obj.Data.Goodsend}的PLC指令";
-                msg += $"[{obj.Data.Tasknum}][{obj.Data.Goodsstart}][{obj.Data.Goodsend}][{obj.Data.VoucherNo}[{obj.Data2.VoucherNo}]";
-                task.CreateStatusLog(db, msg, this.GetType());
-
-                obj.Data.Tasknum = task.ID;
-                obj.Data.Goodsstart = obj.Entity.CODE.ToShort();
-                obj.Data.Goodsend = next.FirstOrDefault().CODE.ToShort();
-                obj.Data.CmdType = IstationCmdType.分配目标地址;
-                obj.Data.VoucherNo++;
+                        default:
+                            break;
+                    }
+                    var next = obj.Entity.GetPath(task.ADDRTO);
+
+                    task.ADDRNEXT = next.FirstOrDefault().CODE;
+                    db.Default.SaveChanges();
+                    var msg = $"下达从{obj.Data.Goodsstart}移动至{obj.Data.Goodsend}的PLC指令";
+                    msg += $"[{obj.Data.Tasknum}][{obj.Data.Goodsstart}][{obj.Data.Goodsend}][{obj.Data.VoucherNo}[{obj.Data2.VoucherNo}]";
+                    task.CreateStatusLog(db, msg, this.GetType());
+
+                    obj.Data.Tasknum = task.ID;
+                    obj.Data.Goodsstart = obj.Entity.CODE.ToShort();
+                    obj.Data.Goodsend = next.FirstOrDefault().CODE.ToShort();
+                    obj.Data.CmdType = IstationCmdType.分配目标地址;
+                    obj.Data.VoucherNo++;
+                });
             });
         }
 

+ 1 - 1
Projects/永冠OPP/WCS.Service/config.json

@@ -14,7 +14,7 @@
         "INFO_SRMINFO": "Info_SRMInfo",
         "INFO_SYTASKSTATUS": "Info_SyTaskTatus",
         "INFO_WMSREQUEST": "INFO_WMSRequest",
-        "INFO_ERROR": "Info_Error"
+        "INFO_WARN": "Info_Warn"
       }
     },
     {

+ 2 - 2
WCS.Core/Device.cs

@@ -165,8 +165,8 @@ public enum DF
     SRM放货 = 1 << 3,
     一楼RGV放货 = 1 << 4,
     月台 = 1 << 5,
-    备用1 = 1 << 6,
-    备用2 = 1 << 7,
+    涂布RGV = 1 << 6,
+    拉膜RGV = 1 << 7,
     备用3 = 1 << 8,
     备用4 = 1 << 9,
     备用5 = 1 << 10,