using SqlSugar;
|
using WIDESEA_Common.CommonEnum;
|
using WIDESEA_Common.LocationEnum;
|
using WIDESEA_Common.TaskEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.BaseRepository;
|
using WIDESEA_Core.BaseServices;
|
using WIDESEA_Core.Utilities;
|
using WIDESEA_DTO.Basic;
|
using WIDESEA_IBasicService;
|
using WIDESEA_Model.Models;
|
|
namespace WIDESEA_BasicService
|
{
|
public partial class LocationInfoService : ServiceBase<Dt_LocationInfo, IRepository<Dt_LocationInfo>>, ILocationInfoService
|
{
|
public IRepository<Dt_LocationInfo> Repository => BaseDal;
|
public IRepository<Dt_Task> _taskRepository { get; }
|
|
public IRepository<Dt_StockInfo> _stockInfoRepository { get; set; }
|
|
public LocationInfoService(IRepository<Dt_LocationInfo> BaseDal, IRepository<Dt_Task> taskRepository, IRepository<Dt_StockInfo> stockInfoRepository) : base(BaseDal)
|
{
|
_taskRepository = taskRepository;
|
_stockInfoRepository = stockInfoRepository;
|
}
|
|
/// <summary>
|
/// 批量启用货位
|
/// </summary>
|
public WebResponseContent LocationEnableStatus(int[] keys)
|
{
|
var locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
|
locationInfos.ForEach(x => x.EnableStatus = EnableStatusEnum.Normal.GetHashCode());
|
Repository.UpdateData(locationInfos);
|
return WebResponseContent.Instance.OK();
|
}
|
|
/// <summary>
|
/// 批量禁用货位
|
/// </summary>
|
public WebResponseContent LocationDisableStatus(int[] keys)
|
{
|
var locationInfos = Repository.QueryData(x => keys.Contains(x.Id));
|
locationInfos.ForEach(x => x.EnableStatus = EnableStatusEnum.Disable.GetHashCode());
|
Repository.UpdateData(locationInfos);
|
return WebResponseContent.Instance.OK();
|
}
|
|
/// <summary>
|
/// 单个启用货位
|
/// </summary>
|
public WebResponseContent LocationEnableStatus(int key) => LocationEnableStatus(new[] { key });
|
|
/// <summary>
|
/// 单个禁用货位
|
/// </summary>
|
public WebResponseContent LocationDisableStatus(int key) => LocationDisableStatus(new[] { key });
|
|
/// <summary>
|
/// 初始化货位
|
/// </summary>
|
public WebResponseContent InitializationLocation(InitializationLocationDTO dto)
|
{
|
try
|
{
|
var (isValid, errorMsg, _) = ModelValidate.ValidateModelData(dto);
|
if (!isValid) return WebResponseContent.Instance.Error(errorMsg);
|
|
var locationInfos = new List<Dt_LocationInfo>();
|
int depth = dto.Depth;
|
|
for (int row = 1; row <= dto.MaxRow; row++)
|
{
|
depth = CalculateDepth(row, dto.MaxRow, dto.Depth, depth);
|
|
for (int col = 1; col <= dto.MaxColumn; col++)
|
{
|
for (int layer = 1; layer <= dto.MaxLayer; layer++)
|
{
|
var location = CreateLocationInfo(dto.Roadway, row, col, layer, depth);
|
locationInfos.Add(location);
|
}
|
}
|
}
|
|
BaseDal.AddData(locationInfos);
|
return WebResponseContent.Instance.OK();
|
}
|
catch (Exception ex)
|
{
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
|
private static int CalculateDepth(int row, int maxRow, int maxDepth, int currentDepth)
|
{
|
int mod = row % maxRow;
|
if (mod == 1) return maxDepth;
|
if (mod == maxDepth + 1) return 1;
|
if (mod > 1 && mod <= maxDepth) return currentDepth - 1;
|
return currentDepth + 1;
|
}
|
|
private static Dt_LocationInfo CreateLocationInfo(string roadwayNo, int row, int col, int layer, int depth)
|
{
|
return new Dt_LocationInfo
|
{
|
WarehouseId = 0,
|
Row = row,
|
Column = col,
|
Layer = layer,
|
Depth = depth,
|
RoadwayNo = roadwayNo,
|
EnableStatus = EnableStatusEnum.Normal.GetHashCode(),
|
LocationStatus = LocationStatusEnum.Free.GetHashCode(),
|
LocationType = LocationTypeEnum.Undefined.GetHashCode(),
|
LocationCode = $"{roadwayNo}-{row:D3}-{col:D3}-{layer:D3}-{depth:D2}",
|
LocationName = $"{roadwayNo}巷道{row:D3}行{col:D3}列{layer:D3}层{depth:D2}深"
|
};
|
}
|
|
|
|
/// <summary>
|
/// 获取空闲货位信息(根据巷道查询)
|
/// </summary>
|
public async Task<Dt_LocationInfo?> GetLocationInfo(string roadwayNo)
|
{
|
var locations = await BaseDal.QueryDataAsync(x =>
|
x.EnableStatus == EnableStatusEnum.Normal.GetHashCode() &&
|
x.RoadwayNo == roadwayNo &&
|
x.LocationStatus == LocationStatusEnum.Free.GetHashCode());
|
|
return locations?
|
.OrderBy(x => x.Layer)
|
.ThenBy(x => x.Depth)
|
.ThenBy(x => x.Column)
|
.ThenBy(x => x.Row)
|
.FirstOrDefault();
|
}
|
|
/// <summary>
|
/// 获取货位信息(根据巷道和货位编码查询)
|
/// </summary>
|
public async Task<Dt_LocationInfo?> GetLocationInfo(string roadwayNo, string locationCode)
|
{
|
return await BaseDal.QueryFirstAsync(x => x.RoadwayNo == roadwayNo && x.LocationCode == locationCode);
|
}
|
|
public async Task<Dt_LocationInfo> GetLocationInfoAsync( string locationCode)
|
{
|
return await BaseDal.QueryFirstAsync(x=>x.LocationCode == locationCode);
|
}
|
|
/// <summary>
|
/// 更新货位信息
|
/// </summary>
|
public async Task<bool> UpdateLocationInfoAsync(Dt_LocationInfo locationInfo)
|
{
|
return await BaseDal.UpdateDataAsync(locationInfo);
|
}
|
|
|
/// <summary>
|
/// 检查并生成移库任务或返回出库任务
|
/// </summary>
|
/// <param name="locationID">任务号</param>
|
/// <returns>任务对象</returns>
|
public async Task<Dt_Task> TransferCheckAsync(int taskNum)
|
{
|
try
|
{
|
// 根据任务号获取任务
|
var outboundTask = await _taskRepository.QueryFirstAsync(x => x.TaskNum == taskNum);
|
if (outboundTask == null)
|
return null;
|
|
var location = await BaseDal.QueryFirstAsync(x => x.LocationCode == outboundTask.SourceAddress);
|
|
// 检查是否需要进行移库
|
if (CheckForInternalTransfer(location))
|
{
|
// 计算对应位置的相对库位 (奇数行的下一行或者偶数行的上一行)
|
var newLocationID = GetRelativeLocationID(location);
|
|
// 获取新的库位的任务
|
var internalTransferTask = await _taskRepository.QueryFirstAsync(x => x.SourceAddress == newLocationID && x.Roadway == outboundTask.Roadway);
|
|
// 如果新的库位没有找到对应的任务
|
if (internalTransferTask == null)
|
{
|
return await HandleNoTaskAtLocation(outboundTask.SourceAddress, newLocationID, outboundTask);
|
}
|
|
// 直接返回一深位出库任务
|
return internalTransferTask;
|
}
|
|
// 返回当前库位的出库任务
|
return outboundTask;
|
}
|
catch (Exception)
|
{
|
return null;
|
}
|
}
|
|
|
#region 移库方法
|
|
/// <summary>
|
/// 计算相对的库位ID
|
/// </summary>
|
/// <param name="locationID">当前库位ID</param>
|
/// <returns>相对的库位ID</returns>
|
private string GetRelativeLocationID(Dt_LocationInfo locationInfo)
|
{
|
int line = locationInfo.Row;
|
|
// 计算相对的货位行值,奇数行的下一行或者偶数行的上一行
|
int relativeLine = line % 2 == 1 ? line + 1 : line - 1;
|
|
// 构建新的库位ID
|
string[] newLocationParts = new string[] { relativeLine.ToString().PadLeft(3, '0'), locationInfo.Column.ToString(), locationInfo.Layer.ToString() };
|
return string.Join("-", newLocationParts);
|
}
|
|
/// <summary>
|
/// 处理没有任务的库位情况
|
/// </summary>
|
/// <param name="originalLocationID">原始库位ID</param>
|
/// <param name="newLocationID">新的库位ID</param>
|
/// <param name="outboundTask">出库任务</param>
|
/// <returns>生成的移库任务或原始出库任务</returns>
|
private async Task<Dt_Task> HandleNoTaskAtLocation(string originalLocationID, string newLocationID, Dt_Task outboundTask)
|
{
|
// 判断该位置是否有库存
|
var stockInfo = await _stockInfoRepository.QueryFirstAsync(x => x.LocationCode == newLocationID);
|
|
if (stockInfo == null)
|
{
|
// 如果没有库存,直接返回当前出库任务
|
return outboundTask;
|
}
|
else
|
{
|
// 如果有库存,生成移库任务
|
var emptyLocation = await GetTransferLocationEmptyAsync(outboundTask.Roadway);
|
var taskNo = await _taskRepository.GetTaskNo();
|
Dt_Task newTransferTask = new Dt_Task()
|
{
|
CreateDate = DateTime.Now,
|
Creater = App.User.UserName,
|
CurrentAddress = originalLocationID,
|
Grade = 99,
|
NextAddress = emptyLocation.LocationCode,
|
PalletCode = stockInfo.PalletCode,
|
Remark = "移库",
|
Roadway = stockInfo.LocationDetails.RoadwayNo,
|
SourceAddress = originalLocationID,
|
TaskNum = taskNo,
|
TargetAddress = emptyLocation.LocationCode,
|
TaskType = TaskTypeEnum.Relocation.GetHashCode(),
|
};
|
|
return await _taskRepository.Db.Insertable(newTransferTask).ExecuteReturnEntityAsync();
|
}
|
}
|
|
/// <summary>
|
/// 根据货位是否需要移库
|
/// </summary>
|
/// <param name="locationID">货位ID</param>
|
/// <returns>是否需要移库</returns>
|
private bool CheckForInternalTransfer(Dt_LocationInfo location)
|
{
|
return location.Depth == 2 ? true : false;
|
}
|
|
/// <summary>
|
/// 根据巷道获取二深位的空库位
|
/// </summary>
|
/// <param name="roadway">巷道</param>
|
/// <returns>货位对象</returns>
|
private async Task<Dt_LocationInfo> GetTransferLocationEmptyAsync(string roadway)
|
{
|
return await BaseDal.QueryFirstAsync(x => x.Depth == 2 && x.LocationStatus == (LocationStatusEnum.Free.GetHashCode()) && x.RoadwayNo == roadway);
|
|
//Db.Queryable<Dt_LocationInfo>()
|
//.Where(x => x.Status == LocationEnum.Free.ObjToInt())
|
//.Where(x => x.Depth == 2.ToString())
|
//.Where(x => x.Roadway == roadway)
|
//.First();
|
}
|
|
#endregion 移库方法
|
|
}
|
}
|