杨前锦
2025-07-01 a93b0e99036c24b9bd58c79bf5e7364b1ba28bae
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs
@@ -1,5 +1,6 @@
using HH.WCS.Mobox3.YNJT_BZP_PT.models;
using HH.WCS.Mobox3.YNJT_PT.api;
using HH.WCS.Mobox3.YNJT_PT.dispatch;
using HH.WCS.Mobox3.YNJT_PT.models;
using HH.WCS.Mobox3.YNJT_PT.models.other;
using HH.WCS.Mobox3.YNJT_PT.util;
@@ -338,7 +339,7 @@
            var offLineRecord = db.Queryable<OffLineRecord>().Where(a => a.S_RFID == record.S_RFID).First();
            if (offLineRecord != null)
            {
                offLineRecord.S_LOC = record.S_LOC;
                offLineRecord.S_DEVICE_NO = record.S_DEVICE_NO;
                offLineRecord.N_IS_URGENT = record.N_IS_URGENT;
                offLineRecord.T_OFF_TIME = record.T_OFF_TIME;
                offLineRecord.N_IS_FULL = record.N_IS_FULL;
@@ -383,148 +384,425 @@
            return greenTireInformation;
        }
        /// <summary>
        /*/// <summary>
        /// 查询入库终点货位
        /// 入库策略:
        /// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
        /// </summary>
        /// <param name="itemCode"></param>
        /// <param name="locNum">1.单货位 2.双货位</param>
        /// <returns></returns>
        public static List<Location> getInStockEndLoc(string itemCode, int locNum)
        public static EndLocGroup getInStockEndLoc(int locNum , string itemCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            EndLocGroup endLocGroup = new EndLocGroup();
            List<Location> locations = new List<Location>();
            // 1.按容积率从大到小,对巷道进行排序
            var roadwayOrderList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
                .GroupBy(a => a.N_ROADWAY)
                .Select(a => new { roadway = a.N_ROADWAY ,  num = SqlFunc.AggregateCount(a.S_CODE)})
                .OrderByDescending(a => a.num)
            List<int> roadwayList = new List<int>();
            // 1.按巷道进行分组,查询每个巷道内同规格物料的数量,并从小到大排序
            var roadwayItemNumOrderGroup = db.Queryable<Location>()
                .LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
                .LeftJoin<CntrItemRel>((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && c.S_ITEM_CODE == itemCode)
                .GroupBy((a, b, c) => a.N_ROADWAY)
                .Select((a, b, c) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
                .OrderBy(a => a.num)
                .ToList();
            // 查询单货位
            if (locNum == 1)
            roadwayList = roadwayItemNumOrderGroup.Where(a => a.num < 10).OrderBy(a => a.num).Select(a => a.roadway).ToList();
            // 2.按巷道进行分组,查询每个巷道空货位数量,并从大到小排序
            if (roadwayList.Count == 0)
            {
                foreach (var order in roadwayOrderList)
                var roadwayEmptyNumOrderGroup = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
                    .GroupBy(a => a.N_ROADWAY)
                    .Select(a => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
                    .OrderByDescending(a => a.num)
                    .ToList();
                roadwayList = roadwayEmptyNumOrderGroup.Select(a => a.roadway).ToList();
            }
            if (roadwayList.Count > 0)
            {
                // 查询单货位
                foreach (var roadway in roadwayList)
                {
                    // 1. 查询1号货位是否有相同物料,有,则查询对应的2号货位是否为空
                    var oneLocList = db.Queryable<Location>()
                        .LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
                        .LeftJoin<CntrItemRel>((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                        .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea
                                        && a.N_ROADWAY == order.roadway
                                        && a.N_COL % 2 == 1
                                        && a.N_CURRENT_NUM == 1
                                        && a.N_LOCK_STATE == 0
                                        && a.C_ENABLE == "Y"
                                        && c.S_ITEM_CODE == itemCode
                                        )
                        .OrderBy(a => a.N_LAYER).OrderBy(a => a.N_COL)
                        .ToList();
                    if (oneLocList.Count > 0)
                    if (locNum == 1)
                    {
                        foreach (var loc in oneLocList)
                        // 查询空货位
                        var emptyLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).First();
                        if (emptyLoc != null)
                        {
                            var twoLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                            if (twoLoc != null)
                            {
                                locations.Add(twoLoc);
                                return locations;
                            }
                            locations.Add(emptyLoc);
                            endLocGroup.endLocList = locations;
                            return endLocGroup;
                        }
                    }
                    // 2.查询2号货位是否有相同物料,有,则查询对应的1号位是否为空
                    if (locations.Count == 0)
                    if (locNum == 2)
                    {
                        var twoLocList = db.Queryable<Location>()
                            .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
                            .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                            .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea
                                            && a.N_ROADWAY == order.roadway
                                            && a.N_COL % 2 == 0
                                            && a.N_CURRENT_NUM == 1
                                            && a.N_LOCK_STATE == 0
                                            && a.C_ENABLE == "Y"
                                            && c.S_ITEM_CODE == itemCode
                                            )
                            .OrderBy(a => a.N_LAYER).OrderBy(a => a.N_COL)
                            .ToList();
                        if (twoLocList.Count > 0)
                        var emptyLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).ToList();
                        if (emptyLocList.Count > 0)
                        {
                            foreach (var loc in twoLocList)
                            // 优先查询相邻双拖空货位
                            if (locations.Count == 0)
                            {
                                var oneLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                if (oneLoc != null)
                                foreach (var loc in emptyLocList)
                                {
                                    locations.Add(oneLoc);
                                    return locations;
                                }
                            }
                        }
                    }
                                    // 查询相邻左侧是否有空货位
                                    var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                    if (leftLoc != null)
                                    {
                                        locations.Add(loc);
                                        locations.Add(leftLoc);
                                        break;
                                    }
                    // 3.没有相同物料的,优先放禁用货位旁边(单一货位)
                    if (locations.Count == 0)
                    {
                       var  disableLocList= db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.C_ENABLE == "N").OrderBy(a => a.N_LAYER).ToList();
                        foreach (var loc in disableLocList)
                        {
                            // 货位为1号位,则查询对应二号位是否为空
                            if (loc.N_LAYER % 2 == 1)
                            {
                                var twoLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                if (twoLoc != null)
                                {
                                    locations.Add(twoLoc);
                                    return locations;
                                    // 查询相邻右侧是否有空货位
                                    var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                    if (rightLoc != null)
                                    {
                                        locations.Add(loc);
                                        locations.Add(rightLoc);
                                        break;
                                    }
                                }
                            }
                            // 货位为2号位,则查询对应一号位是否为空
                            if (loc.N_LAYER % 2 == 0)
                            if (locations.Count < locNum)
                            {
                                var oneLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                if (oneLoc != null)
                                // 查询不相邻的单拖货位
                                foreach (var loc in emptyLocList)
                                {
                                    locations.Add(oneLoc);
                                    return locations;
                                    locations.Add(loc);
                                    if (locations.Count == locNum)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    // 4.没有相同物料的,且禁用货位旁边没有空货位,则优先放1号位
                    if (locations.Count == 0)
                    {
                        oneLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_COL % 2 == 1 && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => a.N_LAYER).OrderByDescending(a => a.N_COL).ToList();
                        if (oneLocList.Count > 0)
                        {
                            locations.Add(oneLocList[0]);
                            return locations;
                            if (locations.Count == locNum)
                            {
                                endLocGroup.endLocList = locations;
                                // 校验货位是否是同巷道,是则生成任务组号
                                var groupNum = locations.GroupBy(a => a.N_ROADWAY).Count();
                                if (groupNum == 1)
                                {
                                    endLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                }
                                return endLocGroup;
                            }
                        }
                    }
                }
            }
            return endLocGroup;
        }*/
            // 查询双货位
            if (locNum == 2)
        /// <summary>
        /// 查询入库终点货位
        /// 入库策略:
        /// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
        /// </summary>
        /// <param name="locNum"></param>
        /// <param name="itemCode"></param>
        /// <param name="roadway"></param>
        /// <param name="excludeRoadway"></param>
        /// <returns></returns>
        public static EndLocGroup getInStockEndLoc(int locNum, string itemCode , int roadway = 0 ,int excludeRoadway = 0)
        {
            var db = new SqlHelper<object>().GetInstance();
            EndLocGroup endLocGroup = new EndLocGroup { endLocList = new List<Location>() };
            // 1. 获取候选巷道列表(物料均衡或巷道均衡)
            List<int> candidateRoadways = new List<int>();
            if (roadway == 0)
            {
                foreach (var order in roadwayOrderList)
                candidateRoadways = GetCandidateRoadways(db, itemCode);
                if (candidateRoadways.Count == 0) return endLocGroup;
                if (excludeRoadway != 0)
                {
                   var oneLocList = db.Queryable<Location>().Where( a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_COL % 2 == 1 && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => a.N_LAYER).OrderBy(a => a.N_COL).ToList();
                    foreach (var loc in oneLocList)
                    {
                       var twoLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (twoLoc != null)
                        {
                            locations.Add(loc);
                            locations.Add(twoLoc);
                            return locations;
                        }
                    }
                    candidateRoadways.Remove(excludeRoadway);
                }
            }
            return locations;
            else
            {
                candidateRoadways.Add(roadway);
            }
            // 2. 处理单货位入库
            if (locNum == 1)
            {
                return FindSingleLocation(db, candidateRoadways);
            }
            // 3. 处理双货位入库
            return FindDoubleLocations(db, candidateRoadways);
        }
        /// <summary>
        /// 获取候选巷道列表(按策略排序)
        /// </summary>
        private static List<int> GetCandidateRoadways(SqlSugarClient db, string itemCode)
        {
            var list = new List<int>();
            // 策略1:巷道内同规格物料 < 10 的巷道(按数量升序)
            var materialRoadwayGroup = db.Queryable<Location>()
                        // 表别名:a = Location, b = LocCntrRel, c = CntrItemRel
                        .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
                        .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                        // 基础筛选条件(所有位置)
                        .Where((a, b, c) =>
                            a.S_AREA_CODE == Settings.stockArea &&  // 指定区域
                            a.N_LOCK_STATE == 0 &&                 // 未锁定
                            a.C_ENABLE == "Y")                     // 启用状态
                        // 按巷道分组(使用原始表字段)
                        .GroupBy((a, b, c) => a.N_ROADWAY)
                        // 选择分组结果(包含聚合计算)
                        .Select((a, b, c) => new
                        {
                            Roadway = a.N_ROADWAY,  // 巷道编号
                            // 统计满足特定条件的数量:
                            // 1. 当前数量=1 (a.N_CURRENT_NUM == 1)
                            // 2. 物料匹配 (c.S_ITEM_CODE == itemCode)
                            // 3. 容器关联存在 (b.S_CNTR_CODE != null)
                            validCount = SqlFunc.AggregateSum(SqlFunc.IIF(
                                a.N_CURRENT_NUM == 1 &&
                                c.S_ITEM_CODE == itemCode &&
                                b.S_CNTR_CODE != null,
                                1, 0))
                        })
                       .ToList();
            if (materialRoadwayGroup.Count > 0)
            {
                list = materialRoadwayGroup.Where(a => a.validCount < 10).OrderBy(a => a.validCount).Select(a => a.Roadway).ToList();
            }
            if (list.Count == 0)
            {
                // 策略2:所有巷道按空货位数降序排序
                materialRoadwayGroup = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .GroupBy(a => a.N_ROADWAY)
                    .Select(a => new { Roadway = a.N_ROADWAY, validCount = SqlFunc.AggregateCount(a.S_CODE) })
                    .ToList();
                list = materialRoadwayGroup.OrderByDescending(a => a.validCount).Select(a => a.Roadway).ToList();
            }
            return list;
        }
        /// <summary>
        /// 查找单货位
        /// </summary>
        private static EndLocGroup FindSingleLocation(SqlSugarClient db, List<int> candidateRoadways)
        {
            foreach (var roadway in candidateRoadways)
            {
                var location = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_ROADWAY == roadway &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .OrderBy(a => a.N_LAYER)
                    .OrderBy(a => a.N_COL)
                    .First();
                if (location != null)
                {
                    return new EndLocGroup
                    {
                        endLocList = new List<Location> { location }
                    };
                }
            }
            return new EndLocGroup();
        }
        /// <summary>
        /// 查找双货位(优化相邻货位查找)
        /// </summary>
        private static EndLocGroup FindDoubleLocations(SqlSugarClient db, List<int> candidateRoadways)
        {
            // 先尝试找相邻货位
            foreach (var roadway in candidateRoadways)
            {
                // 一次性获取巷道所有空货位(减少DB查询)
                var emptyLocs = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_ROADWAY == roadway &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .OrderBy(a => a.N_LAYER)
                    .OrderBy(a => a.N_COL)
                    .ToList();
                if (emptyLocs.Count < 2) continue;
                // 在内存中查找相邻货位(高性能)
                var adjacentPair = FindAdjacentLocations(emptyLocs);
                if (adjacentPair != null)
                {
                    return CreateDoubleLocGroup(adjacentPair);
                }
            }
            // 没有相邻货位时,取任意两个货位
            foreach (var roadway in candidateRoadways)
            {
                var emptyLocs = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_ROADWAY == roadway &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .OrderBy(a => a.N_LAYER)
                    .OrderBy(a => a.N_COL)
                    .Take(2)
                    .ToList();
                if (emptyLocs.Count == 2)
                {
                    return CreateDoubleLocGroup(emptyLocs);
                }
            }
            return new EndLocGroup();
        }
        /// <summary>
        /// 在内存中查找相邻货位(高效算法)
        /// </summary>
        private static List<Location> FindAdjacentLocations(List<Location> locations)
        {
            // 按层->列排序,便于查找相邻
            var sorted = locations
                .OrderBy(l => l.N_LAYER)
                .ThenBy(l => l.N_ROW)
                .ThenBy(l => l.N_COL)
                .ToList();
            for (int i = 0; i < sorted.Count - 1; i++)
            {
                var current = sorted[i];
                var next = sorted[i + 1];
                // 判断是否同一层且相邻列
                if (current.N_LAYER == next.N_LAYER &&
                    current.N_COL + 1 == next.N_COL)
                {
                    return new List<Location> { current, next };
                }
            }
            return null;
        }
        /// <summary>
        /// 创建双货位返回结果
        /// </summary>
        private static EndLocGroup CreateDoubleLocGroup(List<Location> locations)
        {
            return new EndLocGroup
            {
                endLocList = locations,
                groupNo = locations.GroupBy(a => a.N_ROADWAY).Count() == 1
                    ? WMSHelper.GenerateTaskGroupNo()
                    : null
            };
        }
        public class EndLocGroup
        {
            public string groupNo { get; set; }
            public List<Location> endLocList { get; set; }
        }
        /// <summary>
        /// 查询出库开始货位
        /// 1.计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料
        /// 2.同等条件下,优先取前一托货的相邻货位(暂时不做考虑,需确定先入先出(生产时间)是按天算,还是精确到时分秒)
        /// </summary>
        /// <param name="itemCode"></param>
        /// <param name="prevLoc"></param>
        public static Location getOutStockStartLoc(string itemCode, Location prevLoc = null)
        {
            var db = new SqlHelper<object>().GetInstance();
            Location startLoc = null;
            // 1.查询(物料状态OK ,且小于失效时间,大于等于生效时间)出库物料,并按加急料先出,先入先出(生产时间)的原则进行排序
            var query = db.Queryable<Location>()
               .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
               .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
               .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea
                               && a.N_CURRENT_NUM == 1
                               && a.N_LOCK_STATE == 0
                               && a.C_ENABLE == "Y"
                               && b.S_CNTR_CODE != null
                               );
            if (itemCode != null)
            {
                query = query.Where((a, b, c) => c.S_ITEM_CODE == itemCode
                               && c.S_ITEM_STATE == "OK"
                               && SqlFunc.ToDate(c.S_EFFECTIVE_TIME) <= SqlFunc.GetDate()  // 生效时间早于当前时间
                               && SqlFunc.ToDate(c.S_EXPIRATION_TIME) >= SqlFunc.GetDate() // 失效时间晚于当前时间
                               && c.S_EFFECTIVE_TIME != null
                               && c.S_EXPIRATION_TIME != null)
                            .OrderByDescending((a, b, c) => c.N_URGENT_FLAG)
                            .OrderBy((a, b, c) => c.S_TXNDATE);
            }
            else
            {
                query = query.Where((a, b, c) => c.S_ITEM_CODE == itemCode);
            }
            query = query.OrderByDescending((a, b, c) => a.N_ROADWAY == prevLoc.N_ROADWAY);
            var outLocList = query.ToList();
            if (outLocList.Count > 0)
            {
                foreach (var loc in outLocList)
                {
                    // 查询巷道是否正常,异常跳过
                    var deviceConfig = Settings.deviceConfigList.Where(a => a.roadway == loc.N_ROADWAY).First();
                    if (deviceConfig != null)
                    {
                        var stackerStates = WCSDispatch.getDeviceStatus(new List<string>() { deviceConfig.deviceNo } );
                        if ( stackerStates.Count == 0 || stackerStates[0].workStatus != 1 || stackerStates[0].manualStatus == 1 )
                        {
                            continue;
                        }
                    }
                    startLoc = loc;
                    break;
                }
            }
            return startLoc;
        }
        public class StartLocGroup
        {
            public string groupNo {  get; set; }
            public List<Location> startLocList { get; set; }
        }
        /// <summary>
@@ -543,29 +821,69 @@
        /// 查询巷道任务最少的接驳位
        /// </summary>
        /// <returns></returns>
        public static Location getMinTaskMiddleLoc(int type)
        public static Location getMinTaskMiddleLoc(int type , int roadway = 0 , int excludeRoadway = 0)
        {
            Location location = new Location();
            var db = new SqlHelper<object>().GetInstance();
            var roadwayGroup = db.Queryable<Location>()
                .LeftJoin<WCSTask>((a,b) => a.S_CODE == b.S_END_LOC && b.N_B_STATE < 3)
                .Where((a, b) => a.S_AREA_CODE == Settings.stockArea && b.S_CODE != null )
                .GroupBy((a, b) => a.N_ROADWAY)
                .Select( (a, b) => new { roadway = a.N_ROADWAY  , num = SqlFunc.AggregateDistinctCount(a.S_CODE)})
                .OrderBy(a => a.num)
                .ToList();
            var query = db.Queryable<Location>()
                    .LeftJoin<WCSTask>((a, b) => a.S_CODE == b.S_END_LOC && b.N_B_STATE < 3)
                    .Where((a, b) => a.S_AREA_CODE == Settings.stockArea);
            if (roadway != 0)
            {
                query = query.Where((a, b) => a.N_ROADWAY == roadway);
            }
            if (excludeRoadway != 0)
            {
                query = query.Where((a, b) => a.N_ROADWAY != excludeRoadway);
            }
            var roadwayGroup = query.GroupBy((a, b) => a.N_ROADWAY)
                    .Select((a, b) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateDistinctCount(b.S_CODE != null) })
                    .OrderBy(a => a.num)
                    .ToList();
            foreach (var item in roadwayGroup)
            {
                // 1.查询巷道内的堆垛机状态是否正常
                // 2.查询接驳位
                var connectLoc = Settings.connectLocList.Where(a => a.type == type && a.roadway == item.roadway).FirstOrDefault();
                var connectLoc = Settings.connectLocList.Where(a => a.roadway == item.roadway).FirstOrDefault();
                if (connectLoc != null) 
                {
                    location = LocationHelper.GetLoc(connectLoc.locCode);
                    break;
                }
            }
            return location;
        }
        /// <summary>
        /// 查询上线货位
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Location getOnlneLoc(int type)
        {
            Location location = null;
            var connectLoc = Settings.onLineLocList.Where(a => a.type == type).FirstOrDefault();
            if (connectLoc != null)
            {
                location = LocationHelper.GetLoc(connectLoc.locCode);
            }
            return location;
        }
        /// <summary>
        /// 查询叫料异常排出位
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public static Location getCallOutLoc(int row)
        {
            Location location = null;
            var connectLoc = Settings.callOutLocList.Where(a => a.row == row).FirstOrDefault();
            if (connectLoc != null)
            {
                location = LocationHelper.GetLoc(connectLoc.locCode);
            }
            return location;
        }
@@ -599,6 +917,12 @@
            return null;
        }
        /// <summary>
        /// 绑定条码物料信息
        /// </summary>
        /// <param name="cntrCode"></param>
        /// <param name="greenTireInformation"></param>
        /// <returns></returns>
        public static bool bindBarcodeItemInfo( string cntrCode,GreenTireInformation greenTireInformation) 
        {
            bool result = false;
@@ -655,5 +979,28 @@
            }
            return result;
        }
        /// <summary>
        /// 查询硫化工单
        /// </summary>
        /// <param name="dateShift"></param>
        /// <param name="mcn"></param>
        /// <param name="shift"></param>
        /// <returns></returns>
        public static ProductionShedule getProductionShedule(string dateShift ,string mcn ,string shift)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<ProductionShedule>().Where(a => a.DATESHIFT == dateShift && a.MCN == mcn && a.SHIFT == shift).First();
        }
        /// <summary>
        /// 查询胚胎完成硫化的数量
        /// </summary>
        /// <returns></returns>
        public static int getEmbryoFinishNum(string dateShift, string mcn, string shift)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<EmbryoFinishRecord>().Where(a => a.DATE_SHIFT == dateShift && a.CUR_MCN == mcn && a.CUR_SHIFT == shift).Count();
        }
    }    
}