1
pengmn
2025-05-29 f2518583da4cc3d3737986e112b92154535aea4d
1
10个文件已修改
1306 ■■■■■ 已修改文件
HH.WCS.Mobox3.HangYang/api/MoboxController.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/core/WCSCore.cs 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/models/Container.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/models/wms/Algorit.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/process/TaskProcess.cs 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/util/HttpHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/wms/ContainerHelper.cs 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/wms/LocationHelper.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/wms/WCSHelper.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/wms/WMSHelper.cs 313 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.HangYang/api/MoboxController.cs
@@ -143,8 +143,7 @@
        #region 杭氧PDA接口
        #endregion
    }
HH.WCS.Mobox3.HangYang/core/WCSCore.cs
@@ -13,64 +13,91 @@
    {
        public static void OperateAgvTaskStatus(AgvTaskState model)
        {
            var TN_Task = WCSHelper.GetTask(model.No);
            if (TN_Task != null)
            if (model == null) return;
            var task = WCSHelper.GetTask(model.No);
            if (task == null) return;
            if (model.State > 7) return;
            // 状态与操作的映射字典
            var stateActions = new Dictionary<int, Action>
            {
                if (model.State <= 7)
                {
                [1] = () => WCSHelper.Begin(task),
                [2] = () => HandleTaskCompletion(task),
                [3] = () => WCSHelper.UpdateStatus(task, "开始取货"),
                [4] = () => HandlePickCompletion(task),
                [5] = () => WCSHelper.UpdateStatus(task, "开始卸货"),
                [6] = () => HandleUnloadCompletion(task),
                [7] = () => HandleTaskFailure(task)
            };
                    //有任务号请求
                    switch (model.State)
                    {
                        case 1:
                            WCSHelper.Begin(TN_Task);
                            break;
                        #region MyRegion
                        case 3:
                            WCSHelper.UpdateStatus(TN_Task, "开始取货");
                            break;
                        case 4:
                            WCSHelper.UpdateStatus(TN_Task, "取货完成");
                            TaskProcess.OperateStatus(TN_Task, 4);
                            break;
                        case 5:
                            WCSHelper.UpdateStatus(TN_Task, "开始卸货");
                            break;
                        case 6:
                            WCSHelper.UpdateStatus(TN_Task, "卸货完成");
                            TaskProcess.OperateStatus(TN_Task, 6);
                            break;
                        #endregion
                        case 2:
                            WCSHelper.End(TN_Task);
                            //根据任务类型更新作业状态和终点
                            var taskList = Settings.CompleteTasks;
                            if (taskList.taskType.Contains(TN_Task.S_TYPE))
                            {
                                //完成作业
                                WMSHelper.UpdateWmsTask(TN_Task, 2);
                                WMSHelper.UpdateDistributionCntrState(2, 3, TN_Task.S_CNTR_CODE);
                            }
                            if (new List<string> { "料箱入库", "托盘入库" }.Contains(TN_Task.S_TYPE))
                            {
                                ContainerHelper.UpdateCntrItem(TN_Task.S_CNTR_CODE);
                            }
                            //if (WMSHelper.DeleteChange(TN_Task))
                            //{
                            //    WMSHelper.AddChange(TN_Task);
                            //}
                            break;
                        case 7:
                            TaskProcess.OperateStatus(TN_Task, 7);
                            WCSHelper.Fail(TN_Task);
                            break;
                    }
                    WCSHelper.AddActionRecord(model.No, model.State, model.ForkliftNo, model.ExtData);
                }
            if (stateActions.TryGetValue(model.State, out var action))
            {
                action.Invoke();
                WCSHelper.AddActionRecord(model.No, model.State, model.ForkliftNo, model.ExtData);
            }
        }
        // 处理任务完成逻辑
        private static void HandleTaskCompletion(WCSTask task)
        {
            WCSHelper.End(task);
            // 根据任务类型处理不同的完成逻辑
            if (Settings.CompleteTasks.taskType.Contains(task.S_TYPE))
            {
                WMSHelper.UpdateWmsTask(task, 2);
                WMSHelper.UpdateDistributionCntrState(2, 3, task.S_CNTR_CODE);
            }
            if (new List<string> { "料箱入库", "托盘入库" }.Contains(task.S_TYPE))
            {
                ContainerHelper.UpdateCntrItem(task.S_CNTR_CODE);
            }
            // 处理区域变更
            HandleAreaChange(task);
        }
        // 处理取货完成逻辑
        private static void HandlePickCompletion(WCSTask task)
        {
            WCSHelper.UpdateStatus(task, "取货完成");
            TaskProcess.OperateStatus(task, 4);
        }
        // 处理卸货完成逻辑
        private static void HandleUnloadCompletion(WCSTask task)
        {
            WCSHelper.UpdateStatus(task, "卸货完成");
            TaskProcess.OperateStatus(task, 6);
        }
        // 处理任务失败逻辑
        private static void HandleTaskFailure(WCSTask task)
        {
            TaskProcess.OperateStatus(task, 7);
            WCSHelper.Fail(task);
        }
        // 处理区域变更逻辑
        private static void HandleAreaChange(WCSTask task)
        {
            var areas = new List<string> { "TPLKQ", "LXLKQ" };
            if (areas.Contains(task.S_START_AREA))
            {
                WMSHelper.DeleteChange(task);
            }
            if (areas.Contains(task.S_END_AREA))
            {
                WMSHelper.AddChange(task);
            }
        }
        /// <summary>
        /// 任务分发,根据调度类型发给不同的调度系统
@@ -104,11 +131,10 @@
                var list = WMSHelper.GetWmsTaskListByState("等待");
                if (list.Count > 0)
                {
                    list.ForEach(task =>
                    list.ForEach(async task =>
                    {
                        //生成入库任务
                        TaskProcess.CreateInTask(task);
                        await TaskProcess.CreateInTask(task);
                    });
                }
                //查询任务
@@ -118,7 +144,7 @@
                {
                    exelist.ForEach(task =>
                    {
                        //生成入库任务
                        //生成从分拣暂存区到集货托盘位的任务任务
                        TaskProcess.exeCreateInTask(task);
                    });
                }
HH.WCS.Mobox3.HangYang/models/Container.cs
@@ -12,11 +12,11 @@
        public string S_TYPE { get; set; }
        public string S_SPEC { get; set; }
        public float F_WEIGHT { get; set; }
        public float F_LOAD_WEIGHT { get; set; }
        //public float F_LOAD_WEIGHT { get; set; }
        public float F_MAX_WEIGHT { get; set; }
        public int N_LENGTH { get; set; }
        public int N_WIDTH { get; set; }
        public int N_HEIGHT { get; set; }
        //public int N_LENGTH { get; set; }
        //public int N_WIDTH { get; set; }
        //public int N_HEIGHT { get; set; }
        public string C_IS_VIRTUAL { get; set; } = "N";
        public int N_TYPE { get; set; }
        public string C_ENABLE { get; set; } = "Y";
@@ -31,8 +31,8 @@
        /// <summary>
        /// 码盘时候标记
        /// </summary>
        public string S_SRC { get; internal set; }
        public string S_DEST { get; internal set; }
        //public string S_SRC { get; internal set; }
        //public string S_DEST { get; internal set; }
        [SugarColumn(IsIgnore = true)]
HH.WCS.Mobox3.HangYang/models/wms/Algorit.cs
@@ -26,8 +26,6 @@
    /// </summary>
    public class Outbound
    {
        /// <summary>
        /// 库区
        /// </summary>
@@ -57,6 +55,11 @@
        /// 作业任务号
        /// </summary>
        public string opCode { get; set; }
        /// <summary>
        /// 呼叫空托数
        /// </summary>
        public int requiredCount { get; set; }
    }
    public class LocationParams
HH.WCS.Mobox3.HangYang/process/TaskProcess.cs
@@ -924,12 +924,12 @@
        /// </summary>
        /// <param name="mst"></param>
        /// <returns></returns>
        internal static bool CreateInTask(WMSTask mst)
        internal static async Task<bool> CreateInTask(WMSTask mst)
        {
            try
            {
                if (mst.S_B_STATE.Trim() != "等待") return true;
                if (string.IsNullOrEmpty(mst.S_START_LOC)) return false;
                //if (string.IsNullOrEmpty(mst.S_START_LOC)) return false;
                var reservoirs = Settings.ReservoirAreas?.ToList();
                if (reservoirs == null || !reservoirs.Any())
@@ -947,7 +947,13 @@
                    case "合托回库":
                        return HandleMergeReturn(mst, reservoirs);
                    case "分拣回库":
                        return HandleMergeReturn(mst, reservoirs);
                        return await SortingReturn(mst, reservoirs);
                    case "解绑回库":
                        return await UnbindReturn(mst, reservoirs);
                    case "空托回库":
                        return await EmptyPalletReturn(mst, reservoirs);
                    case "空托出库":
                        return EmptyPalletOutbound(mst);
                    case "料箱出库":
                        return HandleBoxOutbound(mst, reservoirs);
                    case "发货暂存":
@@ -1135,7 +1141,7 @@
        }
        /// <summary>
        /// 合托回库 || 分拣回库
        /// 合托回库
        /// </summary>
        /// <param name="mst"></param>
        /// <param name="reservoirs"></param>
@@ -1237,6 +1243,218 @@
                }
            }
            return true;
        }
        /// <summary>
        /// 分拣回库
        /// </summary>
        /// <param name="mst"></param>
        /// <param name="reservoirs"></param>
        /// <returns></returns>
        private static async Task<bool> SortingReturn(WMSTask mst, List<ReservoirArea> reservoirs)
        {
            var trayLst = ContainerHelper.GetCntr(mst.S_CNTR_CODE);
            if (trayLst != null && trayLst.S_TYPE.Equals("托盘"))
            {
                //托盘分拣回库
                var area = reservoirs.Where(s => s.areaName == "入库接驳位").FirstOrDefault();
                if (area == null)
                {
                    LogHelper.Info("Settings出现错误未查询到入库接驳位!", "杭氧");
                    return false;
                }
                //(2.1)先查询入库接驳位是否为空,如果为空直接生成到入库的任务
                var anyLoc = LocationHelper.GetLocAreaList(area.areaCode);
                if (anyLoc.Any())
                {
                    //生成到接驳位的任务
                    var res = TaskProcess.HYCreateTransport(mst.S_START_LOC, anyLoc.FirstOrDefault().S_CODE, "托盘分拣回库", mst.S_CNTR_CODE, mst.S_CODE);
                    if (!res)
                    {
                        LogHelper.Info("托盘分拣回库任务创建失败!", "杭氧");
                        return false;
                    }
                    WMSHelper.UpdateStatus(mst, 1);
                }
            }
            else
            {
                //料箱回库
                var inbound = new Inbound()
                {
                    areaCode = "LXLKQ"
                };
                var wh = new Warehouse(inbound);
                var stored = await wh.StoreItemAsync();
                if (stored == null)
                {
                    LogHelper.Info($"未查询到{inbound.areaCode}可用货位!", "杭氧");
                    return false;
                }
                var res = TaskProcess.HYCreateTransport(mst.S_START_LOC, stored.loationCode, "料箱分拣回库" , mst.S_CNTR_CODE, mst.S_CODE);
                if (!res)
                {
                    LogHelper.Info("料箱分拣回库任务创建失败!", "杭氧");
                    return false;
                }
                WMSHelper.UpdateStatus(mst, 1);
            }
            return true;
        }
        /// <summary>
        /// 解绑回库
        /// </summary>
        /// <param name="mst"></param>
        /// <param name="reservoirs"></param>
        /// <returns></returns>
        private static async Task<bool> UnbindReturn(WMSTask mst, List<ReservoirArea> reservoirs)
        {
            var trayLst = ContainerHelper.GetCntr(mst.S_CNTR_CODE);
            if (trayLst != null && trayLst.S_TYPE.Equals("托盘"))
            {
                //托盘分拣回库
                var area = reservoirs.Where(s => s.areaName == "入库接驳位").FirstOrDefault();
                if (area == null)
                {
                    LogHelper.Info("Settings出现错误未查询到入库接驳位!", "杭氧");
                    return false;
                }
                //(2.1)先查询入库接驳位是否为空,如果为空直接生成到入库的任务
                var anyLoc = LocationHelper.GetLocAreaList(area.areaCode);
                if (anyLoc.Any())
                {
                    //生成到接驳位的任务
                    var res = TaskProcess.HYCreateTransport(mst.S_START_LOC, anyLoc.FirstOrDefault().S_CODE, "托盘解绑回库", mst.S_CNTR_CODE, mst.S_CODE);
                    if (!res)
                    {
                        LogHelper.Info("托盘解绑回库任务创建失败!", "杭氧");
                        return false;
                    }
                    WMSHelper.UpdateStatus(mst, 1);
                }
            }
            else
            {
                //料箱回库
                var inbound = new Inbound()
                {
                    areaCode = "LXLKQ"
                };
                var wh = new Warehouse(inbound);
                var stored = await wh.StoreItemAsync();
                if (stored == null)
                {
                    LogHelper.Info($"未查询到{inbound.areaCode}可用货位!", "杭氧");
                    return false;
                }
                var res = TaskProcess.HYCreateTransport(mst.S_START_LOC, stored.loationCode, "料箱解绑回库", mst.S_CNTR_CODE, mst.S_CODE);
                if (!res)
                {
                    LogHelper.Info("料箱解绑回库任务创建失败!", "杭氧");
                    return false;
                }
                WMSHelper.UpdateStatus(mst, 1);
            }
            return true;
        }
        /// <summary>
        /// 空托回库
        /// </summary>
        /// <param name="mst"></param>
        /// <param name="reservoirs"></param>
        /// <returns></returns>
        private static async Task<bool> EmptyPalletReturn(WMSTask mst, List<ReservoirArea> reservoirs)
        {
            var trayLst = ContainerHelper.GetCntr(mst.S_CNTR_CODE);
            if (trayLst != null && trayLst.S_TYPE.Equals("托盘"))
            {
                //托盘空托回库
                var area = reservoirs.Where(s => s.areaName == "入库接驳位").FirstOrDefault();
                if (area == null)
                {
                    LogHelper.Info("Settings出现错误未查询到入库接驳位!", "杭氧");
                    return false;
                }
                //(2.1)先查询入库接驳位是否为空,如果为空直接生成到入库的任务
                var anyLoc = LocationHelper.GetLocAreaList(area.areaCode);
                if (anyLoc.Any())
                {
                    //生成到接驳位的任务
                    var res = TaskProcess.HYCreateTransport(mst.S_START_LOC, anyLoc.FirstOrDefault().S_CODE, "托盘空托回库", mst.S_CNTR_CODE, mst.S_CODE);
                    if (!res)
                    {
                        LogHelper.Info("托盘空托回库任务创建失败!", "杭氧");
                        return false;
                    }
                    WMSHelper.UpdateStatus(mst, 1);
                }
            }
            else
            {
                //料箱空托回库
                var inbound = new Inbound()
                {
                    areaCode = "LXLKQ"
                };
                var wh = new Warehouse(inbound);
                var stored = await wh.StoreItemAsync();
                if (stored == null)
                {
                    LogHelper.Info($"未查询到{inbound.areaCode}可用货位!", "杭氧");
                    return false;
                }
                var res = TaskProcess.HYCreateTransport(mst.S_START_LOC, stored.loationCode, "料箱空托回库", mst.S_CNTR_CODE, mst.S_CODE);
                if (!res)
                {
                    LogHelper.Info("料箱空托回库任务创建失败!", "杭氧");
                    return false;
                }
                WMSHelper.UpdateStatus(mst, 1);
            }
            return true;
        }
        /// <summary>
        /// 空托出库
        /// </summary>
        /// <param name="mst"></param>
        /// <param name="reservoirs"></param>
        /// <returns></returns>
        private static bool EmptyPalletOutbound(WMSTask mst)
        {
            var result = true;
            var scheduler = new EmptyPalletOutboundScheduler(mst.S_START_AREA);
            var outbound = new Outbound
            {
                endArea = mst.S_END_AREA,
                endBit = mst.S_END_LOC,
                requiredCount = 1,
                taskType = "空托出库"
            };
            // 请求出库
            var tasks = scheduler.GenerateEmptyPalletTasks(outbound);
            foreach (var item in tasks)
            {
                // 创建出库任务
                var res = TaskProcess.HYCreateTransport(item.S_START_LOC, item.S_END_LOC, item.S_TYPE, item.S_CNTR_CODE, mst.S_CODE);
                mst.S_START_LOC = item.S_START_LOC;
                mst.S_CNTR_CODE  = item.S_CNTR_CODE;
                //修改空托出库起点和托盘码
                UpdateTask(mst,1);
                if (!res)
                {
                    LogHelper.Info($"根据配盘单生成出库任务创建出库任务失败!!");
                    return false;
                }
            }
            return result;
        }
        /// <summary>
@@ -1370,13 +1588,17 @@
            if (locList.Any())
            {
                var startLoc = WMSHelper.GetCntrLoc(mst.S_CNTR_CODE);
                // 创建出库任务
                var res = TaskProcess.HYCreateTransport(startLoc.S_LOC_CODE, locList.FirstOrDefault().S_CODE, mst.S_TYPE, mst.S_CNTR_CODE, mst.S_CODE);
                if (!res)
                if (startLoc != null)
                {
                    LogHelper.Info($"根据配盘单生成出库任务创建出库任务失败!!");
                    return false;
                    // 创建出库任务
                    var res = TaskProcess.HYCreateTransport(startLoc.S_LOC_CODE, locList.FirstOrDefault().S_CODE, mst.S_TYPE, mst.S_CNTR_CODE, mst.S_CODE);
                    if (!res)
                    {
                        LogHelper.Info($"根据配盘单生成出库任务创建出库任务失败!!");
                        return false;
                    }
                }
            }
            return true;
@@ -1595,13 +1817,17 @@
                    if (list == null)
                    {
                        list = WMSHelper.GetWmsTaskList("执行", item.cntrNo);
                        if (list != null && list.S_TYPE.Contains("回库"))
                        {
                            list.S_END_AREA = "TPLKQ";
                        }
                    }
                    if (list == null)
                    {
                        result.errMsg = "未查询到在等待中的作业!";
                        return result;
                    }
                    var inbound = new Inbound()
                    {
                        areaCode = list.S_END_AREA
HH.WCS.Mobox3.HangYang/util/HttpHelper.cs
@@ -55,7 +55,7 @@
        #endregion
        #region WebHelper
        public string WebPost(string url, string postData, string cotentType = "application/json")
        public string WebHttpPost(string url, string postData, string cotentType = "application/json")
        {
            Console.WriteLine(url);
            WebRequest request = WebRequest.Create(url);
HH.WCS.Mobox3.HangYang/wms/ContainerHelper.cs
@@ -21,160 +21,7 @@
            var date = DateTime.Now.ToString("yyMMdd");
            return $"TP{date}{id.ToString().PadLeft(4, '0')}";
        }
        /// <summary>
        /// 根据容器类型、目的地、状态查询容器
        /// </summary>
        /// <param name="dest"></param>
        /// <param name="cntrType"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        internal static List<Container> GetCntrListByPurpose(string dest, string cntrType, int state)
        {
            //1.0 查货位容器表
            var db = new SqlHelper<object>().GetInstance();
            var list = db.Queryable<Container>().Where(a => a.S_DEST == dest && a.S_TYPE == cntrType && a.N_B_STATE == state).ToList();
            return list;
        }
        /// <summary>
        /// 创建托盘物料绑定关系
        /// </summary>
        /// <param name="loc"></param>
        /// <param name="cntr"></param>
        /// <param name="itemcode"></param>
        /// <returns></returns>
        internal static bool CreateCntrItem(string loc, string cntr, string itemcode, string itemname, string itemtype, string cntrtype, string batch, int weight, string unit)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                var location = db.Queryable<Location>().Where(a => a.S_CODE == loc).First();
                if (location != null)
                {
                    LogHelper.Info($"托盘{cntr}:添加货位{loc}绑定关系,添加容器货品表");
                    db.BeginTran();
                    var con = db.Queryable<Container>().Where(a => a.S_CODE.Trim() == cntr).First();
                    if (con == null)
                    {
                        var container = new Container { S_CODE = cntr, S_TYPE = cntrtype };
                        db.Insertable<Container>(container).ExecuteCommand();
                    }
                    var cntritem = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE.Trim() == cntr).First();
                    if (cntritem == null)
                    {
                        var cir = new CntrItemDetail { S_CNTR_CODE = cntr, S_ITEM_CODE = itemcode, S_ITEM_NAME = itemname, S_ITEM_SPEC = itemtype, S_WU = unit, F_NET_WEIGHT = weight, S_BATCH_NO = batch };
                        db.Insertable<CntrItemDetail>(cir).ExecuteCommand();
                    }
                    var loctp = new LocCntrRel { S_LOC_CODE = loc, S_CNTR_CODE = cntr };
                    db.Insertable<LocCntrRel>(loctp).ExecuteCommand();
                    location.N_CURRENT_NUM = location.N_CURRENT_NUM + 1;
                    db.Updateable(location).UpdateColumns(it => new { it.N_CURRENT_NUM }).ExecuteCommand();
                    db.Ado.CommitTran();
                    res = true;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Info($"CreateCntrItem => erro:托盘{cntr}添加失败" + ex.Message.ToString());
                db.Ado.RollbackTran();
            }
            return res;
        }
        /// <summary>
        /// 创建托盘物料绑定关系
        /// </summary>
        /// <param name="loc"></param>
        /// <param name="cntr"></param>
        /// <param name="itemcode"></param>
        /// <returns></returns>
        internal static bool CreateCntrItem(string cntr, string itemcode, string itemname, string batch, string weight)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                LogHelper.Info($"托盘{cntr}:添加物料{itemcode}绑定关系");
                db.BeginTran();
                var cntritem = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE.Trim() == cntr).First();
                if (cntritem == null)
                {
                    var cir = new CntrItemDetail { S_CNTR_CODE = cntr, S_ITEM_CODE = itemcode, S_ITEM_NAME = itemname, F_NET_WEIGHT = float.Parse(weight), S_BATCH_NO = batch };
                    db.Insertable<CntrItemDetail>(cir).ExecuteCommand();
                }
                else
                {
                    cntritem.S_ITEM_CODE = itemcode;
                    cntritem.S_ITEM_NAME = itemname;
                    cntritem.F_NET_WEIGHT = float.Parse(weight);
                    cntritem.S_BATCH_NO = batch;
                    db.Updateable<CntrItemDetail>(cntritem).ExecuteCommand();
                }
                var con = db.Queryable<Container>().Where(a => a.S_CODE.Trim() == cntr).First();
                if (con == null)
                {
                    var container = new Container { S_CODE = cntr };
                    db.Insertable<Container>(container).ExecuteCommand();
                }
                db.Ado.CommitTran();
                res = true;
            }
            catch (Exception ex)
            {
                LogHelper.Info($"CreateCntrItem => erro:托盘{cntr}添加失败" + ex.Message.ToString());
                db.Ado.RollbackTran();
            }
            return res;
        }
        /// <summary>
        /// 判断容器是否有物料信息
        /// </summary>
        /// <param name="cntr"></param>
        /// <returns></returns>
        internal static bool CheckEmpty(string cntr)
        {
            //1.0 查货位容器表
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<LocCntrRel>().Count(a => a.S_LOC_CODE.Trim() == cntr) == 0;
        }
        internal static bool AddCntr(string cntrCode, string itemCode)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            var TN_Container = new Container { S_CODE = cntrCode };
            var cntrItemRel = new CntrItemDetail { S_CNTR_CODE = cntrCode, S_ITEM_CODE = itemCode };
            try
            {
                db.BeginTran();
                db.Insertable<Container>(TN_Container).ExecuteCommand();
                db.Insertable<CntrItemDetail>(cntrItemRel).ExecuteCommand();
                db.CommitTran();
                res = true;
            }
            catch (Exception ex)
            {
                db.RollbackTran();
            }
            return res;
        }
        /// <summary>
        /// 根据容器号获取容器信息
@@ -208,335 +55,6 @@
            var db = new SqlHelper<object>().GetInstance();
            var list = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE.Trim() == cntr).ToList();
            return list;
        }
        /// <summary>
        /// 根据物料获取容器信息
        /// </summary>
        /// <param name="cntr"></param>
        /// <returns></returns>
        internal static List<CntrItemDetail> GetItemCntrRel(string itemcode)
        {
            var db = new SqlHelper<object>().GetInstance();
            var list = db.Queryable<CntrItemDetail>().Where(a => a.S_ITEM_CODE.Trim() == itemcode.Trim()).ToList();
            return list;
        }
        /// <summary>
        /// 物料信息绑定到满容器上
        /// </summary>
        /// <param name="cntrCode"></param>
        /// <param name="itemCode"></param>
        /// <param name="batchNo"></param>
        /// <param name="qty"></param>
        /// <param name="purpose">容器用途,用于哪个线边还是目的点</param>
        /// <returns></returns>
        internal static bool BindCntrItemSingle(Container cntr, string itemCode, string batchNo, float qty)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                db.BeginTran();
                db.Updateable(cntr).UpdateColumns(it => new { it.S_DEST }).ExecuteCommand();
                //1.将原有容器物料信息删除
                db.Deleteable<CntrItemDetail>().Where(it => it.S_CNTR_CODE == cntr.S_CODE.Trim()).ExecuteCommand();
                //2.插入新的容器物料信息(容器号不变)
                var cir = new CntrItemDetail { S_CNTR_CODE = cntr.S_CODE.Trim(), S_BATCH_NO = batchNo, F_QTY = qty, S_ITEM_CODE = itemCode };
                db.Insertable<CntrItemDetail>(cir).ExecuteCommand();
                db.CommitTran();
                res = true;
            }
            catch (Exception ex)
            {
                db.RollbackTran();
            }
            return res;
        }
        /// <summary>
        /// 根据容器来源和状态获取托盘
        /// </summary>
        /// <param name="src"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        internal static List<Container> GetCntr(string dest, int state, string cntrType = "")
        {
            var db = new SqlHelper<object>().GetInstance();
            if (cntrType == "")
            {
                return db.Queryable<Container>().Where(a => a.S_DEST == dest && a.N_B_STATE == state).ToList();
            }
            else
            {
                return db.Queryable<Container>().Where(a => a.S_DEST == dest && a.N_B_STATE == state && a.S_TYPE == cntrType).ToList();
            }
        }
        internal static bool UpdateCntr(List<string> cntrs, string dest, int state)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            var models = db.Queryable<Container>().Where(a => cntrs.Contains(a.S_CODE)).ToList();
            if (models.Count > 0)
            {
                models.ForEach(a =>
                {
                    a.S_DEST = dest; a.N_B_STATE = state;
                    db.Updateable(a).UpdateColumns(it => new { it.S_DEST, it.N_B_STATE }).ExecuteCommand();
                });
                res = true;
            }
            return res;
        }
        internal static bool UpdateCntrDest(List<string> cntrs, string dest)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            var models = db.Queryable<Container>().Where(a => cntrs.Contains(a.S_CODE)).ToList();
            if (models.Count > 0)
            {
                models.ForEach(a =>
                {
                    a.S_DEST = dest;
                    db.Updateable(a).UpdateColumns(it => new { it.S_DEST }).ExecuteCommand();
                });
                res = true;
            }
            return res;
        }
        /// <summary>
        /// 更新托盘来源
        /// </summary>
        /// <param name="cntr"></param>
        /// <param name="src"></param>
        /// <returns></returns>
        internal static bool UpdateCntrSrc(string cntr, string src)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            var model = db.Queryable<Container>().Where(a => a.S_CODE == cntr).First();
            if (model != null)
            {
                model.S_SRC = src;
                model.T_MODIFY = DateTime.Now;
                res = db.Updateable(model).UpdateColumns(it => new { it.S_SRC, it.T_MODIFY }).ExecuteCommand() > 0;
            }
            return res;
        }
        internal static bool UpdateCntrState(List<string> cntrs, int state)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            var models = db.Queryable<Container>().Where(a => cntrs.Contains(a.S_CODE)).ToList();
            if (models.Count > 0)
            {
                models.ForEach(a =>
                {
                    a.N_B_STATE = state;
                    db.Updateable(a).UpdateColumns(it => new { it.N_B_STATE }).ExecuteCommand();
                });
                res = true;
            }
            return res;
        }
        internal static bool UpdateCntr(List<string> cntrs, string src, string dest, int state)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            var models = db.Queryable<Container>().Where(a => cntrs.Contains(a.S_CODE)).ToList();
            if (models.Count > 0)
            {
                models.ForEach(a =>
                {
                    a.S_DEST = dest; a.N_B_STATE = state; a.S_SRC = src;
                    db.Updateable(a).UpdateColumns(it => new { it.S_DEST, it.N_B_STATE, it.S_SRC }).ExecuteCommand();
                });
                res = true;
            }
            return res;
        }
        public static bool ClearCntrInfo(string cntr)
        {
            var db = new SqlHelper<object>().GetInstance();
            var model = db.Queryable<Container>().Where(a => a.S_CODE == cntr).First();
            if (model != null)
            {
                model.S_SRC = "";
                model.S_DEST = "";
                model.N_B_STATE = 0;
                model.T_MODIFY = DateTime.Now;
            }
            db.Updateable(model).UpdateColumns(it => new { it.S_SRC, it.S_DEST, it.N_B_STATE, it.T_MODIFY }).ExecuteCommand();
            return db.Deleteable<CntrItemDetail>().Where(a => a.S_CNTR_CODE.Trim() == cntr.Trim()).ExecuteCommand() > 0;
        }
        internal static List<Container> GetCntrBySrc(string src, int state, string cntrType = "")
        {
            var db = new SqlHelper<object>().GetInstance();
            if (cntrType == "")
            {
                return db.Queryable<Container>().Where(a => a.S_SRC == src && a.N_B_STATE == state).ToList();
            }
            else
            {
                return db.Queryable<Container>().Where(a => a.S_SRC == src && a.N_B_STATE == state && a.S_TYPE == cntrType).ToList();
            }
        }
        /// <summary>
        /// enable 让托盘允许被出库计算到,同时增加量表数据
        /// </summary>
        /// <param name="cntr"></param>
        internal static void Enable(string cntr, string loc)
        {
            var db = new SqlHelper<object>().GetInstance();
            var cntrInfo = db.Queryable<Container>().Where(a => a.S_CODE == cntr).First();
            //获取仓库量表
            //获取物理库区
            //获取逻辑库区
            if (cntrInfo != null)
            {
                try
                {
                    db.BeginTran();
                    //防止接口重复调用,量表重复增加
                    if (cntrInfo.C_ENABLE == "N")
                    {
                        cntrInfo.C_ENABLE = "Y";
                        db.Updateable(cntrInfo).UpdateColumns(a => new { a.C_ENABLE, a.T_MODIFY }).ExecuteCommand();
                        var cirList = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE == cntr).ToList();
                        if (cirList.Count > 0)
                        {
                            cirList.ForEach(a =>
                            {
                                var wh = db.Queryable<WHInventory>().Where(b => b.S_ITEM_CODE == a.S_ITEM_CODE).First();
                                if (wh != null)
                                {
                                    //更新仓库量表
                                    wh.F_QTY += a.F_QTY;
                                    wh.T_MODIFY = DateTime.Now;
                                    db.Updateable(wh).UpdateColumns(it => new { it.F_QTY, it.T_MODIFY }).ExecuteCommand();
                                }
                                else
                                {
                                    //新增仓库量表
                                    wh = new WHInventory { F_QTY = a.F_QTY, S_ITEM_CODE = a.S_ITEM_CODE };
                                    db.Insertable(wh).ExecuteCommand();
                                }
                                //写入第三方中间表
                                //如果要统计分拣中,分拣回的量,无法跟踪托盘,除非对托盘加标识,属于哪个库区。
                                //另外分拣回可能去别的巷道,别的逻辑库区,逻辑库区的量控制更复杂,不能计算分拣中和分拣回。所以库区量表本项目暂不考虑
                                /*
                                //获取货位的物理库区和所有逻辑库区
                                var location = db.Queryable<Location>().Where(l => l.S_CODE == loc).First();
                                if (location != null) {
                                    var az = db.Queryable<AZInventory>().Where(b => b.S_ITEM_CODE == a.S_ITEM_CODE && b.S_AREA_CODE == location.S_AREA_CODE).First();
                                    if (az != null) {
                                        //更新库区量表
                                        az.F_QTY += a.F_QTY;
                                        az.T_MODIFY = DateTime.Now;
                                        db.Updateable(az).UpdateColumns(it => new { it.F_QTY, it.T_MODIFY }).ExecuteCommand();
                                    }
                                    else {
                                        //新增库区量表
                                        az = new AZInventory { F_QTY = a.F_QTY, S_ITEM_CODE = a.S_ITEM_CODE, S_AREA_CODE = location.S_AREA_CODE };
                                        db.Insertable(az).ExecuteCommand();
                                    }
                                }
                                //逻辑库区的量表
                                var zoneList = db.Queryable<ZoneLoc>().Where(l => l.S_LOC_CODE == loc).ToList();
                                if (zoneList.Count > 0) {
                                    zoneList.ForEach(z => {
                                        var az = db.Queryable<AZInventory>().Where(b => b.S_ITEM_CODE == a.S_ITEM_CODE && b.S_AREA_CODE == z.S_ZONE_CODE).First();
                                        if (az != null) {
                                            //更新库区量表
                                            az.F_QTY += a.F_QTY;
                                            az.T_MODIFY = DateTime.Now;
                                            db.Updateable(az).UpdateColumns(it => new { it.F_QTY, it.T_MODIFY }).ExecuteCommand();
                                        }
                                        else {
                                            //新增库区量表
                                            az = new AZInventory { F_QTY = a.F_QTY, S_ITEM_CODE = a.S_ITEM_CODE, S_AREA_CODE = z.S_ZONE_CODE, C_IS_LOGIC_AREA = "Y" };
                                            db.Insertable(az).ExecuteCommand();
                                        }
                                    });
                                }
                                */
                            });
                        }
                    }
                    db.CommitTran();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    db.RollbackTran();
                }
            }
        }
        /// <summary>
        /// 绑定货位容器表
        /// </summary>
        /// <param name="cntr"></param>
        /// <returns></returns>
        internal static bool BindLocCntrs(string loc, string cntr, string itemCode, string itemName)
        {
            bool result = true;
            List<string> list = new List<string>(cntr.Split(','));
            var db = new SqlHelper<object>().GetInstance();
            for (int i = 0; i < list.Count; i++)
            {
                if (!string.IsNullOrEmpty(list[i]))
                {
                    string cntrCode = list[i];
                    if (db.Queryable<LocCntrRel>().Count(a => a.S_CNTR_CODE.Trim() == cntrCode) == 0)
                    {
                        var cir = new LocCntrRel { S_LOC_CODE = loc, S_CNTR_CODE = cntrCode };
                        var con = new Container { S_CODE = cntrCode,N_DETAIL_COUNT = 1 };
                        db.Insertable<LocCntrRel>(cir).ExecuteCommand();
                        db.Insertable<Container>(con).ExecuteCommand();
                        if (!string.IsNullOrEmpty(itemCode))
                        {
                            ContainerHelper.BindCntrItem(cntrCode, itemCode, itemName);
                        }
                    }
                }
            }
            //1.0 查货位容器表
            return result;
        }
        /// <summary>
        /// 绑定容器物料表
        /// </summary>
        /// <param name="itemCode"></param>
        /// <param name="batchNo"></param>
        /// <param name="qty"></param>
        /// <returns></returns>
        internal static bool BindCntrItem(string trayCode, string itemCode, string itemName)
        {
            var res = false;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                db.BeginTran();
                var cir = new CntrItemDetail { S_CNTR_CODE = trayCode, S_ITEM_CODE = itemCode, S_ITEM_NAME = itemName };
                db.Insertable<CntrItemDetail>(cir).ExecuteCommand();
                db.Ado.CommitTran();
                res = true;
            }
            catch (Exception ex)
            {
                db.Ado.RollbackTran();
            }
            return res;
        }
        #region 杭氧货位容器物料帮助方法
@@ -593,9 +111,9 @@
        {
            var db = new SqlHelper<object>().GetInstance();
            var model = db.Queryable<Location>().LeftJoin<LocCntrRel>((p, m) => p.S_CODE == m.S_LOC_CODE)
                .Where((p,m)=>p.S_AREA_CODE == areaCode && p.S_LOCK_STATE == "无")
                .Where((p,m)=>m.S_ACTION_SRC == abouts)
                .Select((p,m)=>m)
                .Where((p, m) => p.S_AREA_CODE == areaCode && p.S_LOCK_STATE == "无")
                .Where((p, m) => m.S_ACTION_SRC == abouts)
                .Select((p, m) => m)
                .ToList();
            return model;
        }
@@ -603,10 +121,30 @@
        internal static LocCntrRel GetCntrLoc(string trayCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            var model = db.Queryable<LocCntrRel>().Where(s=>s.S_CNTR_CODE == trayCode).First();
            var model = db.Queryable<LocCntrRel>().Where(s => s.S_CNTR_CODE == trayCode).First();
            return model;
        }
        internal static LocCntrRel GetLocCntr(string loc)
        {
            var db = new SqlHelper<object>().GetInstance();
            var model = db.Queryable<LocCntrRel>().Where(s => s.S_LOC_CODE == loc).First();
            return model;
        }
        internal static bool GetLocItemRel(string loc)
        {
            bool result = false;
            var db = new SqlHelper<object>().GetInstance();
            var model = db.Queryable<LocCntrRel>().Where(s => s.S_LOC_CODE == loc).First();
            if (model != null)
            {
                var list = db.Queryable<CntrItemDetail>().Where(a => a.S_CNTR_CODE.Trim() == model.S_CNTR_CODE).ToList();
                result = list.Any() ? false : true;
            }
            return result;
        }
        #endregion
HH.WCS.Mobox3.HangYang/wms/LocationHelper.cs
@@ -460,15 +460,6 @@
            return db.Queryable<ZoneLoc>().Where(a => a.S_LOC_CODE == loc).ToList();
        }
        internal static void Test()
        {
            //多查询一次也是可以的,先查出可用的货位组,然后选择货位组中列比较大的,或者列比较小的
            var availableRowGroups = new List<Location>().GroupBy(l => l.N_ROW_GROUP).Where(g => !g.Any(l => l.N_LOCK_STATE != 0)).Select(g => g.Key);
            var db = new SqlHelper<object>().GetInstance();
            //db.Queryable<Location>().Where(a => a.S_AREA_CODE == "11").Where(a => SqlFunc.Subqueryable<Location>().Where(b => b.)).GroupBy(z => z.N_ROW_GROUP).ToList();
        }
        #region 杭氧货位帮助Helper
HH.WCS.Mobox3.HangYang/wms/WCSHelper.cs
@@ -44,16 +44,7 @@
            db.Updateable(task).UpdateColumns(it => new { it.S_EQ_TASK_CODE, it.T_MODIFY }).ExecuteCommand();
            return res;
        }
        internal static bool UpdateInfo(WCSTask task, string sourceNo, string endBit, string status)
        {
            var res = false;
            var db = new SqlHelper<WCSTask>().GetInstance();
            task.S_B_STATE = status;
            task.S_OP_CODE = sourceNo;
            task.S_END_LOC = endBit;
            db.Updateable(task).UpdateColumns(it => new { it.S_B_STATE, it.S_OP_CODE, it.S_END_LOC }).ExecuteCommand();
            return res;
        }
        internal static WCSTask GetTask(string no)
        {
            var db = new SqlHelper<WCSTask>().GetInstance();
@@ -62,35 +53,8 @@
        }
        internal static List<WCSTask> GetTaskBycntrcode(string no)
        {
            var db = new SqlHelper<WCSTask>().GetInstance();
            var task = db.Queryable<WCSTask>().Where(a => a.S_CNTR_CODE.Trim() == no && a.S_B_STATE.Trim() == "完成").ToList();
            return task;
        }
        internal static WCSTask GetTaskBySrcNo(string no)
        {
            var db = new SqlHelper<WCSTask>().GetInstance();
            var task = db.Queryable<WCSTask>().Where(a => a.S_OP_CODE == no).First();
            return task;
        }
        internal static List<WCSTask> GetTaskByStart(string bit)
        {
            var db = new SqlHelper<WCSTask>().GetInstance();
            var task = db.Queryable<WCSTask>().Where(a => a.S_START_LOC == bit).ToList();
            return task;
        }
        internal static List<WCSTask> GetTaskByEnd(string bit)
        {
            var db = new SqlHelper<WCSTask>().GetInstance();
            var task = db.Queryable<WCSTask>().Where(a => a.S_END_LOC == bit).ToList();
            return task;
        }
        internal static List<WCSTask> GetTaskByType(string taskType)
        {
            var db = new SqlHelper<WCSTask>().GetInstance();
            return db.Queryable<WCSTask>().Where(a => a.S_TYPE == taskType).ToList();
        }
        internal static bool CreateTask(string no, string from, string to, string taskType, int pri, string cntrInfo, int cntrCount = 1, int startLayer = 1, int endLayer = 1)
        {
            var whCode = Settings.WHCode;
@@ -142,10 +106,7 @@
            };
            return CreateTask(TN_Task);
        }
        internal static bool CheckExist(string no)
        {
            return GetTask(no) != null;
        }
        internal static bool UpdateStatus(string no, int state)
        {
            var res = false;
@@ -237,20 +198,5 @@
            return db.Queryable<WCSTask>().Where(a => a.S_B_STATE.Trim() == status).OrderBy(s => s.T_CREATE).ToList();
        }
        internal static List<WCSTask> GetTaskListByState(int state)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<WCSTask>().Where(a => a.N_B_STATE == state).ToList();
        }
        internal static List<WCSTask> GetWaitingTaskList()
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<WCSTask>().Where(a => a.N_B_STATE == 0).ToList();
        }
    }
}
HH.WCS.Mobox3.HangYang/wms/WMSHelper.cs
@@ -42,63 +42,10 @@
            var date = DateTime.Now.ToString("yyMMdd");
            return $"SO{date}{id.ToString().PadLeft(4, '0')}";
        }
        internal static List<WMSTask> GetOperationListByState(string state)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<WMSTask>().Where(a => a.S_B_STATE == state).ToList();
        }
        internal static List<WMSTask> GetOperationListByState(int state)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<WMSTask>().Where(a => a.N_B_STATE == state).ToList();
        }
        internal static List<WMSTask> GetWaitingOperationList()
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<WMSTask>().Where(a => a.N_B_STATE == 0 || a.N_B_STATE == 3).ToList();
        }
        internal static PutawayOrder GetPutawayOrder(string no)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<PutawayOrder>().Where(a => a.S_NO == no).First();
        }
        internal static bool CreatePutawayOrder(PutawayOrder model)
        {
            var db = new SqlHelper<object>().GetInstance();
            var result = db.Insertable<PutawayOrder>(model).ExecuteCommand() > 0;
            db.Insertable<PutawayDetail>(model.Details).ExecuteCommand();
            return result;
        }
        internal static PutawayDetail GetPutawayOrderDetail(string no, string item_code)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<PutawayDetail>().Where(a => a.S_PUTAWAY_NO == no && a.S_ITEM_CODE == item_code).First();
        }
        internal static PutawayDetail GetPutawayOrderDetail(string item_code)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<PutawayDetail>().Where(a => a.S_ITEM_CODE == item_code && a.F_QTY - a.F_ACC_B_QTY > 0).OrderByDescending(a => a.T_CREATE).First();
        }
        internal static void UpdatePutawayOrderDetailQty(PutawayDetail model)
        {
            var db = new SqlHelper<object>().GetInstance();
            db.Updateable(model).UpdateColumns(it => new { it.F_ACC_B_QTY }).ExecuteCommand();
        }
        internal static ShippingOrder GetShippingOrder(string no)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<ShippingOrder>().Includes(a => a.Details).Where(a => a.S_NO == no).First();
        }
        internal static bool CreateShippingOrder(ShippingOrder model)
        {
            var db = new SqlHelper<object>().GetInstance();
            var result = db.Insertable<ShippingOrder>(model).ExecuteCommand() > 0;
            db.Insertable<ShippingDetail>(model.Details).ExecuteCommand();
            return result;
        }
        internal static bool CreateSortingOrder(List<string> list)
@@ -273,11 +220,6 @@
            throw new NotImplementedException();
        }
        internal static Location GetStart(WMSTask a)
        {
            throw new NotImplementedException();
        }
        internal static void UpdateTaskState(WMSTask task)
        {
            var db = new SqlHelper<object>().GetInstance();
@@ -293,11 +235,8 @@
            return db.Updateable<WMSTask>(a).UpdateColumns(it => new { it.S_END_LOC, it.T_MODIFY }).ExecuteCommand() > 0;
        }
        internal static WMSTask GetWmsTask(string code)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<WMSTask>().Where(a => a.S_CODE == code).First();
        }
        internal static void CreateSortingOrderDetail(string so_no)
        {
@@ -372,15 +311,6 @@
            }
        }
        /// <summary>
        /// 获取开始配货的分拣单,一次性生成分拣明细,避免生成一半再生成,所以创建分拣明细的时候加上事务
        /// </summary>
        /// <returns></returns>
        internal static List<SortingOrder> GetWaitingSortingOrderList()
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<SortingOrder>().Includes(a => a.Composes).Where(a => a.N_B_STATE == 1 || a.N_B_STATE == 20).ToList();
        }
        /// <summary>
        /// 获取配货完成的分拣单,每个分拣单单独创建分拣作业
        /// </summary>
@@ -746,10 +676,10 @@
        internal static LocCntrRel GetCntrLoc(string trayCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            var locCntr = db.Queryable<LocCntrRel>().Where(a => a.S_CNTR_CODE.Trim() == trayCode).First();
            var locList = db.Queryable<Location>().Where(p => p.S_CODE == locCntr.S_LOC_CODE
            && p.N_CURRENT_NUM == p.N_CAPACITY
            var locList = db.Queryable<Location>().Where(p => p.S_CODE == locCntr.S_LOC_CODE
            && p.N_CURRENT_NUM == p.N_CAPACITY
            && p.S_LOCK_STATE.Trim() == "无"
            && p.S_AREA_CODE == "JXHCQ").First();
            if (locList == null)
@@ -820,10 +750,10 @@
        /// <param name="state">状态</param>
        /// <param name="trayCode">托盘号</param>
        /// <returns></returns>
        internal static bool UpdateDistributionCntrState(int taskState,int state,string trayCode)
        internal static bool UpdateDistributionCntrState(int taskState, int state, string trayCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            var distributionCntr = db.Queryable<DistributionCntr>().Where(a => a.N_B_STATE == taskState && a.S_CNTR_CODE == trayCode ).First();
            var distributionCntr = db.Queryable<DistributionCntr>().Where(a => a.N_B_STATE == taskState && a.S_CNTR_CODE == trayCode).First();
            if (distributionCntr != null)
            {
                distributionCntr.N_B_STATE = state;
@@ -917,11 +847,19 @@
            return res;
        }
        internal static bool UpdateTask(WMSTask a, int state)
        {
            var db = new SqlHelper<object>().GetInstance();
            a.T_MODIFY = DateTime.Now;
            a.N_B_STATE = state;
            a.S_B_STATE = GetStateStr(state);
            return db.Updateable<WMSTask>(a).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE, it.S_CNTR_CODE, it.S_START_LOC, it.T_MODIFY }).ExecuteCommand() > 0;
        }
        #endregion
        #region 杭氧立库出入库逻辑算法
        /// <summary>
        /// 立库入库封装算法
        /// </summary>
@@ -939,7 +877,7 @@
            {
                var db = new SqlHelper<object>().GetInstance();
                var locations = db.Queryable<Location>().Where(a => a.S_AREA_CODE == inbound.areaCode).ToList();
                if(inbound.roadWay != 0)
                if (inbound.roadWay != 0)
                {
                    locations.RemoveAll(s => s.N_ROADWAY != inbound.roadWay);
                }
@@ -1061,7 +999,7 @@
                return null; // 无可用位置
            }
            private readonly ConcurrentDictionary<string, SemaphoreSlim> _locationLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
            public async Task<LocationParams> StoreItemAsync()
            {
                LocationParams location = null;
@@ -1099,7 +1037,7 @@
        }
        /// <summary>
        /// 立库出库封装算法
        /// 配盘出库封装算法
        /// </summary>
        public class DoubleDeepOutboundScheduler
        {
@@ -1117,7 +1055,7 @@
            // 生成出库任务队列(含移库任务)
            /// <summary>
            /// 立库WMS货位出库算法(运用于配盘单出库、空托出库)
            /// 立库WMS货位出库算法(运用于配盘单出库)
            /// </summary>
            /// <param name="outbound">出库参数</param>
            /// <returns></returns>
@@ -1134,7 +1072,7 @@
                    var wmsTask = WMSHelper.GetWmsTaskList("执行", outboundItem.trayCode);
                    if (wmsTask == null)
                    {
                        LogHelper.Info($"未查询到在执行中的作业:{outboundItem.trayCode}!", "杭氧");
                        //LogHelper.Info($"未查询到在执行中的作业:{outboundItem.trayCode}!", "杭氧");
                        outboundItem.opCode = "";
                    }
@@ -1158,6 +1096,7 @@
                                .Where(x => x.S_CODE == outerLoc.S_CODE)
                                .ToList()
                                .ForEach(x => x.N_LOCK_STATE = 3);
                                    var trayCode = ContainerHelper.GetLocCntr(outerLoc.S_CODE);
                                    tasks.Add(new WCSTask
                                    {
                                        S_CODE = GenerateTaskNo(),
@@ -1171,20 +1110,14 @@
                                        N_SCHEDULE_TYPE = 1,
                                        N_B_STATE = 0,
                                        S_B_STATE = WCSTask.GetStateStr(0),
                                        S_CNTR_CODE = outboundItem.trayCode,
                                        S_CNTR_CODE = trayCode.S_CNTR_CODE,
                                        N_START_LAYER = 1,
                                        N_END_LAYER = 1,
                                        N_CNTR_COUNT = 1
                                    });
                                }
                                else continue;
                            }
                            //else
                            //{
                            //    //货位为空直接生成出库任务
                            //    tasks.Add(CreateOutboundTask(targetLoc, outboundItem));
                            //}
                        }
                        else
                        {
@@ -1223,19 +1156,19 @@
            private Location FindBestRelocationTarget(Location outerLoc)
            {
                  return _allLocations
                        .Where(loc =>
                            loc.N_ROADWAY == outerLoc.N_ROADWAY &&
                            loc.N_LOCK_STATE == 0 &&
                            loc.N_CURRENT_NUM == 0 &&
                            loc.S_CODE != outerLoc.S_CODE)
                        .OrderBy(loc => loc.N_ROW == outerLoc.N_ROW ? 1 : 0)
                        .ThenBy(loc => loc.N_COL)
                        .ThenBy(loc => Math.Abs(loc.N_LAYER - outerLoc.N_LAYER))
                        .FirstOrDefault();
                return _allLocations
                      .Where(loc =>
                          loc.N_ROADWAY == outerLoc.N_ROADWAY &&
                          loc.N_LOCK_STATE == 0 &&
                          loc.N_CURRENT_NUM == 0 &&
                          loc.S_CODE != outerLoc.S_CODE)
                      .OrderBy(loc => loc.N_ROW == outerLoc.N_ROW ? 1 : 0)
                      .ThenBy(loc => loc.N_COL)
                      .ThenBy(loc => Math.Abs(loc.N_LAYER - outerLoc.N_LAYER))
                      .FirstOrDefault();
            }
            private WCSTask CreateOutboundTask(Location loc,Outbound outbound) =>
            private WCSTask CreateOutboundTask(Location loc, Outbound outbound) =>
                new WCSTask
                {
                    S_CODE = GenerateTaskNo(),
@@ -1245,7 +1178,7 @@
                    S_END_LOC = outbound.endBit,
                    S_TYPE = outbound.taskType,
                    S_OP_CODE = outbound.opCode,
                    N_PRIORITY = 1,
                    N_PRIORITY = 0,
                    N_SCHEDULE_TYPE = 1,
                    N_B_STATE = 0,
                    S_B_STATE = WCSTask.GetStateStr(0),
@@ -1294,6 +1227,182 @@
            }
        }
        public class EmptyPalletOutboundScheduler
        {
            private readonly List<Location> _allLocations;
            public EmptyPalletOutboundScheduler(string areaCode)
            {
                var db = new SqlHelper<object>().GetInstance();
                _allLocations = db.Queryable<Location>()
                                 .Where(a => a.S_AREA_CODE == areaCode)
                                 .ToList();
            }
            /// <summary>
            /// 空托盘出库算法(自动寻找可用空托并生成任务)
            /// </summary>
            public List<WCSTask> GenerateEmptyPalletTasks(Outbound outbound)
            {
                var tasks = new List<WCSTask>();
                var foundPallets = 0;
                if (foundPallets < outbound.requiredCount)
                {
                    var doubleDeepPallets = FindDoubleDeepEmptyPallets();
                    foreach (var palletLoc in doubleDeepPallets)
                    {
                        if (IsDoubleDeepRow(palletLoc.N_ROW))
                        {
                            var outerLoc = FindOuterLocation(palletLoc);
                            if (outerLoc != null)
                            {
                                if (outerLoc.N_CURRENT_NUM == outerLoc.N_CAPACITY)
                                {
                                    // 优先移到深位,其次外侧
                                    var bestTarget = FindBestRelocationTarget(outerLoc);
                                    if (bestTarget != null)
                                    {
                                        //计算到了外侧把外侧的货位锁定
                                        _allLocations
                                    .Where(x => x.S_CODE == outerLoc.S_CODE)
                                    .ToList()
                                    .ForEach(x => x.N_LOCK_STATE = 3);
                                        var trayCode = ContainerHelper.GetLocCntr(outerLoc.S_CODE);
                                        tasks.Add(new WCSTask
                                        {
                                            S_CODE = GenerateTaskNo(),
                                            S_START_AREA = outerLoc.S_AREA_CODE,
                                            S_END_AREA = bestTarget.S_AREA_CODE,
                                            S_START_LOC = outerLoc.S_CODE,
                                            S_END_LOC = bestTarget.S_CODE,
                                            S_TYPE = "深位移库",
                                            S_OP_CODE = outbound.opCode,
                                            N_PRIORITY = 1,
                                            N_SCHEDULE_TYPE = 1,
                                            N_B_STATE = 0,
                                            S_B_STATE = WCSTask.GetStateStr(0),
                                            S_CNTR_CODE = trayCode.S_CNTR_CODE,
                                            N_START_LAYER = 1,
                                            N_END_LAYER = 1,
                                            N_CNTR_COUNT = 1
                                        });
                                    }
                                    else continue;
                                }
                            }
                        }
                        var tray = ContainerHelper.GetLocCntr(palletLoc.S_CODE);
                        outbound.trayCode = tray.S_CNTR_CODE;
                        tasks.Add(CreateEmptyPalletTask(palletLoc, outbound));
                        foundPallets++;
                        if (foundPallets >= outbound.requiredCount) break;
                    }
                }
                return tasks;
            }
            // 关键辅助方法
            private List<Location> FindDoubleDeepEmptyPallets() =>
                _allLocations.Where(loc =>
                    loc.N_LOCK_STATE == 0 &&
                    loc.N_CURRENT_NUM == loc.N_CAPACITY &&
                    ContainerHelper.GetLocItemRel(loc.S_CODE)
                ).OrderBy(loc => loc.N_ROW)   // 按排排序
                 .ThenBy(loc => loc.N_COL)
                 .ToList();
            private WCSTask CreateEmptyPalletTask(Location loc, Outbound outbound) =>
                new WCSTask
                {
                    S_CODE = GenerateTaskNo(),
                    S_START_AREA = loc.S_AREA_CODE,
                    S_END_AREA = outbound.endArea,
                    S_START_LOC = loc.S_CODE,
                    S_END_LOC = outbound.endBit,
                    S_TYPE = outbound.taskType,
                    S_OP_CODE = outbound.opCode,
                    N_PRIORITY = 0,
                    N_SCHEDULE_TYPE = 1,
                    N_B_STATE = 0,
                    S_B_STATE = WCSTask.GetStateStr(0),
                    S_CNTR_CODE = outbound.trayCode,
                    N_START_LAYER = 1,
                    N_END_LAYER = 1,
                    N_CNTR_COUNT = 1
                };
            // 复用原有双深位方法
            private bool IsDoubleDeepRow(int row) => row == 1 || row == 4;
            private Location FindTargetLocation(string code) =>
                _allLocations.FirstOrDefault(loc =>
                    loc.S_CODE == code && loc.N_LOCK_STATE == 0);
            //查询深位外侧的货位
            private Location FindOuterLocation(Location deepLoc) =>
                _allLocations.FirstOrDefault(loc =>
                    loc.N_ROW != deepLoc.N_ROW &&
                    loc.N_ROADWAY == deepLoc.N_ROADWAY &&
                    loc.N_COL == deepLoc.N_COL &&
                    loc.N_LAYER == deepLoc.N_LAYER &&
                    loc.N_LOCK_STATE == 0 || loc.N_LOCK_STATE == 5
            );
            private Location FindBestRelocationTarget(Location outerLoc)
            {
                return _allLocations
                      .Where(loc =>
                          loc.N_ROADWAY == outerLoc.N_ROADWAY &&
                          loc.N_LOCK_STATE == 0 &&
                          loc.N_CURRENT_NUM == 0 &&
                          loc.S_CODE != outerLoc.S_CODE)
                      .OrderBy(loc => loc.N_ROW == outerLoc.N_ROW ? 1 : 0)
                      .ThenBy(loc => loc.N_COL)
                      .ThenBy(loc => Math.Abs(loc.N_LAYER - outerLoc.N_LAYER))
                      .FirstOrDefault();
            }
            private void MarkReservedLocations(List<Outbound> outbound)
            {
                //查询已经被锁住的货位
                var lockLoc = _allLocations
                    .Where(loc => loc.N_LOCK_STATE != 0)
                    .ToList();
                //把锁住的货位标记为占用
                foreach (var item in lockLoc)
                {
                    if (IsDoubleDeepRow(item.N_ROW))
                    {
                        _allLocations
                                .Where(x => x.S_CODE == item.S_CODE)
                                .ToList()
                                .ForEach(x => x.N_LOCK_STATE = 3);
                    }
                }
                foreach (var item in outbound)
                {
                    var loc = FindTargetLocation(item.locCode);
                    if (loc != null && IsDoubleDeepRow(loc.N_ROW))
                    {
                        // 标记该深位对应的外侧货位(如果存在)
                        var outerLoc = FindOuterLocation(loc);
                        if (outerLoc != null)
                        {
                            // 标记深位的外侧货位(避免被移库占用)
                            _allLocations
                                .Where(x => x.S_CODE == outerLoc.S_CODE)
                                .ToList()
                                .ForEach(x => x.N_LOCK_STATE = 5);
                            //标记深位的外侧货位为5
                        }
                    }
                }
            }
        }
        #endregion
        #region 杭氧升降量表帮助方法