using HslCommunication.WebSocket;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
using SqlSugar;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WIDESEA_Common.CommonEnum;
|
using WIDESEA_Common.LocationEnum;
|
using WIDESEA_Common.StockEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.BaseRepository;
|
using WIDESEA_Core.BaseServices;
|
using WIDESEA_Core.Const;
|
using WIDESEA_Core.DB;
|
using WIDESEA_Core.Enums;
|
using WIDESEA_Core.Helper;
|
using WIDESEA_Core.Seed;
|
using WIDESEA_Core.Utilities;
|
using WIDESEA_DTO.Basic;
|
using WIDESEA_IBasicService;
|
using WIDESEA_Model.Models;
|
|
namespace WIDESEA_BasicService
|
{
|
public class LocationCache
|
{
|
public string LocationCode { get; set; }
|
|
public DateTime DateTime { get; set; }
|
}
|
public partial class LocationInfoService : ServiceBase<Dt_LocationInfo, IRepository<Dt_LocationInfo>>, ILocationInfoService
|
{
|
private readonly IUnitOfWorkManage _unitOfWorkManage;
|
private readonly IRepository<Dt_StockInfo> _stockInfoRepository;
|
public IRepository<Dt_LocationInfo> Repository => BaseDal;
|
public readonly IRepository<Dt_LocationType> _locationTypeRepository;
|
|
public LocationInfoService(IRepository<Dt_LocationInfo> BaseDal, IUnitOfWorkManage unitOfWorkManage, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_LocationType> locationTypeRepository) : base(BaseDal)
|
{
|
_unitOfWorkManage = unitOfWorkManage;
|
_stockInfoRepository = stockInfoRepository;
|
_locationTypeRepository = locationTypeRepository;
|
}
|
|
/// <summary>
|
/// 批量启用货位
|
/// </summary>
|
/// <param name="keys">货位主键数组</param>
|
/// <returns></returns>
|
public WebResponseContent LocationEnableStatus(int[] keys)
|
{
|
List<Dt_LocationInfo> locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
|
locationInfos.ForEach(x =>
|
{
|
x.EnableStatus = EnableStatusEnum.Normal.ObjToInt();
|
});
|
Repository.UpdateData(locationInfos);
|
|
return WebResponseContent.Instance.OK();
|
}
|
|
/// <summary>
|
/// 批量禁用货位
|
/// </summary>
|
/// <param name="keys">货位主键数组</param>
|
/// <returns></returns>
|
public WebResponseContent LocationDisableStatus(int[] keys)
|
{
|
List<Dt_LocationInfo> locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
|
locationInfos.ForEach(x =>
|
{
|
x.EnableStatus = EnableStatusEnum.Disable.ObjToInt();
|
});
|
Repository.UpdateData(locationInfos);
|
|
return WebResponseContent.Instance.OK();
|
}
|
|
/// <summary>
|
/// 单个启用货位
|
/// </summary>
|
/// <param name="key">货位主键</param>
|
/// <returns></returns>
|
public WebResponseContent LocationEnableStatus(int key)
|
{
|
return LocationEnableStatus(new int[] { key });
|
}
|
|
/// <summary>
|
/// 单个禁用货位
|
/// </summary>
|
/// <param name="key">货位主键</param>
|
/// <returns></returns>
|
public WebResponseContent LocationDisableStatus(int key)
|
{
|
return LocationDisableStatus(new int[] { key });
|
}
|
|
/// <summary>
|
/// 批量修改货位状态
|
/// </summary>
|
/// <param name="locationInfos"></param>
|
/// <param name="locationStatus"></param>
|
public void UpdateLocationStatus(List<Dt_LocationInfo> locationInfos, LocationStatusEnum locationStatus)
|
{
|
locationInfos.ForEach(x =>
|
{
|
x.LocationStatus = locationStatus.ObjToInt();
|
});
|
UpdateData(locationInfos);
|
}
|
|
|
private readonly static object _locker = new object();
|
static List<LocationCache> locationCaches = new List<LocationCache>();
|
private int locationCacheTime = 10;
|
/// <summary>
|
///
|
/// </summary>
|
/// <param name="roadwayNo"></param>
|
/// <returns></returns>
|
public Dt_LocationInfo? AssignLocation(int locationType)
|
{
|
if (locationType <= 0)
|
{
|
throw new ArgumentOutOfRangeException("仓库区域错误!");
|
}
|
lock (_locker)
|
{
|
|
List<LocationCache> removeItems = locationCaches.Where(x => (DateTime.Now - x.DateTime).TotalMinutes > locationCacheTime).ToList();
|
int count = removeItems.Count;
|
for (int i = 0; i < count; i++)
|
{
|
locationCaches.Remove(removeItems[i]);
|
}
|
|
List<string> lockLocationCodes = locationCaches.Select(x => x.LocationCode).ToList();
|
|
Dictionary<string, OrderByType> orderBy = new Dictionary<string, OrderByType>()
|
{
|
{ nameof(Dt_LocationInfo.RoadwayNo),OrderByType.Asc },
|
{ nameof(Dt_LocationInfo.Layer),OrderByType.Asc },
|
{ nameof(Dt_LocationInfo.Column),OrderByType.Asc },
|
{ nameof(Dt_LocationInfo.Depth),OrderByType.Desc },
|
{ nameof(Dt_LocationInfo.Row),OrderByType.Asc }
|
};
|
|
var first = BaseDal.QueryFirst(x => x.LocationType == locationType && x.LocationStatus == LocationStatusEnum.Free.ObjToInt() && x.EnableStatus != EnableStatusEnum.Disable.ObjToInt() && !lockLocationCodes.Contains(x.LocationCode), orderBy);//查询空货位信息并排除5分钟内分配的货位,根据层、列、深度、行排序
|
if (first != null)
|
{
|
locationCaches.Add(new LocationCache { LocationCode = first?.LocationCode, DateTime = DateTime.Now });
|
}
|
|
return first;
|
}
|
}
|
public Dt_LocationInfo? AssignLocation()
|
{
|
lock (_locker)
|
{
|
|
List<LocationCache> removeItems = locationCaches.Where(x => (DateTime.Now - x.DateTime).TotalMinutes > locationCacheTime).ToList();
|
int count = removeItems.Count;
|
for (int i = 0; i < count; i++)
|
{
|
locationCaches.Remove(removeItems[i]);
|
}
|
|
List<string> lockLocationCodes = locationCaches.Select(x => x.LocationCode).ToList();
|
|
Dictionary<string, OrderByType> orderBy = new Dictionary<string, OrderByType>()
|
{
|
{ nameof(Dt_LocationInfo.RoadwayNo),OrderByType.Asc },
|
{ nameof(Dt_LocationInfo.Layer),OrderByType.Asc },
|
{ nameof(Dt_LocationInfo.Column),OrderByType.Asc },
|
{ nameof(Dt_LocationInfo.Depth),OrderByType.Desc },
|
{ nameof(Dt_LocationInfo.Row),OrderByType.Asc }
|
};
|
|
var first = BaseDal.QueryFirst(x => x.LocationStatus == LocationStatusEnum.Free.ObjToInt() && x.EnableStatus != EnableStatusEnum.Disable.ObjToInt() && !lockLocationCodes.Contains(x.LocationCode), orderBy);//查询空货位信息并排除5分钟内分配的货位,根据层、列、深度、行排序
|
|
locationCaches.Add(new LocationCache { LocationCode = first.LocationCode, DateTime = DateTime.Now });
|
|
return first;
|
}
|
}
|
/// <summary>
|
/// 获取可出库货位编号
|
/// </summary>
|
/// <param name="warehouseId"></param>
|
/// <returns></returns>
|
public List<string> GetCanOutLocationCodes()
|
{
|
return Repository.QueryData(x => x.LocationCode, x => x.LocationStatus == LocationStatusEnum.InStock.ObjToInt() && (x.EnableStatus == EnableStatusEnum.OnlyOut.ObjToInt() || x.EnableStatus == EnableStatusEnum.Normal.ObjToInt())).Distinct().ToList();
|
}
|
|
/// <summary>
|
/// 根据货位编号集合获取货位信息
|
/// </summary>
|
/// <param name="locationCodes"></param>
|
/// <returns></returns>
|
public List<Dt_LocationInfo> GetLocationInfos(List<string> locationCodes)
|
{
|
return Repository.QueryData(x => locationCodes.Contains(x.LocationCode));
|
}
|
|
public List<LocationTypeDto> GetLocationTypes()
|
{
|
return _locationTypeRepository.Db.Queryable<Dt_LocationType>().Select(x =>
|
new LocationTypeDto { LocationType = x.LocationType, LocationTypeDesc = x.LocationTypeDesc }).ToList();
|
}
|
|
/// <summary>
|
/// 初始化货位
|
/// </summary>
|
/// <param name="initializationLocationDTO"></param>
|
/// <returns></returns>
|
public WebResponseContent InitializationLocation(InitializationLocationDTO initializationLocationDTO)
|
{
|
try
|
{
|
(bool, string, object?) result = ModelValidate.ValidateModelData(initializationLocationDTO);
|
if (!result.Item1) return WebResponseContent.Instance.Error(result.Item2);
|
if (BaseDal.QueryData().ToList().Any())
|
{
|
return WebResponseContent.Instance.OK();
|
}
|
|
var lanes = BuildLanes(31, 25);
|
var list = new List<Dt_LocationInfo>();
|
int id = 1;
|
|
foreach (var lane in lanes)
|
{
|
string roadwayNo = $"{lane.LaneIndex}";
|
|
if (lane.Rows.Length == 1)
|
{
|
int row = lane.Rows[0];
|
for (int col = 1; col <= 31; col++)
|
for (int layer = 1; layer <= 13; layer++)
|
{
|
list.Add(new Dt_LocationInfo
|
{
|
WarehouseId = 0,
|
LocationCode = $"HAI-{row.ToString().PadLeft(3, '0')}-{col.ToString().PadLeft(3, '0')}-{layer.ToString().PadLeft(2, '0')} ",
|
LocationName = $"{row.ToString()}行{col.ToString()}列{layer.ToString()}层 ",
|
|
|
RoadwayNo = roadwayNo,
|
Row = row,
|
Column = col,
|
Layer = layer,
|
Depth = 1,
|
LocationType = 1,
|
LocationStatus = 0,
|
EnableStatus = 1,
|
Creater = "System",
|
CreateDate = DateTime.Now
|
});
|
}
|
}
|
else
|
{
|
int r1 = lane.Rows[0];
|
int r2 = lane.Rows[1];
|
for (int col = 1; col <= 31; col++)
|
for (int layer = 1; layer <= 13; layer++)
|
{
|
list.Add(new Dt_LocationInfo
|
{
|
WarehouseId = 0,
|
LocationCode = $"HAI-{r1.ToString().PadLeft(3, '0')}-{col.ToString().PadLeft(3, '0')}-{layer.ToString().PadLeft(2, '0')} ",
|
LocationName = $"{r1.ToString()}行{col.ToString()}列{layer.ToString()}层 ",
|
|
|
RoadwayNo = roadwayNo,
|
Row = r1,
|
Column = col,
|
Layer = layer,
|
Depth = 1,
|
LocationType = 1,
|
LocationStatus = 0,
|
EnableStatus = 1,
|
Creater = "System",
|
CreateDate = DateTime.Now
|
});
|
list.Add(new Dt_LocationInfo
|
{
|
WarehouseId = 0,
|
LocationCode = $"HAI-{r2.ToString().PadLeft(3, '0')}-{col.ToString().PadLeft(3, '0')}-{layer.ToString().PadLeft(2, '0')} ",
|
LocationName = $"{r2.ToString()}行{col.ToString()}列{layer.ToString()}层 ",
|
|
|
|
RoadwayNo = roadwayNo,
|
Row = r2,
|
Column = col,
|
Layer = layer,
|
Depth = 1,
|
LocationType = 1,
|
LocationStatus = 0,
|
EnableStatus = 1,
|
Creater = "System",
|
CreateDate = DateTime.Now
|
});
|
}
|
}
|
}
|
BaseDal.AddData(list);
|
|
|
|
|
var has4cols = new List<int> { 7, 8, 9, 14, 15, 16, 17, 18, 19, 23, 24, 25, 26, 27 };
|
var hsd21cols = 16;
|
|
int depth = initializationLocationDTO.Depth;
|
List<Dt_LocationInfo> locationInfos = new List<Dt_LocationInfo>();
|
for (int i = 0; i < initializationLocationDTO.MaxRow; i++)
|
{
|
if ((i + 1) % initializationLocationDTO.MaxRow == 1)
|
{
|
depth = initializationLocationDTO.Depth;
|
}
|
else if ((i + 1) % initializationLocationDTO.MaxRow == initializationLocationDTO.Depth + 1)
|
{
|
depth = 1;
|
}
|
else if ((i + 1) % initializationLocationDTO.MaxRow > 1 && (i + 1) % initializationLocationDTO.MaxRow <= initializationLocationDTO.Depth)
|
{
|
depth -= 1;
|
}
|
else
|
{
|
depth += 1;
|
}
|
for (int j = 0; j < initializationLocationDTO.MaxColumn; j++)
|
{
|
for (int k = 0; k < initializationLocationDTO.MaxLayer; k++)
|
{
|
|
|
Dt_LocationInfo locationInfo = new Dt_LocationInfo()
|
{
|
WarehouseId = 0,
|
Column = j + 1,
|
EnableStatus = EnableStatusEnum.Normal.ObjToInt(),
|
Layer = k + 1,
|
LocationStatus = LocationStatusEnum.Free.ObjToInt(),
|
LocationType = LocationTypeEnum.Normal.ObjToInt(),
|
RoadwayNo = $"{initializationLocationDTO.Roadway.ToString()}",
|
Row = i + 1,
|
Depth = depth,
|
};
|
|
locationInfo.LocationCode = $"HAI-{locationInfo.Row.ToString().PadLeft(3, '0')}-{locationInfo.Column.ToString().PadLeft(3, '0')}-{locationInfo.Layer.ToString().PadLeft(2, '0')}";
|
locationInfo.LocationName = $"HAI{locationInfo.RoadwayNo}巷道{locationInfo.Row.ToString().PadLeft(3, '0')}行{locationInfo.Column.ToString().PadLeft(3, '0')}列{locationInfo.Layer.ToString().PadLeft(3, '0')}层";
|
|
|
//locationInfo.LocationCode = $"{locationInfo.RoadwayNo}-{locationInfo.Row.ToString().PadLeft(3, '0')}-{locationInfo.Column.ToString().PadLeft(3, '0')}-{locationInfo.Layer.ToString().PadLeft(3, '0')}-{locationInfo.Depth.ToString().PadLeft(2, '0')}";
|
// locationInfo.LocationName = $"{locationInfo.RoadwayNo}巷道{locationInfo.Row.ToString().PadLeft(3, '0')}行{locationInfo.Column.ToString().PadLeft(3, '0')}列{locationInfo.Layer.ToString().PadLeft(3, '0')}层{locationInfo.Depth.ToString().PadLeft(2, '0')}深";
|
locationInfos.Add(locationInfo);
|
|
}
|
}
|
}
|
// BaseDal.AddData(locationInfos);
|
return WebResponseContent.Instance.OK();
|
}
|
catch (Exception ex)
|
{
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
|
|
|
private record Lane(int LaneIndex, int[] Rows);
|
|
private static List<Lane> BuildLanes(int rows, int singleRow)
|
{
|
var lanes = new List<Lane>();
|
int laneIdx = 1;
|
int r = 1;
|
while (r <= rows)
|
{
|
if (r == singleRow)
|
{
|
lanes.Add(new Lane(laneIdx++, new[] { r }));
|
r++;
|
}
|
else if (r + 1 <= rows)
|
{
|
if (r + 1 == singleRow)
|
{
|
lanes.Add(new Lane(laneIdx++, new[] { r }));
|
r++;
|
}
|
else
|
{
|
lanes.Add(new Lane(laneIdx++, new[] { r, r + 1 }));
|
r += 2;
|
}
|
}
|
else
|
{
|
lanes.Add(new Lane(laneIdx++, new[] { r }));
|
r++;
|
}
|
}
|
return lanes;
|
}
|
}
|
}
|