杨前锦
昨天 06a8b6963d6d4f229d4e196b4b09ce57e2cbf2dd
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs
@@ -384,121 +384,350 @@
            return greenTireInformation;
        }
        /// <summary>
        /*/// <summary>
        /// 查询入库终点货位
        /// 入库策略:
        /// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
        /// </summary>
        /// <param name="locNum">1.单货位 2.双货位</param>
        /// <returns></returns>
        public static EndLocGroup getInStockEndLoc(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();
            // 查询单货位
            foreach (var order in roadwayOrderList)
            roadwayList = roadwayItemNumOrderGroup.Where(a => a.num < 10).OrderBy(a => a.num).Select(a => a.roadway).ToList();
            // 2.按巷道进行分组,查询每个巷道空货位数量,并从大到小排序
            if (roadwayList.Count == 0)
            {
                if (locNum == 1)
                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)
                {
                    /*// 查询所有相同物料货位
                    var sameItemLocList = 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_CURRENT_NUM == 1
                                       && a.N_LOCK_STATE == 0
                                       && a.C_ENABLE == "Y"
                                       && b.S_CNTR_CODE != null
                                       && c.S_ITEM_CODE == itemCode
                                       )
                       .OrderBy((a, b, c) => new { a.N_LAYER, a.N_COL })
                       .ToList();
                    // 查询相同物料的左右是否有空货位
                    foreach (var loc in sameItemLocList)
                    if (locNum == 1)
                    {
                        var leftLoc = 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 (leftLoc != null)
                        // 查询空货位
                        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)
                        {
                            locations.Add(leftLoc);
                            break;
                            locations.Add(emptyLoc);
                            endLocGroup.endLocList = locations;
                            return endLocGroup;
                        }
                    }
                        var rightLoc = 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 (rightLoc != null)
                        {
                            locations.Add(leftLoc);
                            break;
                        }
                    }*/
                    // 查询空货位
                    var emptyLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.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)
                    if (locNum == 2)
                    {
                        locations.Add(emptyLoc);
                        endLocGroup.endLocList = locations;
                        return endLocGroup;
                        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)
                        {
                            // 优先查询相邻双拖空货位
                            if (locations.Count == 0)
                            {
                                foreach (var loc in emptyLocList)
                                {
                                    // 查询相邻左侧是否有空货位
                                    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;
                                    }
                                    // 查询相邻右侧是否有空货位
                                    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;
                                    }
                                }
                            }
                            if (locations.Count < locNum)
                            {
                                // 查询不相邻的单拖货位
                                foreach (var loc in emptyLocList)
                                {
                                    locations.Add(loc);
                                    if (locations.Count == locNum)
                                    {
                                        break;
                                    }
                                }
                            }
                            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;
                            }
                        }
                    }
                }
                if (locNum == 2)
                {
                    var emptyLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.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)
                    {
                        // 查询双拖空货位
                        if (locations.Count == 0)
                        {
                            foreach (var loc in emptyLocList)
                            {
                                var leftLoc = 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 (leftLoc != null)
                                {
                                    locations.Add(loc);
                                    locations.Add(leftLoc);
                                    break;
                                }
                                var rightLoc = 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 (rightLoc != null)
                                {
                                    locations.Add(loc);
                                    locations.Add(leftLoc);
                                    break;
                                }
                            }
                            if (locations.Count == locNum)
                            {
                                endLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                endLocGroup.endLocList = locations;
                                return endLocGroup;
                            }
                        }
                        // 查询单拖货位
                        foreach (var loc in emptyLocList)
                        {
                            locations.Add(loc);
                            if (locations.Count == locNum)
                            {
                                endLocGroup.endLocList = locations;
                                return endLocGroup;
                            }
                        }
                    }
                }
            }
            return endLocGroup;
        }*/
        /// <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)
            {
                candidateRoadways = GetCandidateRoadways(db, itemCode);
                if (candidateRoadways.Count == 0) return endLocGroup;
                if (excludeRoadway != 0)
                {
                    candidateRoadways.Remove(excludeRoadway);
                }
            }
            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
@@ -509,14 +738,15 @@
        /// <summary>
        /// 查询出库开始货位
        /// 计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料
        /// 1.计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料
        /// 2.同等条件下,优先取前一托货的相邻货位(暂时不做考虑,需确定先入先出(生产时间)是按天算,还是精确到时分秒)
        /// </summary>
        /// <param name="itemCode"></param>
        /// <param name="locNum"></param>
        public static StartLocGroup getOutStockStartLoc(string itemCode, int locNum )
        /// <param name="prevLoc"></param>
        public static Location getOutStockStartLoc(string itemCode, Location prevLoc = null)
        {
            var db = new SqlHelper<object>().GetInstance();
            StartLocGroup startLocGroup = new StartLocGroup();
            Location startLoc = null;
            // 1.查询(物料状态OK ,且小于失效时间,大于等于生效时间)出库物料,并按加急料先出,先入先出(生产时间)的原则进行排序
            var query = db.Queryable<Location>()
@@ -544,6 +774,7 @@
            {
                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)
@@ -551,54 +782,20 @@
                foreach (var loc in outLocList)
                {
                    // 查询巷道是否正常,异常跳过
                    var stackerStates = WCSDispatch.getStackerState(loc.N_ROADWAY);
                    if (stackerStates.Count == 0 || stackerStates[0].roadway_state == "0" || stackerStates[0].roadway_state == "3")
                    var deviceConfig = Settings.deviceConfigList.Where(a => a.roadway == loc.N_ROADWAY).First();
                    if (deviceConfig != null)
                    {
                        continue;
                    }
                    var cntrItemRel = db.Queryable<CntrItemRel>().LeftJoin<LocCntrRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE).Where((a, b) => b.S_LOC_CODE == loc.S_CODE).First();
                    if (cntrItemRel != null)
                    {
                        startLocGroup.startLocList.Add(loc);
                        if (locNum == startLocGroup.startLocList.Count)
                        var stackerStates = WCSDispatch.getDeviceStatus(new List<string>() { deviceConfig.deviceNo } );
                        if ( stackerStates.Count == 0 || stackerStates[0].workStatus != 1 || stackerStates[0].manualStatus == 1 )
                        {
                            break;
                        }
                        var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == loc.N_ROADWAY && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (leftLoc != null)
                        {
                            var locCntrRel = db.Queryable<LocCntrRel>()
                               .LeftJoin<CntrItemRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE)
                               .Where((a, b) => a.S_LOC_CODE == leftLoc.S_CODE && b.S_ITEM_CODE == itemCode)
                               .First();
                            if (locCntrRel != null)
                            {
                                startLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                startLocGroup.startLocList.Add(leftLoc);
                                break;
                            }
                        }
                        var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == loc.N_ROADWAY && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (rightLoc != null && startLocGroup.startLocList.Count == 0)
                        {
                            var locCntrRel = db.Queryable<LocCntrRel>()
                                .LeftJoin<CntrItemRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE)
                                .Where((a, b) => a.S_LOC_CODE == rightLoc.S_CODE && b.S_ITEM_CODE == itemCode)
                                .First();
                            if (locCntrRel != null)
                            {
                                startLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                startLocGroup.startLocList.Add(rightLoc);
                                break;
                            }
                            continue;
                        }
                    }
                    startLoc = loc;
                    break;
                }
            }
            return startLocGroup;
            return startLoc;
        }
@@ -624,30 +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>()
            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)
                    .GroupBy((a, b) => a.N_ROADWAY)
                    .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;
        }
@@ -694,51 +930,27 @@
            var cntrItemRel = db.Queryable<CntrItemRel>().Where(a => a.S_CNTR_CODE == cntrCode).First();
            if (cntrItemRel == null)
            {
                var overage = getOverage(greenTireInformation.BARCODE);
                DateTime txndate = DateTime.Parse(greenTireInformation.TXNDATE);
                DateTime minTime = txndate.AddHours(overage.MINHOUR);
                DateTime maxTime = txndate.AddDays(overage.OVERAGE);
                cntrItemRel = new CntrItemRel()
                {
                    S_CG_ID = greenTireInformation.BARCODE,
                    S_ITEM_CODE = greenTireInformation.ITEMCODE,
                    S_CNTR_CODE = cntrCode,
                    S_CELL_NO = greenTireInformation.TIRECODE,
                    F_QTY = greenTireInformation.QTY,
                    S_MCN = greenTireInformation.MCN,
                    S_OPR = greenTireInformation.OPR,
                    S_OPR02 = greenTireInformation.OPR02,
                    S_OPR03 = greenTireInformation.OPR03,
                    S_OPR04 = greenTireInformation.OPR04,
                    S_WINDUP = greenTireInformation.WINDUP,
                    S_TXNDATE = greenTireInformation.TXNDATE,
                    S_DATE_SHIFT = greenTireInformation.DATE_SHIFT,
                    S_EFFECTIVE_TIME = minTime.ToString("yyyy-MM-dd HH:mm:ss"),
                    S_EXPIRATION_TIME = maxTime.ToString("yyyy-MM-dd HH:mm:ss"),
                };
                result = db.Insertable(cntrItemRel).ExecuteCommand() > 0;
            }
            else 
            {
                var overage = getOverage(greenTireInformation.BARCODE);
                DateTime txndate = DateTime.Parse(greenTireInformation.TXNDATE);
                DateTime minTime = txndate.AddHours(overage.MINHOUR);
                DateTime maxTime = txndate.AddDays(overage.OVERAGE);
                cntrItemRel.S_CG_ID = greenTireInformation.BARCODE;
                cntrItemRel.S_ITEM_CODE = greenTireInformation.ITEMCODE;
                cntrItemRel.S_CNTR_CODE = cntrCode;
                cntrItemRel.S_CELL_NO = greenTireInformation.TIRECODE;
                cntrItemRel.F_QTY = greenTireInformation.QTY;
                cntrItemRel.S_MCN = greenTireInformation.MCN;
                cntrItemRel.S_OPR = greenTireInformation.OPR;
                cntrItemRel.S_OPR02 = greenTireInformation.OPR02;
                cntrItemRel.S_OPR03 = greenTireInformation.OPR03;
                cntrItemRel.S_OPR04 = greenTireInformation.OPR04;
                cntrItemRel.S_WINDUP = greenTireInformation.WINDUP;
                cntrItemRel.S_MCN = greenTireInformation.MCN;;
                cntrItemRel.S_TXNDATE = greenTireInformation.TXNDATE;
                cntrItemRel.S_DATE_SHIFT = greenTireInformation.DATE_SHIFT;
                cntrItemRel.S_EFFECTIVE_TIME = minTime.ToString("yyyy-MM-dd HH:mm:ss");
                cntrItemRel.S_EXPIRATION_TIME = maxTime.ToString("yyyy-MM-dd HH:mm:ss");
                result = db.Updateable(cntrItemRel).ExecuteCommand() > 0;
            }
            return result;
@@ -747,14 +959,14 @@
        /// <summary>
        /// 查询硫化工单
        /// </summary>
        /// <param name="dateShift"></param>
        /// <param name="mcn"></param>
        /// <param name="shift"></param>
        /// <param name="curMcn">工位</param>
        /// <param name="shift"> 班次</param>
        /// <param name="planStartDate">工单开始时间</param>
        /// <returns></returns>
        public static ProductionShedule getProductionShedule(string dateShift ,string mcn ,string shift)
        public static ProductionShedule getProductionShedule(string curMcn ,string shift ,string planStartDate)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<ProductionShedule>().Where(a => a.DATESHIFT == dateShift && a.MCN == mcn && a.SHIFT == shift).First();
            return db.Queryable<ProductionShedule>().Where(a => a.CUR_MCN == curMcn && a.CUR_SHIFT == shift && a.CUR_PLANSTARTDATE == planStartDate).OrderByDescending(a => a.LAST_MODIFY_TIME).First();
        }
        /// <summary>
@@ -766,5 +978,192 @@
            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();
        }
        /// <summary>
        /// 批量添加物料条码信息
        /// </summary>
        /// <returns></returns>
        public static bool batchAddItemBarcodeInfo(List<GreenTireInformation> GreenTireInfoList)
        {
            bool result = true;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                db.BeginTran();
                if (GreenTireInfoList.Count > 0)
                {
                    GreenTireInfoList.ForEach(item => {
                        var itemBarcodeInfo = db.Queryable<GreenTireInformation>().Where(a => a.BARCODE == item.BARCODE).First();
                        if (itemBarcodeInfo == null)
                        {
                            var bo = db.Insertable<GreenTireInformation>(item).ExecuteCommand() == 0;
                            if (bo)
                            {
                                result = false;
                                LogHelper.Info($"添加成型条码信息失败,物料条码信息:{JsonConvert.SerializeObject(item)}", "GT");
                            }
                        }
                    });
                }
                db.CommitTran();
            }
            catch (Exception ex)
            {
                LogHelper.Info($"添加成型条码信息错误,错误信息:{ex.Message}", "GT");
                db.RollbackTran();
            }
            return result;
        }
        /// <summary>
        /// 批量添加物料条码信息
        /// </summary>
        /// <returns></returns>
        public static bool batchAddProductionInfo(List<ProductionShedule> productionShedules)
        {
            bool result = true;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                db.BeginTran();
                if (productionShedules.Count > 0)
                {
                    productionShedules.ForEach(item => {
                        var bo = db.Insertable<ProductionShedule>(item).ExecuteCommand() == 0;
                        if (bo)
                        {
                            result = false;
                            LogHelper.Info($"添加硫化工单信息失败,物料条码信息:{JsonConvert.SerializeObject(item)}", "GT");
                        }
                    });
                }
                db.CommitTran();
            }
            catch (Exception ex)
            {
                LogHelper.Info($"添加硫化工单信息错误,错误信息:{ex.Message}", "GT");
                db.RollbackTran();
            }
            return result;
        }
        /// <summary>
        /// 同步条码状态表
        /// </summary>
        /// <returns></returns>
        public static bool synBarcodeStatus(List<iWMS_semi_bld_BCstatus> model)
        {
            bool result = true;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                db.BeginTran();
                if (model.Count > 0)
                {
                    model.ForEach(update => {
                        // 同步条码状态信息表
                        db.Insertable(update).ExecuteCommand();
                        // 同步条码信息表
                        var greenTireInfo = db.Queryable<GreenTireInformation>().Where(a => a.BARCODE == update.S_BC_ENTRIED).First();
                        if (greenTireInfo != null)
                        {
                            greenTireInfo.JDGE = update.S_JDGE;
                            greenTireInfo.LAST_MODIFY_TIME = update.LAST_MODIFY_TIME;
                            db.Updateable(greenTireInfo).ExecuteCommand();
                        }
                        // 同步容器物料表
                        var cntrItemRel = db.Queryable<CntrItemRel>().Where(a => a.S_CG_ID == update.S_BC_ENTRIED).First();
                        if (cntrItemRel != null)
                        {
                            cntrItemRel.S_ITEM_STATE = update.S_JDGE;
                            cntrItemRel.T_MODIFY = DateTime.Now;
                            db.Updateable(cntrItemRel).ExecuteCommand();
                        }
                    });
                }
                db.CommitTran();
            }
            catch (Exception ex)
            {
                LogHelper.Info($"同步条码状态表错误,错误信息:{ex.Message}", "GT");
                db.RollbackTran();
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 同步抽检状态表
        /// </summary>
        /// <returns></returns>
        public static bool synSamplingStatus(List<iWMS_semi_bld_BCsample> model)
        {
            bool result = true;
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                db.BeginTran();
                if (model.Count > 0)
                {
                    model.ForEach(update => {
                        // 同步抽检条码状态信息表
                        db.Insertable(update).ExecuteCommand();
                        // 同步条码信息表
                        var greenTireInfo = db.Queryable<GreenTireInformation>().Where(a => a.BARCODE == update.S_BC_ENTRIED).First();
                        if (greenTireInfo != null)
                        {
                            greenTireInfo.JDGE = update.S_JDGE;
                            greenTireInfo.LAST_MODIFY_TIME = update.LAST_MODIFY_TIME;
                            db.Updateable(greenTireInfo).ExecuteCommand();
                        }
                    });
                }
                db.CommitTran();
            }
            catch (Exception ex)
            {
                LogHelper.Info($"同步抽检状态表错误,错误信息:{ex.Message}", "GT");
                db.RollbackTran();
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 查询上一次的同步时间
        /// </summary>
        /// <param name="tableType">1.成型条码信息 2.硫化机叫料信息 3.条码状态表 4.抽检状态表</param>
        /// <returns></returns>
        public static string getDataLastSynTime(int tableType)
        {
            var db = new SqlHelper<object>().GetInstance();
            string lastTimeStr = null;
            if (tableType == 1)
            {
               var lastTime = db.Queryable<GreenTireInformation>().OrderByDescending(a => a.LAST_MODIFY_TIME).Select(a => a.LAST_MODIFY_TIME).First();
                if (lastTime != null)
                {
                    lastTimeStr = lastTime.ToString("yyyy-MM-dd HH:mm:ss:fff");
                }
            }
            else if (tableType == 2)
            {
               var lastTime = db.Queryable<ProductionShedule>().OrderByDescending(a => a.LAST_MODIFY_TIME).Select(a => a.LAST_MODIFY_TIME).First();
                if (lastTime != null)
                {
                    lastTimeStr = lastTime.ToString("yyyy-MM-dd HH:mm:ss:fff");
                }
            }
            else if (tableType == 3)
            {
            }
            else if (tableType == 4)
            {
            }
            return lastTimeStr;
        }
    }    
}