using System; using System.Collections.Generic; using System.Linq; using Google.Protobuf; using HH.WCS.Mobox3.RiDong.dto; using HH.WCS.Mobox3.RiDong.models; using HH.WCS.Mobox3.RiDong.util; namespace HH.WCS.Mobox3.RiDong.generalMethod; /// /// 货位方法 /// public static class LocationMethod { /// /// 获取指定接驳位 /// /// 作业信息 /// public static Location QueryLocation(OperationDto input) { var location = new Location(); int purpose = 0; // 入库(根据终点判断) if (input.taskType == 1 || input.taskType == 3) { purpose = 3; // 获取当前终点货位 location = AdoSqlMethod.QueryFirst(p => p.S_CODE == input.endLocation); } // 出库(根据起点判断) else if (input.taskType == 2 || input.taskType == 4 || input.taskType == 5 || input.taskType == 6 || input.taskType == 7) { purpose = 4; // 获取当前起点货位 location = AdoSqlMethod.QueryFirst(p => p.S_CODE == input.startLocation); } if (location != null) { // 查询当前出、类型以及对应巷道的接驳位 var jbwLocation = AdoSqlMethod .QueryFirst(p => p.N_PURPOSE == purpose && p.N_ROADWAY == location.N_ROADWAY); if (jbwLocation != null) { return jbwLocation; } } return null; } /// /// 获取立体库区货位信息 /// /// 容器类型 /// public static Location QueryStereoscopicStorehouseLocation(string containerType) { Location location = new Location(); // 排查出该托盘类型对应的循环数据 var containerPrioritys = Settings.ContainerPrioritysList.First(p=>p.containerType == containerType); // 根据容器类型找不同的优先顺序的货位,因为每个托盘的长宽高是不一样的 switch (containerType) { case "1": case "1a": case "2": case "2a": case "3": case "3a": case "4": case "5": case "6": case "7": location = QueryStereoscopicStorehouseLocation(1, containerPrioritys); break; case "8": location = QueryStereoscopicStorehouseLocation(11,containerPrioritys); break; case "7a": location = QueryStereoscopicStorehouseLocation(12,containerPrioritys); break; default: location = null; break; } return location; } /// /// 获取立体库区货位信息 /// /// /// public static Location QueryOutLocation(string containerCode) { var locCntrRel = AdoSqlMethod.QueryFirst(p => p.S_CNTR_CODE == containerCode); if (locCntrRel != null) { var location = AdoSqlMethod.QueryFirst(p => p.S_CODE == locCntrRel.S_LOC_CODE); if (location != null) { return location; } } return null; } /// /// 根据优先顺序获取可用货位 /// /// /// /// private static Location QueryStereoscopicStorehouseLocation(int priority, Settings.ContainerPrioritys containerPrioritys) { var sqlSugarClient = AdoSqlMethod.QuerySqlSugarClient(); if (priority == 11) { // 查询出所有该优先级的可用货位 var locations = sqlSugarClient.Queryable() .Where(p => p.N_PRIORITY == priority && p.N_CURRENT_NUM == 0 && p.N_LOCK_STATE == 0 && p.N_PURPOSE == 1).ToList(); // 优先查询今日份任务中未完成的(等待,执行中) var notQueryList = AdoSqlMethod.QueryList(p=>p.N_B_STATE < 2 && p.T_CREATE.Date == DateTime.Today); if (notQueryList.Count > 0) { var groupBy = notQueryList.GroupBy(p=>p.N_ROADWAY); foreach (var item in groupBy) { if (item.Key == 1 || item.Key == 2 || item.Key == 3 || item.Key == 4) { locations = locations.Where(p=>p.N_ROADWAY != item.Key).ToList(); } else if (item.Key == 5 && item.ToList().Count >= 3) { locations = locations.Where(p=>p.N_ROADWAY != item.Key).ToList(); } } } // 存在该优先级的可用货位 if (locations.Count > 0) { // 一次五条任务均分巷道 // return SelectOptimalLocation(locations); // 3组均分 return SelectOptimalLocationTwo(locations, priority); // 5组均分 // return SelectOptimaLocationThree(locations, priority); // 随机分配 // return SelectOptimaLocationRandom(locations, priority); } } else if(priority == 12) { // 查询出所有该优先级的可用货位 var locations = sqlSugarClient.Queryable() .Where(p => p.N_PRIORITY == priority && p.N_CURRENT_NUM == 0 && p.N_LOCK_STATE == 0 && p.N_PURPOSE == 1).ToList(); // 存在该优先级的可用货位 if (locations.Count > 0) { // 一次五条任务均分巷道 // return SelectOptimalLocation(i); // 3组均分 return SelectOptimalLocationTwo(locations, priority); // 5组均分 // return SelectOptimaLocationThree(locations, i); // 随机分配 // return SelectOptimaLocationRandom(locations, i); } } else { foreach (var i in containerPrioritys.priority) { // 查询出所有该优先级的可用货位 var locations = sqlSugarClient.Queryable() .Where(p => p.N_PRIORITY == i && p.N_CURRENT_NUM == 0 && p.N_LOCK_STATE == 0 && p.N_PURPOSE == 1).ToList(); // 优先查询今日份任务中未完成的(等待,执行中) var notQueryList = AdoSqlMethod.QueryList(p=>p.N_B_STATE < 2 && p.T_CREATE.Date == DateTime.Today); if (notQueryList.Count > 0) { var groupBy = notQueryList.GroupBy(p=>p.N_ROADWAY); foreach (var item in groupBy) { if (item.Key == 1 || item.Key == 2 || item.Key == 3 || item.Key == 4) { locations = locations.Where(p=>p.N_ROADWAY != item.Key).ToList(); } else if (item.Key == 5 && item.ToList().Count >= 3) { locations = locations.Where(p=>p.N_ROADWAY != item.Key).ToList(); } } } // 存在该优先级的可用货位 if (locations.Count > 0) { // 一次五条任务均分巷道 // return SelectOptimalLocation(i); // 3组均分 return SelectOptimalLocationTwo(locations, i); // 5组均分 // return SelectOptimaLocationThree(locations, i); // 随机分配 // return SelectOptimaLocationRandom(locations, i); } } } return null; } /// /// 根据优先顺序获取可用货位(一次五条任务均分巷道) /// /// /// public static Location SelectOptimalLocation(IEnumerable locations) { // 将该优先级的所有货位进行分组(根据巷道) var list = locations.OrderBy(p => p.N_ROADWAY).GroupBy(p => p.N_ROADWAY).ToList(); foreach (var item in list) { var rowList = AdoSqlMethod.QueryCount(r => r.N_ROADWAY == item.Key && r.N_LOCK_STATE != 0); // 说明没有任务,此时可以随机一个给一个货位数据 if (rowList == 0) { return item.ToList().OrderBy(p => p.N_LAYER).ThenBy(p => p.N_COL).First(); } } return null; } // /// // /// 货位分配逻辑(伪均分) // /// // /// 货位数据集合 // /// 货位数据集合 // /// // private static Location SelectOptimalLocationTwo(IEnumerable locations, int priority) // { // // 对数据进行分组(1组、2组、3组),这里是所有符合条件的货位数据 // var groups = locations.GroupBy(p => p.S_GROUP).ToList(); // // // 查询最新的任务,判断该任务的分组,(过滤掉对应组的排数据) // var operations = AdoSqlMethod.QueryFirstByDecs(p=>p.T_CREATE); // // // 符合条件的货位集合 // var locationDtos = new List(); // // // 循环groups // foreach (var grouping in groups) // { // var locationDto = new LocationDto(); // locationDto.Group = grouping.Key; // locationDto.Eligibility = grouping.Count(); // locationDto.Locklocation = AdoSqlMethod.QueryCount(p => // p.N_PURPOSE == 1 && p.S_GROUP == grouping.Key && p.N_PRIORITY == priority && // (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); // // int group = 0; // // if(grouping.Key == "1组") // group = 1; // if(grouping.Key == "2组") // group = 2; // if(grouping.Key == "3组") // group = 3; // // // 有可用货位,同时上面已经出现过巷道的任务了 // if (operations.Count(p => p.S_EXT_ATTR2 == group) > 0) // { // // 满货位数量+2000(让该分组货位变成最大值) // locationDto.Locklocation += 2000; // } // // locationDtos.Add(locationDto); // } // // // 查找locationDtos中满货位数量最少的分组 // var locationgroup = locationDtos.OrderBy(p=>p.Locklocation).First(); // // // 判断该对象是哪个分组 // if (locationgroup.Group == "1组") // { // // 获取1组中的数据 // var locations1 = groups.First(p=>p.Key == "1组").ToList(); // // // 根据巷道分组 // var roadwaylist = locations1.GroupBy(p=>p.N_ROADWAY).ToList(); // // // 长度大于2,说明1和2巷道都有数据 // if (roadwaylist.Count > 2) // { // // 查询1和2巷道里满货位最少的数据 // int num1 = AdoSqlMethod.QueryCount(p => // p.N_PURPOSE == 1 && p.N_ROADWAY == 1 && p.N_PRIORITY == priority && // (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); // // // 查询1和2巷道里满货位最少的数据 // int num2 = AdoSqlMethod.QueryCount(p => // p.N_PURPOSE == 1 && p.N_ROADWAY == 2 && p.N_PRIORITY == priority && // (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); // // // 获取最少的 // var min = Math.Min(num1, num2); // // // 如果最少数量和巷道2是一致的,则返回2巷道里的货位 // if (min == num2) // { // return roadwaylist.First(p=>p.Key == 2).OrderBy(p => p.N_LAYER) // .ThenBy(p => p.N_COL) // .First(); // } // if (min == num1) // { // return roadwaylist.First(p=>p.Key == 1).OrderBy(p => p.N_LAYER) // .ThenBy(p => p.N_COL) // .First(); // } // } // } // // 判断该对象是哪个分组 // if (locationgroup.Group == "2组") // { // // 获取1组中的数据 // var locations1 = groups.First(p=>p.Key == "2组").ToList(); // // // 根据巷道分组 // var roadwaylist = locations1.GroupBy(p=>p.N_ROADWAY).ToList(); // // // 长度大于2,说明1和2巷道都有数据 // if (roadwaylist.Count > 2) // { // // 查询1和2巷道里满货位最少的数据 // int num1 = AdoSqlMethod.QueryCount(p => // p.N_PURPOSE == 1 && p.N_ROADWAY == 3 && p.N_PRIORITY == priority && // (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); // // // 查询1和2巷道里满货位最少的数据 // int num2 = AdoSqlMethod.QueryCount(p => // p.N_PURPOSE == 1 && p.N_ROADWAY == 4 && p.N_PRIORITY == priority && // (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); // // // 获取最少的 // var min = Math.Min(num1, num2); // // // 如果最少数量和巷道2是一致的,则返回2巷道里的货位 // if (min == num2) // { // return roadwaylist.First(p=>p.Key == 4).OrderBy(p => p.N_LAYER) // .ThenBy(p => p.N_COL) // .First(); // } // if (min == num1) // { // return roadwaylist.First(p=>p.Key == 3).OrderBy(p => p.N_LAYER) // .ThenBy(p => p.N_COL) // .First(); // } // } // } // // 判断该对象是哪个分组 // if (locationgroup.Group == "3组") // { // // 获取3组中的数据 // var locations1 = groups.First(p=>p.Key == "3组").ToList(); // // return locations1.OrderBy(p => p.N_LAYER) // .ThenBy(p => p.N_COL) // .First(); // } // // return null; // } #region 货位分配(根据匹配的货位进行均分循环) /// /// 货位分配逻辑(伪均分) /// /// 货位数据集合 /// 货位数据集合 /// private static Location SelectOptimalLocationTwo(IEnumerable locations, int priority) { // 对数据进行分组(1组、2组、3组),这里是所有符合条件的货位数据 var groups = locations.GroupBy(p => p.S_GROUP).ToList(); // 查询最新的任务,判断该任务的分组,(过滤掉对应组的排数据) var operations = AdoSqlMethod.QueryFirstByDecs(p => p.T_CREATE); // 符合条件的货位集合 var locationDtos = GetLocationDtos(groups, operations, priority); // 查找locationDtos中满货位数量最少的分组 var locationGroup = locationDtos.OrderBy(p => p.Locklocation).First(); return GetOptimalLocation(locationGroup, groups, priority); } /// /// 对已经产生了任务的前两个分组的满货位进行数据操作 /// /// /// /// /// private static List GetLocationDtos(List> groups, List operations, int priority) { var locationDtos = new List(); foreach (var grouping in groups) { var locationDto = new LocationDto { Group = grouping.Key, Eligibility = grouping.Count(), Locklocation = AdoSqlMethod.QueryCount(p => p.N_PURPOSE == 1 && p.S_GROUP == grouping.Key && p.N_PRIORITY == priority && (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)) }; int groupNumber = GetGroupNumber(grouping.Key); // 有可用货位,同时上面已经出现过巷道的任务了 if (operations.Count(p => p.S_EXT_ATTR2 == groupNumber) > 0) { // 满货位数量+2000(让该分组货位变成最大值) locationDto.Locklocation += 2000; } locationDtos.Add(locationDto); } return locationDtos; } /// /// 根据分组key转换成对应的数值类型 /// /// /// private static int GetGroupNumber(string groupKey) { switch (groupKey) { case "1组": return 1; case "2组": return 2; case "3组": return 3; default: return 0; } } /// /// 判断最终从那个巷道中获取货位 /// /// /// /// /// private static Location GetOptimalLocation(LocationDto locationGroup, List> groups, int priority) { switch (locationGroup.Group) { case "1组": return GetOptimalLocationInGroup(groups, "1组", new[] { 1, 2 }, priority); case "2组": return GetOptimalLocationInGroup(groups, "2组", new[] { 3, 4 }, priority); case "3组": var locations3 = groups.First(p => p.Key == "3组").ToList(); return locations3.OrderBy(p => p.N_LAYER) .ThenBy(p => p.N_COL) .First(); default: return null; } } /// /// 获取货位 /// /// /// /// /// /// private static Location GetOptimalLocationInGroup(List> groups, string groupKey, int[] roadways, int priority) { var locationsInGroup = groups.First(p => p.Key == groupKey).ToList(); var roadwayList = locationsInGroup.GroupBy(p => p.N_ROADWAY).ToList(); // 长度大于2,说明1和2巷道都有数据 if (roadwayList.Count == 2) { int[] numArray = new int[roadways.Length]; for (int i = 0; i < roadways.Length; i++) { int group = roadways[i]; numArray[i] = AdoSqlMethod.QueryCount(p => p.N_PURPOSE == 1 && p.N_ROADWAY == group && p.N_PRIORITY == priority && (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); } int minIndex = Array.IndexOf(numArray, numArray.Min()); int minRoadway = roadways[minIndex]; return roadwayList.First(p => p.Key == minRoadway).ToList().OrderBy(p => p.N_LAYER) .ThenBy(p => p.N_COL) .First(); } if(roadwayList.Count == 1) { var locations = roadwayList.First().ToList(); return locations.OrderBy(p => p.N_LAYER) .ThenBy(p => p.N_COL) .First(); } return null; } #endregion /// /// 货位均分(平均分配) /// /// /// /// private static Location SelectOptimaLocationThree(IEnumerable locations, int priority) { // 将该优先级的所有货位进行分组(根据巷道) var list = locations.GroupBy(p => p.N_ROADWAY).ToList(); // 初始化最小键和最小值 int minKey = 0; double minValue = 9999; // 查下每个巷道中的满货位的数量 foreach (var item in list) { var queryCount = AdoSqlMethod.QueryCount(p => p.N_PURPOSE == 1 && p.N_ROADWAY == item.Key && p.N_PRIORITY == priority && (p.N_CURRENT_NUM == 1 || p.N_LOCK_STATE == 1)); if (queryCount < minValue) { minValue = queryCount; // 获取每个巷道中的存储位,数量为1,以及有入库锁的数量 minKey = item.Key; } } return list[minKey].ToList().OrderBy(p => p.N_LAYER).ThenBy(p => p.N_COL).First(); } /// /// 货位分配(随机分配) /// /// /// /// private static Location SelectOptimaLocationRandom(IEnumerable locations, int priority) { var list = locations.ToList(); // 创建随机数生成器 Random random = new Random(); // 生成随机索引 int randomIndex = random.Next(list.Count); // 获取随机元素 return list[randomIndex]; } }