You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
10 KiB
C#

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
|* (c) 2026 WenJY
|* CLR4.0.30319.42000
|* Mr.Wen's MacBook Pro
|* Sln.Wcs.Business
|* 7E8A9B2C-3D4F-5E6A-7B8C-9D0E1F2A3B4C
|*
|* WenJY
|*
|* 2026-05-15 15:30:00
|* V1.0.0
|* ///
|*
|*--------------------------------------------------------------------
|*
|*
|*
|*
|* V1.0.0
|*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using System.Linq.Expressions;
using Sln.Wcs.Business.Domain.Dto.CreateTask;
using Sln.Wcs.Business.Domain.Dto.FilterLocation;
using Sln.Wcs.Business.Domain.Dto.SaveTask;
using Sln.Wcs.Business.Domain.Dto.ValidateMaterial;
using Sln.Wcs.Business.Domain.Enum;
using Sln.Wcs.Business.Domain.Model.CreateTask;
using Sln.Wcs.Business.Domain.Model.FilterLocation;
using Sln.Wcs.Business.Domain.Model.SaveTask;
using Sln.Wcs.Business.Util;
using Sln.Wcs.Model.Domain;
using Sln.Wcs.Repository.service;
namespace Sln.Wcs.Business;
/// <summary>
/// 通用仓储任务业务处理类
/// 支持扩展点:子类可重写虚方法实现特定业务逻辑
/// </summary>
public class StoreTaskBusiness : EntityWrapper
{
private readonly IBasePathInfoService _basePathInfoService;
private readonly ILiveTaskQueueService _liveTaskQueueService;
private readonly IBaseStoreInfoService _baseStoreInfoService;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="basePathInfoService">路径服务</param>
/// <param name="liveTaskQueueService">任务队列服务</param>
/// <param name="baseStoreInfoService">仓库服务</param>
public StoreTaskBusiness(
IBasePathInfoService basePathInfoService,
ILiveTaskQueueService liveTaskQueueService,
IBaseStoreInfoService baseStoreInfoService)
{
_basePathInfoService = basePathInfoService;
_liveTaskQueueService = liveTaskQueueService;
_baseStoreInfoService = baseStoreInfoService;
}
#region 虚方法 - 供子类重写的扩展点
/// <summary>
/// 校验物料(可被子类重写)
/// </summary>
public virtual ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto)
{
throw new NotImplementedException();
}
/// <summary>
/// 创建任务(可被子类重写)
/// </summary>
/// <param name="createTaskDto">创建任务参数包含taskType和taskCategory</param>
public virtual CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto)
{
CreateTaskResultDto resultDto = new CreateTaskResultDto();
try
{
ValidateCreateTaskParams(createTaskDto);
BasePathInfo pathInfo = GetPathInfo(createTaskDto);
string taskCode = GenerateTaskCode();
List<LiveTaskDetail> taskDetails = pathInfo.pathDetails
.Select(item => LiveTaskDetailWrapper(taskCode, createTaskDto, item))
.ToList();
var taskQueue = LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo);
taskQueue.taskSteps = taskDetails.Count;
taskQueue.taskDetails = taskDetails;
resultDto.code = Domain.Enum.BusinessStatusEnum.;
resultDto.msg = $"{GetCategoryName(createTaskDto.taskCategory)}{GetTaskTypeName(createTaskDto.taskType)}任务创建成功:{taskCode};关联路径:{pathInfo.pathName}";
resultDto.data = new CreateTaskResultModel()
{
taskCode = taskCode,
taskQueue = taskQueue,
taskDetails = taskDetails,
};
}
catch (Exception e)
{
resultDto.code = Domain.Enum.BusinessStatusEnum.;
resultDto.msg = e.Message;
}
return resultDto;
}
/// <summary>
/// 筛选库位(可被子类重写)
/// </summary>
/// <param name="filterLocationDto">筛选库位参数包含taskType和taskCategory</param>
public virtual FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto)
{
FilterLocationResultDto resultDto = new FilterLocationResultDto();
try
{
ValidateFilterLocationParams(filterLocationDto);
int locationStatus = filterLocationDto.taskType == TaskTypeEnum.InStore ? 0 : 1;
Expression<Func<BaseStoreInfo, bool>> storeWhere = GetStoreWhere(filterLocationDto.taskType, filterLocationDto.taskCategory);
Expression<Func<BaseLocationInfo, bool>> locationWhere = GetLocationWhere(filterLocationDto, locationStatus);
List<BaseStoreInfo> storeInfos = _baseStoreInfoService.GetBasePathInfo(storeWhere, locationWhere);
BaseStoreInfo? storeInfo = storeInfos
.Where(s => s.locationInfos.Count > 0)
.OrderBy(x => x.storeCode)
.FirstOrDefault() ?? throw new ArgumentNullException($"未获取到可用仓库");
BaseLocationInfo? locationInfo = storeInfo.locationInfos
.OrderBy(x => x.locationRows)
.ThenBy(x => x.locationColumns)
.ThenBy(x => x.locationLayers)
.FirstOrDefault() ?? throw new ArgumentNullException($"目标仓库:{storeInfo.storeName}中未获取到可用库位");
resultDto.code = Domain.Enum.BusinessStatusEnum.;
resultDto.msg = "执行完成";
resultDto.data = new FilterLocationResultModel()
{
storeInfo = storeInfo,
locationInfos = storeInfo.locationInfos,
locationInfo = locationInfo,
};
}
catch (Exception e)
{
resultDto.code = Domain.Enum.BusinessStatusEnum.;
resultDto.msg = e.Message;
}
return resultDto;
}
/// <summary>
/// 保存任务(可被子类重写)
/// </summary>
/// <param name="saveTaskDto">保存任务参数</param>
public virtual SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto)
{
SaveTaskResultDto resultDto = new SaveTaskResultDto();
try
{
var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue);
resultDto.code = Domain.Enum.BusinessStatusEnum.;
resultDto.msg = "执行完成";
resultDto.data = new SaveTaskResultModel()
{
isRes = inRes
};
}
catch (Exception e)
{
resultDto.code = Domain.Enum.BusinessStatusEnum.;
resultDto.msg = e.Message;
}
return resultDto;
}
#endregion
#region 受保护虚方法 - 可被子类定制
/// <summary>
/// 校验创建任务参数(可被子类重写添加额外校验)
/// </summary>
protected virtual void ValidateCreateTaskParams(CreateTaskDto createTaskDto)
{
if (string.IsNullOrEmpty(createTaskDto.materialCode))
{
throw new InvalidOperationException($"物料编号不允许为 NULL");
}
if (string.IsNullOrEmpty(createTaskDto.palletBarcode))
{
throw new InvalidOperationException($"{GetCategoryName(createTaskDto.taskCategory)}条码不允许为 NULL");
}
if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint))
{
throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL");
}
}
/// <summary>
/// 校验筛选库位参数(可被子类重写添加额外校验)
/// </summary>
protected virtual void ValidateFilterLocationParams(FilterLocationDto filterLocationDto)
{
if (string.IsNullOrEmpty(filterLocationDto.materialCode))
{
throw new InvalidOperationException($"物料编号不允许为 NULL");
}
}
/// <summary>
/// 获取路径信息(可被子类重写定制路径查询逻辑)
/// </summary>
protected virtual BasePathInfo GetPathInfo(CreateTaskDto createTaskDto)
{
Expression<Func<BasePathInfo, bool>> exp = x =>
x.startPoint == createTaskDto.startPoint &&
x.endPoint == createTaskDto.endPoint &&
x.pathType == (int)createTaskDto.taskType &&
x.pathCategory == (int)createTaskDto.taskCategory;
return _basePathInfoService.GetBasePathInfo(exp)
.FirstOrDefault() ?? throw new InvalidOperationException($"{GetCategoryName(createTaskDto.taskCategory)}{GetTaskTypeName(createTaskDto.taskType)}输送路径为 NULL");
}
/// <summary>
/// 生成任务编号(可被子类重写定制生成规则)
/// </summary>
protected virtual string GenerateTaskCode()
{
return DateTime.Now.ToString("yyyyMMddHHmmss") + new Random().Next(10, 99);
}
/// <summary>
/// 获取仓库查询条件(可被子类重写)
/// </summary>
protected virtual Expression<Func<BaseStoreInfo, bool>> GetStoreWhere(TaskTypeEnum taskType, TaskCategoryEnum taskCategory)
{
return x => x.storeType == (int)taskCategory && x.isFlag == 1;
}
/// <summary>
/// 获取库位查询条件(可被子类重写)
/// </summary>
protected virtual Expression<Func<BaseLocationInfo, bool>> GetLocationWhere(FilterLocationDto filterLocationDto, int locationStatus)
{
return x => x.materialCode == filterLocationDto.materialCode &&
x.locationStatus == locationStatus &&
x.isFlag == 1;
}
#endregion
/// <summary>
/// 获取分类名称
/// </summary>
private string GetCategoryName(TaskCategoryEnum taskCategory)
{
return taskCategory switch
{
TaskCategoryEnum.Material => "包材",
TaskCategoryEnum.Product => "成品",
TaskCategoryEnum.Pallet => "托盘",
_ => "未知"
};
}
/// <summary>
/// 获取任务类型名称
/// </summary>
private string GetTaskTypeName(TaskTypeEnum taskType)
{
return taskType switch
{
TaskTypeEnum.InStore => "入库",
TaskTypeEnum.OutStore => "出库",
_ => "未知"
};
}
}