using HH.WCS.Hexafluo; using HH.WCS.Hexafluo.util; using HH.WCS.Hexafluo.wms; using HH.WCS.SJML.Comm; using HH.WCS.SJML.Entitys; using HH.WCS.ZCQTJ.Entitys; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace HH.WCS.SJML.Bll { public class In_AlgorBLL { public InAssignResultEntity InAssign(InAssignEntity model) { //定义返回实体 InAssignResultEntity resultEntity = new InAssignResultEntity(); resultEntity.Msg = ""; resultEntity.errCode = ""; LogHelper.Info("入库算法", "入库算法参数:" + JsonConvert.SerializeObject(model)); var chi = new SqlHelper().GetInstance(); var newDb = chi.CopyNew(); try { #region 传入参数判断 if (model == null) { resultEntity.Success = false; resultEntity.errCode = "6"; resultEntity.Msg = "参数实体不能为 null !"; return resultEntity; } //判断传入库区列表不能为空 if (model.lstAreaPrior == null || model.lstAreaPrior.Count == 0) { resultEntity.Success = false; resultEntity.errCode = "6"; resultEntity.Msg = "指定的入作业库库区列表不能为空!"; return resultEntity; } #endregion //(流离式、平库、立库)标准入库算法 string areaType = newDb.Queryable().Where(e => e.S_AREA_CODE == model.lstAreaPrior[0].areaCode).First()?.S_NOTE; if (string.IsNullOrEmpty(areaType)) { resultEntity.Success = false; resultEntity.errCode = "6"; resultEntity.Msg = "终点的库区类型为空!"; return resultEntity; } if (areaType == Constants.Area_Struc_PingStock || areaType == Constants.Area_Struc_LiStock) { resultEntity = FlatAreaGetLocation(model); } else { throw new Exception("入库的库区类型 即不是平库也不是立库"); } resultEntity.areaType = areaType; LogHelper.Info("入库算法", "入库返回结果:" + JsonConvert.SerializeObject(resultEntity)); return resultEntity; } catch (Exception ex) { LogHelper.Info("入库算法", "异常日志:" + ex.Message); resultEntity.errCode = "5"; resultEntity.Msg = "算法异常," + ex.Message; return resultEntity; } } public InAssignResultEntity FlatAreaGetLocation(InAssignEntity model) { InAssignResultEntity resultEntity = new InAssignResultEntity(); resultEntity.Success = false; List lstTrueLocation = new List();//货位实体 List lstTmpLocation = new List();//货位实体 List lstALR = null;//逻辑分区 List lstLocation = new List(); List lstLockLItem = new List(); List locationInLock = new List(); List lstEmptyLocation = new List(); List lstTrueLItem = new List(); List lstAreaPrior = model.lstAreaPrior.OrderByDescending(o => o.Prior).ToList(); StringBuilder sbDetailError = new StringBuilder(); var chi = new SqlHelper().GetInstance(); var newDb = chi.CopyNew(); #region 从autobom和货位扩展表中获取可用货位集合 //按优先级循环处理库区获取可用货位集合 foreach (areaPriorClass item in lstAreaPrior) { TN_AreaEntitys areaModel = newDb.Queryable().Where(e => e.S_AREA_CODE == item.areaCode.ToString()).First(); model.stockCode = areaModel.S_WH_CODE; resultEntity.isControlQty = areaModel.S_CONTROL_QTY; resultEntity.areaCode = item.areaCode; //这里判断库区是否可用 并且哪些巷道可用 且必须库区类型是立库 var Subs = Expressionable.Create(); Subs.And(it => it.S_WH_CODE == areaModel.S_WH_CODE); Subs.And(it => it.S_AREA_CODE == item.areaCode); // Subs.And(it => it.S_IS_IN_OUT == "入库"); var Subsidiary = newDb.Queryable().Where(Subs.ToExpression()).ToList(); List tNs = new List();//将不能入的接驳位放进去 var IsJb = newDb.Queryable().Where(e => e.S_IsOpen == "N").ToList(); LogHelper.Info("入库算法", "关闭的接驳位:" + JsonConvert.SerializeObject(IsJb)); //筛选出辅助表里入库的 var ttg = Subsidiary.FindAll(e => e.S_IS_IN_OUT == "入库" && e.S_FlowNo == item.S_FlowNo).ToList(); foreach (var itm in ttg) { var Location = itm.S_CONNECTION.Split(',').ToList(); bool pp = false; foreach (var em in Location) { if (IsJb.FindAll(e => e.S_JbBit == em).ToList().Count() == 0) { pp = true; } } if (!pp) { tNs.Add(itm); } } if (model.needCalLock) { model.lockLocation = resultEntity.isControlQty.Equals("Y") ? true : false;//不管控数量时,不锁定目的货位 } //定义传入变量实体 获取可用货位集合 LogicTrue logicModel = new LogicTrue(); logicModel.stockCode = ""; if (string.IsNullOrEmpty(model.logicAreaCode)) { logicModel.type = 2; logicModel.areaCode = item.areaCode; } else { //只支持逻辑分区关联货位、库区 logicModel.areaCode = item.areaCode; var Texp = Expressionable.Create(); Texp.AndIF(!string.IsNullOrEmpty(model.logicAreaCode), it => it.S_ZONAL_CODE == model.logicAreaCode); Texp.And(it => it.S_AREA_CODE == item.areaCode); Texp.And(it => it.S_START_USING == "Y"); lstALR = newDb.Queryable().Where(Texp.ToExpression()).ToList(); // CreateDAL().GetLocationByLogicArea(model.logicAreaCode, item.areaCode); if (lstALR != null && lstALR.Count > 0) { if (lstALR[0].S_TYPE == 2) { logicModel.type = 2; logicModel.areaCode = item.areaCode; } else if (lstALR[0].S_TYPE == 3) { logicModel.type = 3; logicModel.lstLocationCode = lstALR.Where(o => o.S_TYPE == 3).Select(o => o.S_LOCATION_CODE).ToList(); } } if (!string.IsNullOrEmpty(model.logicAreaCode) && lstALR.Count() == 0) { resultEntity.Success = false; resultEntity.errCode = "8"; resultEntity.Msg = "当有指定逻辑分区编号的时候,逻辑分区表必须要有与之对应的数据"; return resultEntity; } } //获取在autobom中可用货位的集合(去除废弃的货位) LogHelper.Info("入库算法", "求可用货位的logicModel参数:" + JsonConvert.SerializeObject(logicModel)); lstLocation = LocationTrue(logicModel); // LogHelper.Info("入库算法", $"lstLocation {lstLocation.Count()}"); //获取在货位扩展表中可用的货位的集合(去除锁定的货位) lstEmptyLocation.AddRange(lstLocation); lstTrueLocation.AddRange(lstLocation); lstTrueLItem = lstLocation.ToList(); // LogHelper.Info("入库算法", $"lstTrueLItem {lstTrueLItem.Count()}"); // LogHelper.Info("入库算法", "没锁且当前容量等于0的货位有:" + JsonConvert.SerializeObject(lstLocation)); #region 密集型库区定制代码 //获取入库算法策略 var exp = Expressionable.Create(); exp.And(it => it.S_WH_CODE == model.stockCode); exp.And(it => it.S_AREA_CODE == resultEntity.areaCode); exp.And(it => it.S_STRATEGY_TYPE == "入库"); exp.And(it => it.S_START_USING == "Y"); List lstStrategy = newDb.Queryable().Where(exp.ToExpression()).ToList(); //获取预出库锁定的货位 if (lstStrategy.Select(o => o.S_STRATEGY_CODE).ToList().Contains("FirstInLastOut"))//先进后出 { var loca = Expressionable.Create(); loca.And(it => it.S_WH_CODE == model.stockCode); loca.And(it => it.S_AREA_CODE == resultEntity.areaCode); loca.And(it => logicModel.lstLocationCode.Contains(it.S_LOC_CODE)); loca.And(it => it.S_LOCK_STATE == "出库锁"); List locationOutLock = newDb.Queryable().Where(loca.ToExpression()).ToList(); LogHelper.Info("入库算法", "当前有出库锁的货位:" + JsonConvert.SerializeObject(locationOutLock)); foreach (Location lEntity in locationOutLock) { lstTrueLItem.RemoveAll(o => o.N_ROW == lEntity.N_ROW && o.N_COL == lEntity.N_COL && o.N_LAYER == lEntity.N_LAYER); } LogHelper.Info("入库算法", "去除预出库锁定后的lstTrueLItem数据:" + JsonConvert.SerializeObject(lstTrueLItem)); //去除被外侧预入库锁定的货位 var lca = Expressionable.Create(); lca.And(it => it.S_WH_CODE == model.stockCode); lca.And(it => it.S_AREA_CODE == resultEntity.areaCode); lca.And(it => logicModel.lstLocationCode.Contains(it.S_LOC_CODE)); lca.And(it => it.S_LOCK_STATE == "入库锁"); locationInLock = newDb.Queryable().Where(lca.ToExpression()).ToList(); LogHelper.Info("入库算法", "当前有入库锁的货位:" + JsonConvert.SerializeObject(locationOutLock)); foreach (Location lEntity in locationInLock) { lstTrueLItem.RemoveAll(o => o.N_ROW == lEntity.N_ROW && o.N_COL == lEntity.N_COL && o.N_LAYER == lEntity.N_LAYER && o.N_SIDE > lEntity.N_SIDE); lstTrueLItem.RemoveAll(o => o.N_ROW == lEntity.N_ROW && o.N_COL == lEntity.N_COL && o.N_LAYER == lEntity.N_LAYER && o.N_SIDE < lEntity.N_SIDE); } //去除被外侧货物阻挡的货位 var ca = Expressionable.Create(); ca.And(it => it.S_WH_CODE == model.stockCode); ca.And(it => it.S_AREA_CODE == resultEntity.areaCode); var locations = newDb.Queryable().Where(ca.ToExpression()).ToList(); LogHelper.Info("入库算法", "locations数据:" + JsonConvert.SerializeObject(locations)); foreach (Location itemC in locations) { lstTrueLItem.RemoveAll(o => o.N_ROW == itemC.N_ROW && o.N_COL == itemC.N_COL && o.N_LAYER == itemC.N_LAYER && o.N_SIDE > itemC.N_SIDE); } LogHelper.Info("入库算法", "去除阻挡后的lstTrueLItem数据:" + JsonConvert.SerializeObject(lstTrueLItem)); } #endregion #region 地堆型库区定制代码 if (areaModel.S_AREA_TYPE == "地堆") { if (lstTrueLItem.Count > 0) { var Inloca = Expressionable.Create(); Inloca.And(it => it.S_WH_CODE == model.stockCode); Inloca.And(it => it.S_AREA_CODE == resultEntity.areaCode); Inloca.And(it => logicModel.lstLocationCode.Contains(it.S_LOC_CODE)); Inloca.And(it => it.S_LOCK_STATE == "入库锁"); locationInLock = newDb.Queryable().Where(Inloca.ToExpression()).ToList(); foreach (Location lEntity in locationInLock) { lstTrueLItem.RemoveAll(o => o.N_ROW == lEntity.N_ROW); } LogHelper.Info("入库算法", "过滤预入库锁定货位后的数据:" + JsonConvert.SerializeObject(lstTrueLItem)); var Outloca = Expressionable.Create(); Outloca.And(it => it.S_WH_CODE == model.stockCode); Outloca.And(it => it.S_AREA_CODE == resultEntity.areaCode); Outloca.And(it => logicModel.lstLocationCode.Contains(it.S_LOC_CODE)); Outloca.And(it => it.S_LOCK_STATE == "出库锁"); List locationOutLock = newDb.Queryable().Where(Outloca.ToExpression()).ToList(); foreach (Location lEntity in locationOutLock) { lstTrueLItem.RemoveAll(o => o.N_ROW == lEntity.N_ROW); } LogHelper.Info("入库算法", "过滤预出库锁定货位后的数据:" + JsonConvert.SerializeObject(lstTrueLItem)); lstTrueLItem = lstTrueLItem.OrderBy(c => c.N_ROW).ThenBy(e => e.N_COL).ToList(); } } #endregion //判断库区是否为立库 如果是则经过二次过滤 if (areaModel.S_NOTE == Constants.Area_Struc_LiStock) { if (Subsidiary.Any()) { if (Subsidiary.FindAll(e => e.S_AREA_TYPE != Constants.Area_Struc_LiStock).Count() == 0) { //先排除掉不可用巷道 var SubNo = Subsidiary.FindAll(e => e.N_Y_ROADWAY == "N").ToList(); if (model.S_Roadway.Count() > 0) { LogHelper.Info("入库算法", $"入参固定巷道{JsonConvert.SerializeObject(model.S_Roadway)} "); lstTrueLItem = lstTrueLItem.FindAll(e => model.S_Roadway.Contains(e.N_ROADWAY.ToString())); // LogHelper.Info("入库算法", $"入参固定巷道 选择后符合条件的货位{JsonConvert.SerializeObject(lstTrueLItem)} "); } if (SubNo.Any() && model.IsChangeBit == 0) { foreach (var Su in SubNo) { lstTrueLItem.RemoveAll(e => e.N_ROADWAY == Su.N_ROADWAY); LogHelper.Info("入库算法", $"巷道关闭移除对应巷道 {Su.N_ROADWAY}"); } } if (tNs.Any()) { foreach (var Su in tNs) { lstTrueLItem.RemoveAll(e => e.N_ROADWAY == Su.N_ROADWAY); LogHelper.Info("入库算法", $"接驳位关闭移除对应巷道 {Su.N_ROADWAY}"); } } if (item.areaCode == "LC11M") { //查询几个特殊的接驳位 var Jbw1 = IsJb.Find(e => e.S_JbBit == "TMRKHCW-01"); var Jbw2 = IsJb.Find(e => e.S_JbBit == "TMRKJBW-01"); var Jbw3 = IsJb.Find(e => e.S_JbBit == "TMRKHCW-02"); var Jbw4 = IsJb.Find(e => e.S_JbBit == "TMRKJBW-04"); if (Jbw1 != null && Jbw2 != null) { lstTrueLItem.RemoveAll(e => e.N_ROADWAY == 1); LogHelper.Info("入库算法", $"LC11M库 巷道中间的接驳位和可入巷道的接驳位都关闭了则排除巷道 1"); } if (Jbw3 != null && Jbw4 != null) { lstTrueLItem.RemoveAll(e => e.N_ROADWAY == 4); LogHelper.Info("入库算法", $"LC11M库 巷道中间的接驳位和可入巷道的接驳位都关闭了则排除巷道 4"); } } var Sudiary = Subsidiary.GroupBy(e => e.N_ROADWAY).Select(c => c.First()).ToList(); // LogHelper.Info("入库算法", $"Sudiary {JsonConvert.SerializeObject(Sudiary)}"); //lstTrueLItem = (from l1 in lstTrueLItem // join l2 in Subsidiary // on l1.N_ROADWAY equals l2.N_ROADWAY // orderby l2.N_ROADWAY descending // select l1).ToList(); lstTrueLItem = (from l1 in lstTrueLItem join l2 in Sudiary on l1.N_ROADWAY equals l2.N_ROADWAY orderby l2.N_ROADWAY_PRIORITY descending select l1).ToList(); // LogHelper.Info("入库算法", $"lstTrueLItem {lstTrueLItem.Count()}"); } } if (resultEntity.areaCode == "LC11L" && !string.IsNullOrEmpty(model.itemCode)) { lstTrueLItem.RemoveAll(e => e.N_LAYER == 5); LogHelper.Info("入库算法", $"满托移除第五层货位"); } if (lstTrueLItem.Count > 0 && (resultEntity.areaCode == "LC11L" || resultEntity.areaCode == "LC11X")) { List Remo = new List(); var gghhj = lstTrueLItem.GroupBy(e => e.N_ROADWAY).Select(c => c.First()).ToList(); foreach (var gg in gghhj) { var RemoL = lstTrueLItem.FindAll(e => e.N_ROADWAY == gg.N_ROADWAY).ToList().Take(2); if (RemoL != null && RemoL.Count() > 0) { foreach (var aaaf in RemoL) { Remo.Add(aaaf); } } } LogHelper.Info("入库算法", $"固定排除两个货位:{JsonConvert.SerializeObject(Remo)} "); if (Remo.Count > 0) { foreach (var ro in Remo) { lstTrueLItem.Remove(ro); } } } } if (lstTrueLItem.Count > 0) { if (resultEntity.isControlQty == "N") { //该库区中的货位如果为不管控数量,则对所有货位平均分配入库任务 resultEntity = AverageLocation(lstTrueLItem, model.lockLocation, resultEntity.isControlQty); } else { if (resultEntity.areaCode == "LC11L" && string.IsNullOrEmpty(model.itemCode)) { var ggj = lstTrueLItem.FindAll(e => e.N_LAYER == 5).ToList(); if (ggj.Count() > 0) { LogHelper.Info("入库算法", $"空托有五层时 只算五层的"); lstTrueLItem = ggj; } } //根据入库策略计算货位 resultEntity = CalLocationByStraty(resultEntity, lstTrueLItem, lstLocation, lstLockLItem, model.lockLocation, logicModel); } } if (resultEntity.Success) { break; } } if (!resultEntity.Success) { if (lstEmptyLocation == null || lstEmptyLocation.Count == 0) { resultEntity.Success = false; resultEntity.errCode = "8"; resultEntity.Msg = "空货位不足"; return resultEntity; } if (lstTrueLocation == null || lstTrueLocation.Count == 0) { resultEntity.Success = false; resultEntity.errCode = "8"; resultEntity.Msg = "两表关联后无可用的货位!请根据ID在日志管理中查询详细原因"; return resultEntity; } resultEntity.Success = false; resultEntity.errCode = "8"; resultEntity.Msg = "启用策略后无可用的货位"; return resultEntity; } #endregion return resultEntity; } public List LocationTrue(LogicTrue model) { List locationCodes = new List(); List lstLocation = new List(); var chi = new SqlHelper().GetInstance(); var newDb = chi.CopyNew(); var exp = Expressionable.Create(); exp.AndIF(model.type == 1, (it, b) => it.S_WH_CODE == model.stockCode); exp.AndIF(model.type == 2, (it, b) => it.S_AREA_CODE == model.areaCode); exp.AndIF(model.type == 3, (it, b) => model.lstLocationCode.Contains(it.S_LOC_CODE)); exp.And((it, b) => it.S_LOCK_STATE == "无"); exp.And((it, b) => it.C_ENABLE == "Y"); exp.And((it, b) => it.N_CURRENT_NUM == 0); exp.And((it, b) => string.IsNullOrEmpty(b.S_CNTR_CODE)); lstLocation = newDb.Queryable().LeftJoin((it, b) => it.S_LOC_CODE == b.S_LOC_CODE).Where(exp.ToExpression()).ToList(); return lstLocation; } private InAssignResultEntity AverageLocation(List lstTrueLocation, bool lockLocation, string isControlQty) { InAssignResultEntity resultEntity = new InAssignResultEntity(); //策略实体 TN_ArithmeticEntitys Trctics = new TN_ArithmeticEntitys(); Location at_l_Entity = AverageBalance(lstTrueLocation); //bool result = CreateDAL().UpdateLocationTaskQty(at_l_Entity.CN_S_LOCATION_CODE, at_l_Entity.CN_N_INTASK_QTY + 1); resultEntity.Success = true; resultEntity.Msg = ""; resultEntity.locationCode = at_l_Entity.S_LOC_CODE; resultEntity.stockCode = at_l_Entity.S_WH_CODE; return resultEntity; } #region 货位平均使用原则 只返回一个货位实体 /// /// 货位平均使用原则 /// /// 一个巷道内的所有货位数据 /// public Location AverageBalance(List lstTrueLocation) { Location nearLocationEntity = new Location(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return nearLocationEntity; } //按照排分组 并获得排中可用货位的数据 var v = lstTrueLocation.OrderBy(o => o.N_ROW).OrderByDescending(c => c.N_COL).ToList();//按照货位可用数量进行升序, 找到CN_N_INTASK_QTY最小的货位 nearLocationEntity = v.FirstOrDefault(); return nearLocationEntity; } #endregion /// /// 获取平库立库货架中最近的一个可用货位 /// /// /// /// /// private InAssignResultEntity CalLocationByStraty(InAssignResultEntity resultEntity, List lstTrueLocation, List lstAllLocation, List lstLockLItem, bool lockLocation, LogicTrue logicModel) { List lstTmp_Location = new List(); #region 查询该库区配置的入库策略及优先级 List lstStrategy = new List(); var exp = Expressionable.Create(); var chi = new SqlHelper().GetInstance(); var newDb = chi.CopyNew(); // exp.And(it => it.S_WH_CODE == resultEntity.stockCode); exp.And(it => it.S_AREA_CODE == resultEntity.areaCode); exp.And(it => it.S_STRATEGY_TYPE == "入库"); exp.And(it => it.S_START_USING == "Y"); lstStrategy = newDb.Queryable().Where(exp.ToExpression()).ToList(); // List lstStrate = lstStrategy.OrderByDescending(a => a.I_PRIORITY).Select(o => o.S_STRATEGY_CODE).ToList(); #endregion LogHelper.Info("入库算法", "循环前lstTmp_Location数据:" + JsonConvert.SerializeObject(lstTmp_Location)); lstTmp_Location = CalculateLocByStegy(lstTrueLocation, lstAllLocation, lstLockLItem, lstStrategy, logicModel); LogHelper.Info("入库算法", "循环后lstTmp_Location数据:" + JsonConvert.SerializeObject(lstTmp_Location)); if (lstTmp_Location == null || lstTmp_Location.Count == 0) { resultEntity.Success = false; resultEntity.errCode = "8"; resultEntity.Msg = "库区有空货位但启用算法策略后计算出货位不足"; return resultEntity; } Location at_l_Entity = lstTmp_Location[0]; if (lockLocation) { #region 锁定入库货位 newDb.BeginTran(); try { var I = newDb.Updateable().SetColumns(it => it.S_LOCK_STATE == "入库锁").Where(x => x.S_LOC_CODE == at_l_Entity.S_LOC_CODE && x.S_LOCK_STATE == "无").ExecuteCommand(); if (I == 0) { newDb.RollbackTran(); throw new System.Exception("锁定终点货位失败!"); } newDb.CommitTran(); LogHelper.Info("入库算法", at_l_Entity.S_LOC_CODE + "货位更改为入库锁,锁定影响数据结果:" + I); if (I > 0) { resultEntity.Success = true; resultEntity.Msg = ""; resultEntity.locationCode = at_l_Entity.S_LOC_CODE; resultEntity.stockCode = at_l_Entity.S_WH_CODE; } else { resultEntity.Success = false; resultEntity.errCode = "5"; resultEntity.Msg = "锁定货位状态失败"; } } catch (Exception ex) { newDb.RollbackTran(); resultEntity.Success = false; resultEntity.errCode = "5"; resultEntity.Msg = "锁定货位状态失败"; } #endregion } else { resultEntity.Success = true; resultEntity.Msg = ""; resultEntity.locationCode = at_l_Entity.S_LOC_CODE; resultEntity.stockCode = at_l_Entity.S_WH_CODE; } return resultEntity; } /// /// 根据入库策略筛选符合条件的货位 /// /// /// /// /// /// public List CalculateLocByStegy(List lstLocation, List lstAllLocation, List lstLockLItem, List lstStrategy, LogicTrue logicModel) { List lstFilterLoc = lstLocation; List lstTmp = new List(); TN_ArithmeticEntitys Trctics = new TN_ArithmeticEntitys(); List lstStrate = lstStrategy.OrderByDescending(a => a.I_PRIORITY).Select(o => o.S_STRATEGY_CODE).ToList(); foreach (string stegy in lstStrate) { //逐个策略进行计算 switch (stegy) { case "TaskNumberBalance"://任务均衡 lstFilterLoc = TaskNumberBalance(lstFilterLoc); break; case "RoadWayBalance": //巷道均衡 lstFilterLoc = RoadWayBalance(lstFilterLoc); break; case "NearByRoadWay": //巷道由近及远 lstFilterLoc = RoadWayBalance(lstFilterLoc); break; case "NearbyBalance": //就近原则 lstFilterLoc = NearbyBalance(lstFilterLoc); break; case "DistantBalance": //就远原则 lstFilterLoc = DistantBalance(lstFilterLoc); break; case "NearbyBalanceLayRe": //一左一右放 lstFilterLoc = NearbyBalanceLayRe(lstFilterLoc); break; case "NearbyBalanceRow": //排就近原则 lstFilterLoc = NearbyBalanceRow(lstFilterLoc); break; case "NearbyBalanceLay": //层就近原则 lstFilterLoc = NearbyBalanceLay(lstFilterLoc); break; case "EmptyFullPercentageBalance"://空满百分比均衡 lstFilterLoc = EmptyFullPercentageBalance(lstFilterLoc, logicModel); break; } } return lstFilterLoc; } #region 巷道均衡 返回巷道对应的货位列表 /// /// 巷道均衡策略 /// /// 可用的货位信息数据 /// 计算后返回的实体 public List RoadWayBalance(List lstTrueLocation) { //指定计算后返回的实体 List location_roadray = new List(); //按照巷道分组 并获得巷道中可用货位的数据 //之后进行倒叙 找到可用货位最多的巷道 var v = lstTrueLocation.GroupBy(x => x.N_ROADWAY).Select(g => (new { roadWay = g.Key, qty = g.Count() })).OrderByDescending(o => o.qty); //倒叙排列后的巷道 循环 foreach (var item in v) { //取得巷道列表中可用货位最多的巷道 并获取巷道中所有货位 location_roadray = lstTrueLocation.Where(o => o.N_ROADWAY == item.roadWay).ToList(); if (location_roadray != null && location_roadray.Count > 0) { break; } } return location_roadray; } #endregion #region 任务数均衡 /// /// 任务数均衡 /// /// /// public List TaskNumberBalance(List lstTrueLocation) { var model = lstTrueLocation.FirstOrDefault(); var Roadray = lstTrueLocation.Select(e => e.N_ROADWAY).Distinct().ToList(); var Inloca = Expressionable.Create(); Inloca.And(it => it.S_WH_CODE == model.S_WH_CODE); Inloca.And(it => it.S_AREA_CODE == model.S_AREA_CODE); Inloca.And(it => Roadray.Contains(it.N_ROADWAY)); Inloca.And(it => it.S_LOCK_STATE == "入库锁"); var locationInLock = SqlSugarHelper.Db.Queryable().Where(Inloca.ToExpression()).ToList(); //LogHelper.Info("入库算法", "查询入库锁的数据:" + JsonConvert.SerializeObject(locationInLock)); if (locationInLock.Count() == 0) { return lstTrueLocation; } else { var InLock = locationInLock.Select(e => e.N_ROADWAY).Distinct().ToList(); // LogHelper.Info("入库算法", "筛序出第一次出现的接驳位 (分组):" + JsonConvert.SerializeObject(InLock)); var ffr = Roadray.Except(InLock).ToList(); // LogHelper.Info("入库算法", "筛序出 所有入库的巷道和有任务的巷道的差集:" + JsonConvert.SerializeObject(ffr)); if (ffr.Count > 0) { var lstTLocation = lstTrueLocation.FindAll(e => ffr.Contains(e.N_ROADWAY)).ToList(); // LogHelper.Info("入库算法", "筛序出--所有入库的巷道和有任务的巷道的差集所在的巷道的货位:" + JsonConvert.SerializeObject(lstTLocation)); if (lstTLocation.Count() > 0) { return lstTLocation; } else { return lstTrueLocation; } } else { var gg = locationInLock.GroupBy(x => x.N_ROADWAY).Select(g => (new { roadWay = g.Key, qty = g.Count() })).OrderBy(o => o.qty).ToList(); // LogHelper.Info("入库算法", "筛选出--没有差集则进行分组算任务量:" + JsonConvert.SerializeObject(gg)); var v = locationInLock.GroupBy(x => x.N_ROADWAY).Select(g => (new { roadWay = g.Key, qty = g.Count() })).OrderBy(o => o.qty).ToList().FirstOrDefault(); // LogHelper.Info("入库算法", "筛选出--没有差集则进行分组算任务量 排序取第一个:" + JsonConvert.SerializeObject(v)); var lseLocation = lstTrueLocation.FindAll(e => e.N_ROADWAY == v.roadWay).ToList(); // LogHelper.Info("入库算法", "筛选出--查询出筛选出的第一个巷道的所有货位数据:" + JsonConvert.SerializeObject(lseLocation)); if (lseLocation.Count() > 0) { return lseLocation; } return lstTrueLocation; } } } #endregion #region 就近原则 只返回一个货位实体 /// /// 就近原则 /// /// 一个巷道内的所有货位数据 /// public List NearbyBalance(List lstTrueLocation) { List lstNearLocation = new List(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return lstNearLocation; } //先判断是否存在多个巷道,如果存在就近选择一个巷道 var location_roadray = lstTrueLocation.OrderBy(o => o.N_ROADWAY).Select(o => o.N_ROADWAY).Distinct().ToList(); if (location_roadray != null && location_roadray.Count > 1) { lstTrueLocation = lstTrueLocation.Where(o => o.N_ROADWAY == location_roadray[0]).ToList(); } //找到最小的列 var v_col = lstTrueLocation.OrderBy(o => o.N_ROW).ThenBy(o => o.N_COL).ToList(); //找到一个排下最小的列对应的所有货位 找层 var v_f = v_col.Where(o => o.N_COL == v_col[0].N_COL && o.N_ROW == v_col[0].N_ROW).OrderBy(o => o.N_LAYER).ToList(); //找到符合条件的层的内侧 var v_side = v_f.Where(o => o.N_LAYER == v_f[0].N_LAYER).OrderByDescending(o => o.N_SIDE).ToList(); var max_side = v_side[0].N_SIDE; //获得侧最大的货位 lstNearLocation.Add(v_side.Where(o => o.N_SIDE == max_side).FirstOrDefault()); return lstNearLocation; } #endregion public List NearbyBalanceLayRe(List lstTrueLocation) { List lstNearLocation = new List(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return lstNearLocation; } //先判断是否存在多个巷道,如果存在就近选择一个巷道 var location_roadray = lstTrueLocation.OrderBy(o => o.N_ROADWAY).Select(o => o.N_ROADWAY).Distinct().ToList(); if (location_roadray != null && location_roadray.Count > 1) { lstTrueLocation = lstTrueLocation.Where(o => o.N_ROADWAY == location_roadray[0]).ToList(); } var v_col = lstTrueLocation.OrderBy(e => e.N_LAYER).ThenByDescending(o => o.N_SIDE).ThenBy(e => e.N_ROW).ThenBy(o => o.N_COL).ToList(); //LogHelper.Info("入库算法", "排序后:" + JsonConvert.SerializeObject(v_col)); //获得侧最大的货位 lstNearLocation.Add(v_col.FirstOrDefault()); return lstNearLocation; } #region 就远原则 只返回一个货位实体 /// /// 就远原则 /// /// 一个巷道内的所有货位数据 /// public List DistantBalance(List lstTrueLocation) { List lstNearLocation = new List(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return lstNearLocation; } //先判断是否存在多个巷道,如果存在就近选择一个巷道 var location_roadray = lstTrueLocation.OrderBy(o => o.N_ROADWAY).Select(o => o.N_ROADWAY).Distinct().ToList(); if (location_roadray != null && location_roadray.Count > 1) { var len = location_roadray.Count - 1; lstTrueLocation = lstTrueLocation.Where(o => o.N_ROADWAY == location_roadray[len]).ToList(); } //找到最大的列 var v_col = lstTrueLocation.OrderByDescending(o => o.N_ROW).ThenByDescending(o => o.N_COL).ToList(); //找到一个排下最小的列对应的所有货位 找层 var v_f = v_col.Where(o => o.N_COL == v_col[0].N_COL && o.N_ROW == v_col[0].N_ROW).OrderBy(o => o.N_LAYER).ToList(); //找到符合条件的层的内侧 var v_side = v_f.Where(o => o.N_LAYER == v_f[0].N_LAYER).OrderByDescending(o => o.N_SIDE).ToList(); var max_side = v_side[0].N_SIDE; //获得侧最大的货位 lstNearLocation.Add(v_side.Where(o => o.N_SIDE == max_side).FirstOrDefault()); return lstNearLocation; } #endregion public List NearbyBalanceRow(List lstTrueLocation) { List lstNearLocation = new List(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return lstNearLocation; } //先判断是否存在多个巷道,如果存在就近选择一个巷道 var location_row = lstTrueLocation.OrderBy(o => o.N_ROW).Select(o => o.N_ROW).Distinct().ToList(); //找到排空货位最多的排 var v_row = lstTrueLocation.Where(o => o.N_ROW == location_row[0]).ToList(); //找到最小的列 var v_col = v_row.OrderBy(o => o.N_COL).ToList(); var min_col = v_col[0].N_COL; //找到一个排下最小的列对应的所有货位 var v_f = v_row.Where(o => o.N_COL == min_col).OrderBy(o => o.N_LAYER).ToList(); //先按照层倒叙取最小的层 var min_floor = v_f[0].N_LAYER; //获得层最小的单个 lstNearLocation.Add(v_f.Where(o => o.N_LAYER == min_floor).FirstOrDefault()); return lstNearLocation; } public List NearbyBalanceLay(List lstTrueLocation) { List lstNearLocation = new List(); if (lstTrueLocation == null || lstTrueLocation.Count == 0) { return lstNearLocation; } //先判断是否存在多个巷道,如果存在就近选择一个巷道 var location_roadray = lstTrueLocation.OrderBy(o => o.N_ROADWAY).Select(o => o.N_ROADWAY).Distinct().ToList(); if (location_roadray != null && location_roadray.Count > 1) { lstTrueLocation = lstTrueLocation.Where(o => o.N_ROADWAY == location_roadray[0]).ToList(); } //找到最小的排 层 侧 var v_col = lstTrueLocation.OrderBy(o => o.N_ROW).ThenBy(o => o.N_LAYER).ThenByDescending(e => e.N_SIDE).ThenBy(e => e.N_COL).ToList(); //获得侧最大的货位 lstNearLocation.Add(v_col.FirstOrDefault()); return lstNearLocation; } public static int I = 0; public List EmptyFullPercentageBalance(List lstTrueLocation, LogicTrue logicModel) { Dictionary percentage = new Dictionary(); var location_roadray = lstTrueLocation.OrderBy(o => o.N_ROADWAY).Select(o => o.N_ROADWAY).Distinct().ToList(); if (logicModel != null && logicModel?.lstLocationCode?.Count() > 0) { var Inloca = Expressionable.Create(); Inloca.And(it => logicModel.lstLocationCode.Contains(it.S_LOC_CODE)); Inloca.And(it => it.C_ENABLE == "Y"); var locationInLock = SqlSugarHelper.Db.Queryable().Where(Inloca.ToExpression()).ToList(); foreach (var item in location_roadray) { LogHelper.Info("入库算法", $"开始巷道:{item}"); var ggf = lstTrueLocation.FindAll(e => e.N_ROADWAY == item).ToList();//空货位数 var ffg = locationInLock.FindAll(e => e.N_ROADWAY == item).ToList();//总货位数 LogHelper.Info("入库算法", $"空货位数:{ggf.Count()}"); LogHelper.Info("入库算法", $"总货位数:{ffg.Count()}"); double Bfb = ((double)ggf.Count() / (double)ffg.Count()) * 100; // var ff = Math.Round(Bfb, 2); LogHelper.Info("入库算法", $"巷道:{item} 空满比例{Bfb}%"); percentage.Add(item, Bfb); } var abc = percentage.OrderByDescending(e => e.Value).ToDictionary(x => x.Key, x => x.Value); var roa = abc.First().Key; lstTrueLocation = lstTrueLocation.FindAll(e => e.N_ROADWAY == roa).ToList(); } else { var model = lstTrueLocation.FirstOrDefault(); var Roadray = lstTrueLocation.Select(e => e.N_ROADWAY).Distinct().ToList(); var Inloca = Expressionable.Create(); Inloca.And(it => it.S_WH_CODE == model.S_WH_CODE); Inloca.And(it => it.S_AREA_CODE == model.S_AREA_CODE); Inloca.And(it => it.C_ENABLE == "Y"); var locationInLock = SqlSugarHelper.Db.Queryable().Where(Inloca.ToExpression()).ToList(); foreach (var item in location_roadray) { LogHelper.Info("入库算法", $"开始巷道:{item}"); var ggf = lstTrueLocation.FindAll(e => e.N_ROADWAY == item).ToList();//空货位数 var ffg = locationInLock.FindAll(e => e.N_ROADWAY == item).ToList();//总货位数 LogHelper.Info("入库算法", $"空货位数:{ggf.Count()}"); LogHelper.Info("入库算法", $"总货位数:{ffg.Count()}"); double Bfb = ((double)ggf.Count() / (double)ffg.Count()) * 100; // var ff = Math.Round(Bfb, 2); LogHelper.Info("入库算法", $"巷道:{item} 空满比例{Bfb}%"); percentage.Add(item, Bfb); } var abc = percentage.OrderByDescending(e => e.Value).ToDictionary(x => x.Key, x => x.Value); var roa = abc.First().Key; lstTrueLocation = lstTrueLocation.FindAll(e => e.N_ROADWAY == roa).ToList(); } return lstTrueLocation; } } }