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;
|
|
/// <summary>
|
/// 货位方法
|
/// </summary>
|
public static class LocationMethod
|
{
|
/// <summary>
|
/// 获取指定接驳位
|
/// </summary>
|
/// <param name="input">作业信息</param>
|
/// <returns></returns>
|
public static Location QueryLocation(OperationDto input)
|
{
|
var location = new Location();
|
int purpose = 0;
|
// 入库(根据终点判断)
|
if (input.taskType == 1 || input.taskType == 3)
|
{
|
purpose = 3;
|
|
// 获取当前终点货位
|
location = AdoSqlMethod<Location>.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<Location>.QueryFirst(p => p.S_CODE == input.startLocation);
|
}
|
|
if (location != null)
|
{
|
// 查询当前出、类型以及对应巷道的接驳位
|
var jbwLocation = AdoSqlMethod<Location>
|
.QueryFirst(p => p.N_PURPOSE == purpose && p.N_ROADWAY == location.N_ROADWAY);
|
|
if (jbwLocation != null)
|
{
|
return jbwLocation;
|
}
|
}
|
|
return null;
|
}
|
|
/// <summary>
|
/// 获取立体库区货位信息
|
/// </summary>
|
/// <param name="containerType">容器类型</param>
|
/// <returns></returns>
|
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;
|
}
|
|
/// <summary>
|
/// 获取立体库区货位信息
|
/// </summary>
|
/// <param name="containerCode"></param>
|
/// <returns></returns>
|
public static Location QueryOutLocation(string containerCode)
|
{
|
var locCntrRel = AdoSqlMethod<LocCntrRel>.QueryFirst(p => p.S_CNTR_CODE == containerCode);
|
|
if (locCntrRel != null)
|
{
|
var location = AdoSqlMethod<Location>.QueryFirst(p => p.S_CODE == locCntrRel.S_LOC_CODE);
|
|
if (location != null)
|
{
|
return location;
|
}
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// 根据优先顺序获取可用货位
|
/// </summary>
|
/// <param name="priority"></param>
|
/// <param name="containerPrioritys"></param>
|
/// <returns></returns>
|
private static Location QueryStereoscopicStorehouseLocation(int priority, Settings.ContainerPrioritys containerPrioritys)
|
{
|
var sqlSugarClient = AdoSqlMethod<object>.QuerySqlSugarClient();
|
|
if (priority == 11)
|
{
|
// 查询出所有该优先级的可用货位
|
var locations = sqlSugarClient.Queryable<Location>()
|
.Where(p => p.N_PRIORITY == priority && p.N_CURRENT_NUM == 0 && p.N_LOCK_STATE == 0 && p.N_PURPOSE == 1).ToList();
|
|
var notQueryList = AdoSqlMethod<Task>
|
.QueryList(p=> p.N_B_STATE < 2 && p.T_CREATE.Date == DateTime.Today && (p.N_TYPE == 1 || p.N_TYPE == 3) && p.N_SCHEDULE_TYPE == 2);
|
|
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<Location>()
|
.Where(p => p.N_PRIORITY == priority && p.N_CURRENT_NUM == 0 && p.N_LOCK_STATE == 0 && p.N_PURPOSE == 1).ToList();
|
|
var notQueryList = AdoSqlMethod<Task>
|
.QueryList(p=> p.N_B_STATE < 2 && p.T_CREATE.Date == DateTime.Today && (p.N_TYPE == 1 || p.N_TYPE == 3) && p.N_SCHEDULE_TYPE == 2);
|
|
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, priority);
|
|
// 5组均分
|
// return SelectOptimaLocationThree(locations, i);
|
|
// 随机分配
|
// return SelectOptimaLocationRandom(locations, i);
|
}
|
}
|
else
|
{
|
foreach (var i in containerPrioritys.priority)
|
{
|
// 查询出所有该优先级的可用货位
|
var locations = sqlSugarClient.Queryable<Location>()
|
.Where(p => p.N_PRIORITY == i && p.N_CURRENT_NUM == 0 && p.N_LOCK_STATE == 0 && p.N_PURPOSE == 1).ToList();
|
|
var notQueryList = AdoSqlMethod<Task>
|
.QueryList(p=> p.N_B_STATE < 2 && p.T_CREATE.Date == DateTime.Today && (p.N_TYPE == 1 || p.N_TYPE == 3) && p.N_SCHEDULE_TYPE == 2);
|
|
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;
|
}
|
|
/// <summary>
|
/// 根据优先顺序获取可用货位(一次五条任务均分巷道)
|
/// </summary>
|
/// <param name="locations"></param>
|
/// <returns></returns>
|
public static Location SelectOptimalLocation(IEnumerable<Location> locations)
|
{
|
// 将该优先级的所有货位进行分组(根据巷道)
|
var list = locations.OrderBy(p => p.N_ROADWAY).GroupBy(p => p.N_ROADWAY).ToList();
|
|
foreach (var item in list)
|
{
|
var rowList = AdoSqlMethod<Location>.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;
|
}
|
|
// /// <summary>
|
// /// 货位分配逻辑(伪均分)
|
// /// </summary>
|
// /// <param name="locations">货位数据集合</param>
|
// /// <param name="priority">货位数据集合</param>
|
// /// <returns></returns>
|
// private static Location SelectOptimalLocationTwo(IEnumerable<Location> locations, int priority)
|
// {
|
// // 对数据进行分组(1组、2组、3组),这里是所有符合条件的货位数据
|
// var groups = locations.GroupBy(p => p.S_GROUP).ToList();
|
//
|
// // 查询最新的任务,判断该任务的分组,(过滤掉对应组的排数据)
|
// var operations = AdoSqlMethod<Operation>.QueryFirstByDecs(p=>p.T_CREATE);
|
//
|
// // 符合条件的货位集合
|
// var locationDtos = new List<LocationDto>();
|
//
|
// // 循环groups
|
// foreach (var grouping in groups)
|
// {
|
// var locationDto = new LocationDto();
|
// locationDto.Group = grouping.Key;
|
// locationDto.Eligibility = grouping.Count();
|
// locationDto.Locklocation = AdoSqlMethod<Location>.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<Location>.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<Location>.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<Location>.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<Location>.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 货位分配(根据匹配的货位进行均分循环)
|
|
/// <summary>
|
/// 货位分配逻辑(伪均分)
|
/// </summary>
|
/// <param name="locations">货位数据集合</param>
|
/// <param name="priority">货位数据集合</param>
|
/// <returns></returns>
|
private static Location SelectOptimalLocationTwo(IEnumerable<Location> locations, int priority)
|
{
|
// 对数据进行分组(1组、2组、3组),这里是所有符合条件的货位数据
|
var groups = locations.GroupBy(p => p.S_GROUP).ToList();
|
|
// 查询最新的任务,判断该任务的分组,(过滤掉对应组的排数据)
|
var operations = AdoSqlMethod<Operation>.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);
|
}
|
|
/// <summary>
|
/// 对已经产生了任务的前两个分组的满货位进行数据操作
|
/// </summary>
|
/// <param name="groups"></param>
|
/// <param name="operations"></param>
|
/// <param name="priority"></param>
|
/// <returns></returns>
|
private static List<LocationDto> GetLocationDtos(List<IGrouping<string, Location>> groups, List<Operation> operations, int priority)
|
{
|
var locationDtos = new List<LocationDto>();
|
|
foreach (var grouping in groups)
|
{
|
var locationDto = new LocationDto
|
{
|
Group = grouping.Key,
|
Eligibility = grouping.Count(),
|
Locklocation = AdoSqlMethod<Location>.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;
|
}
|
|
/// <summary>
|
/// 根据分组key转换成对应的数值类型
|
/// </summary>
|
/// <param name="groupKey"></param>
|
/// <returns></returns>
|
private static int GetGroupNumber(string groupKey)
|
{
|
switch (groupKey)
|
{
|
case "1组":
|
return 1;
|
case "2组":
|
return 2;
|
case "3组":
|
return 3;
|
default:
|
return 0;
|
}
|
}
|
|
/// <summary>
|
/// 判断最终从那个巷道中获取货位
|
/// </summary>
|
/// <param name="locationGroup"></param>
|
/// <param name="groups"></param>
|
/// <param name="priority"></param>
|
/// <returns></returns>
|
private static Location GetOptimalLocation(LocationDto locationGroup, List<IGrouping<string, Location>> 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;
|
}
|
}
|
|
/// <summary>
|
/// 获取货位
|
/// </summary>
|
/// <param name="groups"></param>
|
/// <param name="groupKey"></param>
|
/// <param name="roadways"></param>
|
/// <param name="priority"></param>
|
/// <returns></returns>
|
private static Location GetOptimalLocationInGroup(List<IGrouping<string, Location>> 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<Location>.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
|
|
|
/// <summary>
|
/// 货位均分(平均分配)
|
/// </summary>
|
/// <param name="locations"></param>
|
/// <param name="priority"></param>
|
/// <returns></returns>
|
private static Location SelectOptimaLocationThree(IEnumerable<Location> 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<Location>.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();
|
}
|
|
/// <summary>
|
/// 货位分配(随机分配)
|
/// </summary>
|
/// <param name="locations"></param>
|
/// <param name="priority"></param>
|
/// <returns></returns>
|
private static Location SelectOptimaLocationRandom(IEnumerable<Location> locations, int priority)
|
{
|
var list = locations.ToList();
|
|
// 创建随机数生成器
|
Random random = new Random();
|
|
// 生成随机索引
|
int randomIndex = random.Next(list.Count);
|
|
// 获取随机元素
|
return list[randomIndex];
|
}
|
}
|