From ffa7e93dbec11ad42f29f33483c78b2e390fb2cd Mon Sep 17 00:00:00 2001 From: WenJY Date: Mon, 18 May 2026 11:14:44 +0800 Subject: [PATCH 1/3] =?UTF-8?q?change=20-=20=E8=B0=83=E5=BA=A6=E7=AD=96?= =?UTF-8?q?=E7=95=A5=E9=80=BB=E8=BE=91=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 7 + Sln.Wcs.Strategy/ITaskExecuteStrategy.cs | 8 +- Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj | 4 +- Sln.Wcs.Strategy/TaskExecuteStrategy.cs | 258 +++++++++++++---------- 4 files changed, 159 insertions(+), 118 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..61a5292 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(dotnet build *)" + ] + } +} diff --git a/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs b/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs index 2a0e0bb..3ffb4f3 100644 --- a/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs +++ b/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs @@ -1,13 +1,13 @@ namespace Sln.Wcs.Strategy; /// -/// 任务执行策略接口 - 从任务队列中取出待执行任务,根据设备类型下发到对应 SDK +/// 任务执行调度策略 - 按任务类别(包材/托盘/成品)并行调度, +/// AGV 阶段并发下发(多车),提升机阶段按设备串行下发 /// public interface ITaskExecuteStrategy { /// - /// 执行一轮任务调度:查询待执行任务,按设备类型下发 + /// 启动任务调度,持续运行直到 cancellationToken 被取消 /// - /// 本次下发的任务数量 - Task ExecuteAsync(); + Task ExecuteAsync(CancellationToken cancellationToken = default); } diff --git a/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj b/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj index 428753c..8370e97 100644 --- a/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj +++ b/Sln.Wcs.Strategy/Sln.Wcs.Strategy.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/Sln.Wcs.Strategy/TaskExecuteStrategy.cs b/Sln.Wcs.Strategy/TaskExecuteStrategy.cs index 61f559f..6abba79 100644 --- a/Sln.Wcs.Strategy/TaskExecuteStrategy.cs +++ b/Sln.Wcs.Strategy/TaskExecuteStrategy.cs @@ -1,169 +1,203 @@ -using Sln.Wcs.HikRoBotSdk; -using Sln.Wcs.HikRoBotSdk.Dto.GenAgvSchedulingTask; -using Sln.Wcs.HoistSdk; -using Sln.Wcs.HoistSdk.Dto.HoistTaskExecutor; +using System.Collections.Concurrent; +using Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask; +using Sln.Wcs.HikRoBotApi.Enum; +using Sln.Wcs.HikRoBotApi.Service; +using Sln.Wcs.HoistApi.Domain.Dto.HoistTaskExecutor; +using Sln.Wcs.HoistApi.Domain.Enum; +using Sln.Wcs.HoistApi.Service; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository.service; namespace Sln.Wcs.Strategy; -/// -/// 任务执行策略 - 轮询数据库中待执行的任务,根据设备类型调用对应 SDK 下发 -/// public class TaskExecuteStrategy : ITaskExecuteStrategy { private readonly ILiveTaskQueueService _taskQueueService; private readonly ILiveTaskDetailService _taskDetailService; - private readonly IHIKRoBotSdk _hikRobotSdk; - private readonly IHoistSdk _hoistSdk; + private readonly IHikRoBotService _hikRobotService; + private readonly IHoistApiService _hoistService; + + // AGV 多车并发,默认最大 10 个并发 + private readonly SemaphoreSlim _agvSemaphore = new(10, 10); + + // 提升机按设备串行,每台提升机一次只能执行一个任务 + private readonly ConcurrentDictionary _hoistSemaphores = new(); public TaskExecuteStrategy( ILiveTaskQueueService taskQueueService, ILiveTaskDetailService taskDetailService, - IHIKRoBotSdk hikRobotSdk, - IHoistSdk hoistSdk) + IHikRoBotService hikRobotService, + IHoistApiService hoistService) { _taskQueueService = taskQueueService; _taskDetailService = taskDetailService; - _hikRobotSdk = hikRobotSdk; - _hoistSdk = hoistSdk; + _hikRobotService = hikRobotService; + _hoistService = hoistService; + } + + public Task ExecuteAsync(CancellationToken cancellationToken = default) + { + return Task.WhenAll( + ProcessCategory(1, cancellationToken), // 包材 + ProcessCategory(2, cancellationToken), // 成品 + ProcessCategory(3, cancellationToken) // 托盘 + ); } /// - /// 执行一轮任务调度:查询所有待执行任务,按设备类型下发 + /// 按任务类别轮询待执行任务,同一类别内多个任务并行处理 /// - public Task ExecuteAsync() + private async Task ProcessCategory(int taskCategory, CancellationToken ct) { - return Task.Run(() => + while (!ct.IsCancellationRequested) { - // 1. 查询所有待执行的任务队列(task_status = 1) - var pendingTasks = _taskQueueService.Query(x => x.taskStatus == 1); - - if (pendingTasks.Count == 0) - return 0; - - int dispatchedCount = 0; - - foreach (var task in pendingTasks) + try { - try + var pendingTasks = _taskQueueService.Query(x => + x.taskStatus == 1 && x.taskCategory == taskCategory); + + if (pendingTasks.Count > 0) { - // 2. 查询任务明细 - var details = _taskDetailService.Query(x => x.taskCode == task.taskCode); - - if (details.Count == 0) - continue; - - // 3. 取第一个未执行的明细步骤 - var currentDetail = details - .Where(x => x.taskStatus == 1) - .OrderBy(x => x.objId) - .FirstOrDefault(); - - if (currentDetail == null) - continue; - - // 4. 根据设备类型下发任务 - var success = DispatchByDeviceType(currentDetail); - - if (success) + await Parallel.ForEachAsync(pendingTasks, ct, async (task, innerCt) => { - // 5. 更新明细状态为执行中 - currentDetail.taskStatus = 2; - _taskDetailService.Update(currentDetail); - - // 6. 更新队列状态为执行中 - task.taskStatus = 2; - _taskQueueService.Update(task); - - dispatchedCount++; - } - } - catch (Exception ex) - { - Console.WriteLine($"任务 {task.taskCode} 下发失败: {ex.Message}"); + await ProcessTask(task, innerCt); + }); } } + catch (Exception ex) + { + Console.WriteLine($"任务类别 {taskCategory} 调度异常: {ex.Message}"); + } - return dispatchedCount; - }); + await Task.Delay(1000, ct); + } } /// - /// 根据设备类型分发到对应 SDK + /// 处理单个任务:按顺序遍历明细步骤,依次下发到对应设备 /// - private bool DispatchByDeviceType(LiveTaskDetail detail) + private async Task ProcessTask(LiveTaskQueue task, CancellationToken ct) + { + try + { + var details = _taskDetailService.Query(x => + x.taskCode == task.taskCode && x.taskStatus == 1) + .OrderBy(x => x.objId) + .ToList(); + + foreach (var detail in details) + { + if (ct.IsCancellationRequested) return; + + var success = await DispatchDetail(detail); + if (!success) break; + } + + // 检查是否还有待执行的明细,若无则更新队列状态为执行中 + var remainingPending = _taskDetailService.Query(x => + x.taskCode == task.taskCode && x.taskStatus == 1); + + if (remainingPending.Count == 0) + { + task.taskStatus = 2; + _taskQueueService.Update(task); + } + } + catch (Exception ex) + { + Console.WriteLine($"任务 {task.taskCode} 处理异常: {ex.Message}"); + } + } + + /// + /// 根据设备类型分发明细到对应设备 API + /// + private Task DispatchDetail(LiveTaskDetail detail) { return detail.deviceType switch { 1 => DispatchToAgv(detail), 2 => DispatchToHoist(detail), - _ => throw new NotSupportedException($"不支持的设备类型: {detail.deviceType}") + _ => Task.FromResult(false) // ConveyorLine 暂不处理 }; } /// - /// 下发 AGV 任务(海康机器人 SDK) + /// 下发 AGV 任务,通过 HikRoBotApi(AGV 多车可并发) /// - private bool DispatchToAgv(LiveTaskDetail detail) + private async Task DispatchToAgv(LiveTaskDetail detail) { - var dto = new GenAgvSchedulingTaskDto + await _agvSemaphore.WaitAsync(); + try { - reqCode = detail.taskCode, - reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - clientCode = "WCS", - taskCode = detail.taskCode, - taskTyp = detail.taskType switch + var dto = new GenAgvSchedulingTaskDto { - 1 => "1", // 入库 - 2 => "2", // 出库 - _ => "0" - }, - taskMode = detail.taskType switch + reqCode = detail.taskCode, + reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), + clientCode = "WCS", + taskCode = detail.taskCode, + taskTyp = detail.taskType switch { 1 => "1", 2 => "2", _ => "0" }, + taskMode = detail.taskType switch { 1 => "2", 2 => "1", _ => "0" }, + wbCode = detail.startPoint, + ctnrCode = detail.palletBarcode, + materialLot = detail.materialBarcode, + positionCodePath = new List + { + new() { positionCode = detail.startPoint, type = "00" }, + new() { positionCode = detail.endPoint, type = "00" } + } + }; + + var result = _hikRobotService.GetGenAgvSchedulingTask(dto); + if (result.code.Equals(HikRoBotStatusEnum.成功)) { - 1 => "2", // 入库 move - 2 => "1", // 出库 move - _ => "0" - }, - wbCode = detail.startPoint, - ctnrCode = detail.palletBarcode, - materialLot = detail.materialBarcode, - positionCodePath = new List - { - new() { positionCode = detail.startPoint, type = "00" }, - new() { positionCode = detail.endPoint, type = "00" } + detail.taskStatus = 2; + _taskDetailService.Update(detail); + return true; } - }; - var result = _hikRobotSdk.GenAgvSchedulingTask(dto); - return result.code == "0"; - } - - /// - /// 下发提升机任务(Hoist SDK) - /// - private bool DispatchToHoist(LiveTaskDetail detail) - { - var dto = new HoistTaskExeDto + Console.WriteLine($"AGV 任务 {detail.taskCode} 下发失败: [{result.code}] {result.msg}"); + return false; + } + finally { - hoistCode = detail.startPoint, - taskCode = detail.taskCode, - startPoint = ParseIntPoint(detail.startPoint), - endPoint = ParseIntPoint(detail.endPoint) - }; - - var result = _hoistSdk.HoistTaskExecutor(dto); - return result.code == "0"; + _agvSemaphore.Release(); + } } /// - /// 将位置字符串转为整数楼层/层号 + /// 下发提升机任务,通过 HoistApi(每台提升机串行) /// - private static int ParseIntPoint(string? point) + private async Task DispatchToHoist(LiveTaskDetail detail) { - if (string.IsNullOrEmpty(point)) - return 0; + var hoistCode = detail.startPoint ?? "default"; + var semaphore = _hoistSemaphores.GetOrAdd(hoistCode, _ => new SemaphoreSlim(1, 1)); - return int.TryParse(point, out var val) ? val : 0; + await semaphore.WaitAsync(); + try + { + var dto = new HoistTaskExeDto + { + hoistCode = hoistCode, + taskCode = detail.taskCode, + startPoint = int.TryParse(detail.startPoint, out var s) ? s : 0, + endPoint = int.TryParse(detail.endPoint, out var e) ? e : 0 + }; + + var result = _hoistService.HoistTaskExecutor(dto); + if (result.code.Equals(HoistStatusEnum.成功)) + { + detail.taskStatus = 2; + _taskDetailService.Update(detail); + return true; + } + + Console.WriteLine($"提升机 {hoistCode} 任务 {detail.taskCode} 下发失败: [{result.code}] {result.msg}"); + return false; + } + finally + { + semaphore.Release(); + } } } -- 2.38.5 From e5abfdfa364196ca179233a61d068ac1d9338785 Mon Sep 17 00:00:00 2001 From: WenJY Date: Mon, 18 May 2026 17:38:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?change=20-=20=E5=8C=85=E6=9D=90=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=E7=AD=96=E7=95=A5=E5=88=9D=E6=AD=A5=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sln.Wcs.Business.Tests.csproj | 29 - .../StoreTaskBusinessTests.cs | 515 ------------------ Sln.Wcs.Business/BaseBusiness.cs | 64 --- Sln.Wcs.Business/InStore/MaterialInStore.cs | 203 ------- Sln.Wcs.Business/InStore/PalletInStore.cs | 199 ------- Sln.Wcs.Business/InStore/ProductInStore.cs | 200 ------- Sln.Wcs.Business/OutStore/MaterialOutStore.cs | 203 ------- Sln.Wcs.Business/OutStore/PalletOutStore.cs | 200 ------- Sln.Wcs.Business/OutStore/ProductOutStore.cs | 200 ------- Sln.Wcs.Business/StoreTaskBusiness.cs | 46 +- Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs | 39 +- Sln.Wcs.Model/Domain/LiveTaskQueue.cs | 3 +- Sln.Wcs.Repository/Repository.cs | 1 + .../service/ILiveTaskQueueService.cs | 9 + .../service/Impl/LiveTaskQueueServiceImpl.cs | 39 ++ Sln.Wcs.Strategy/ITaskExecuteStrategy.cs | 13 - Sln.Wcs.Strategy/MaterialStrategy.cs | 175 ++++++ Sln.Wcs.Strategy/TaskExecuteStrategy.cs | 203 ------- Sln.Wcs.sln | 6 - Sln.Wcs/MaterialInStoreTest.cs | 44 +- Sln.Wcs/Program.cs | 12 + Sln.Wcs/Sln.Wcs.csproj | 1 + 22 files changed, 287 insertions(+), 2117 deletions(-) delete mode 100644 Sln.Wcs.Business.Tests/Sln.Wcs.Business.Tests.csproj delete mode 100644 Sln.Wcs.Business.Tests/StoreTaskBusinessTests.cs delete mode 100644 Sln.Wcs.Business/BaseBusiness.cs delete mode 100644 Sln.Wcs.Business/InStore/MaterialInStore.cs delete mode 100644 Sln.Wcs.Business/InStore/PalletInStore.cs delete mode 100644 Sln.Wcs.Business/InStore/ProductInStore.cs delete mode 100644 Sln.Wcs.Business/OutStore/MaterialOutStore.cs delete mode 100644 Sln.Wcs.Business/OutStore/PalletOutStore.cs delete mode 100644 Sln.Wcs.Business/OutStore/ProductOutStore.cs delete mode 100644 Sln.Wcs.Strategy/ITaskExecuteStrategy.cs create mode 100644 Sln.Wcs.Strategy/MaterialStrategy.cs delete mode 100644 Sln.Wcs.Strategy/TaskExecuteStrategy.cs diff --git a/Sln.Wcs.Business.Tests/Sln.Wcs.Business.Tests.csproj b/Sln.Wcs.Business.Tests/Sln.Wcs.Business.Tests.csproj deleted file mode 100644 index 63712b7..0000000 --- a/Sln.Wcs.Business.Tests/Sln.Wcs.Business.Tests.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - net8.0 - enable - enable - false - true - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/Sln.Wcs.Business.Tests/StoreTaskBusinessTests.cs b/Sln.Wcs.Business.Tests/StoreTaskBusinessTests.cs deleted file mode 100644 index 9ff1ed1..0000000 --- a/Sln.Wcs.Business.Tests/StoreTaskBusinessTests.cs +++ /dev/null @@ -1,515 +0,0 @@ -#region << 版 本 注 释 >> -/*-------------------------------------------------------------------- -|* 版权所有 (c) 2026 WenJY 保留所有权利。 -|* CLR版本:4.0.30319.42000 -|* 机器名称:Mr.Wen's MacBook Pro -|* 命名空间:Sln.Wcs.Business.Tests -|* 唯一标识: -|* -|* 创建者:WenJY -|* 电子邮箱: -|* 创建时间:2026-05-17 -|* 版本:V1.0.0 -|* 描述:StoreTaskBusiness 单元测试 -|* -|*-------------------------------------------------------------------- -|* 修改人: -|* 时间: -|* 修改说明: -|* -|* 版本:V1.0.0 -|*--------------------------------------------------------------------*/ -#endregion << 版 本 注 释 >> - -using Moq; -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.Enum; -using Sln.Wcs.Model.Domain; -using Sln.Wcs.Repository.service; -using Xunit; - -namespace Sln.Wcs.Business.Tests; - -/// -/// 可测试的 StoreTaskBusiness 子类,用于访问 protected 方法 -/// -public class TestableStoreTaskBusiness : StoreTaskBusiness -{ - public TestableStoreTaskBusiness( - IBasePathInfoService basePathInfoService, - ILiveTaskQueueService liveTaskQueueService, - IBaseStoreInfoService baseStoreInfoService) - : base(basePathInfoService, liveTaskQueueService, baseStoreInfoService) - { - } - - public void PublicValidateCreateTaskParams(CreateTaskDto dto) => - ValidateCreateTaskParams(dto); - - public void PublicValidateFilterLocationParams(FilterLocationDto dto) => - ValidateFilterLocationParams(dto); - - public string PublicGenerateTaskCode() => GenerateTaskCode(); - - public string PublicGetCategoryName(TaskCategoryEnum category) => - GetCategoryName(category); - - public string PublicGetTaskTypeName(TaskTypeEnum taskType) => - GetTaskTypeName(taskType); - - public string PublicGetTaskSuccessMessage( - string taskCode, string pathName, TaskTypeEnum taskType, TaskCategoryEnum taskCategory) => - GetTaskSuccessMessage(taskCode, pathName, taskType, taskCategory); - - public BasePathInfo PublicGetPathInfo( - CreateTaskDto createTaskDto, TaskTypeEnum taskType, TaskCategoryEnum taskCategory) => - GetPathInfo(createTaskDto, taskType, taskCategory); -} - -public class StoreTaskBusinessTests -{ - private readonly Mock _mockBasePathInfoService; - private readonly Mock _mockLiveTaskQueueService; - private readonly Mock _mockBaseStoreInfoService; - private readonly TestableStoreTaskBusiness _storeTaskBusiness; - - public StoreTaskBusinessTests() - { - _mockBasePathInfoService = new Mock(); - _mockLiveTaskQueueService = new Mock(); - _mockBaseStoreInfoService = new Mock(); - _storeTaskBusiness = new TestableStoreTaskBusiness( - _mockBasePathInfoService.Object, - _mockLiveTaskQueueService.Object, - _mockBaseStoreInfoService.Object); - } - - #region GetCategoryName 测试 - - [Theory] - [InlineData(TaskCategoryEnum.Material, "包材")] - [InlineData(TaskCategoryEnum.Product, "成品")] - [InlineData(TaskCategoryEnum.Pallet, "托盘")] - public void GetCategoryName_ValidCategory_ReturnsCorrectName(TaskCategoryEnum category, string expected) - { - var result = _storeTaskBusiness.PublicGetCategoryName(category); - Assert.Equal(expected, result); - } - - #endregion - - #region GetTaskTypeName 测试 - - [Theory] - [InlineData(TaskTypeEnum.InStore, "入库")] - [InlineData(TaskTypeEnum.OutStore, "出库")] - public void GetTaskTypeName_ValidType_ReturnsCorrectName(TaskTypeEnum taskType, string expected) - { - var result = _storeTaskBusiness.PublicGetTaskTypeName(taskType); - Assert.Equal(expected, result); - } - - #endregion - - #region ValidateCreateTaskParams 测试 - - [Fact] - public void ValidateCreateTaskParams_NullMaterialCode_ThrowsException() - { - var dto = new CreateTaskDto - { - materialCode = null!, - palletBarcode = "PLT001", - startPoint = "A", - endPoint = "B" - }; - - var exception = Assert.Throws(() => - _storeTaskBusiness.PublicValidateCreateTaskParams(dto)); - - Assert.Contains("物料编号不允许为 NULL", exception.Message); - } - - [Fact] - public void ValidateCreateTaskParams_NullPalletBarcode_ThrowsException() - { - var dto = new CreateTaskDto - { - materialCode = "MAT001", - palletBarcode = null!, - startPoint = "A", - endPoint = "B", - taskCategory = TaskCategoryEnum.Material - }; - - var exception = Assert.Throws(() => - _storeTaskBusiness.PublicValidateCreateTaskParams(dto)); - - Assert.Contains("条码不允许为 NULL", exception.Message); - } - - [Fact] - public void ValidateCreateTaskParams_NullStartPoint_ThrowsException() - { - var dto = new CreateTaskDto - { - materialCode = "MAT001", - palletBarcode = "PLT001", - startPoint = null!, - endPoint = "B" - }; - - var exception = Assert.Throws(() => - _storeTaskBusiness.PublicValidateCreateTaskParams(dto)); - - Assert.Contains("起始位置、终点位置不允许为 NULL", exception.Message); - } - - [Fact] - public void ValidateCreateTaskParams_EmptyEndPoint_ThrowsException() - { - var dto = new CreateTaskDto - { - materialCode = "MAT001", - palletBarcode = "PLT001", - startPoint = "A", - endPoint = "" - }; - - var exception = Assert.Throws(() => - _storeTaskBusiness.PublicValidateCreateTaskParams(dto)); - - Assert.Contains("起始位置、终点位置不允许为 NULL", exception.Message); - } - - [Fact] - public void ValidateCreateTaskParams_ValidParams_NoException() - { - var dto = new CreateTaskDto - { - materialCode = "MAT001", - palletBarcode = "PLT001", - startPoint = "A", - endPoint = "B", - taskCategory = TaskCategoryEnum.Material - }; - - var exception = Record.Exception(() => - _storeTaskBusiness.PublicValidateCreateTaskParams(dto)); - - Assert.Null(exception); - } - - #endregion - - #region ValidateFilterLocationParams 测试 - - [Fact] - public void ValidateFilterLocationParams_NullMaterialCode_ThrowsException() - { - var dto = new FilterLocationDto - { - materialCode = null! - }; - - var exception = Assert.Throws(() => - _storeTaskBusiness.PublicValidateFilterLocationParams(dto)); - - Assert.Contains("物料编号不允许为 NULL", exception.Message); - } - - [Fact] - public void ValidateFilterLocationParams_ValidParams_NoException() - { - var dto = new FilterLocationDto - { - materialCode = "MAT001" - }; - - var exception = Record.Exception(() => - _storeTaskBusiness.PublicValidateFilterLocationParams(dto)); - - Assert.Null(exception); - } - - #endregion - - #region GenerateTaskCode 测试 - - [Fact] - public void GenerateTaskCode_ReturnsCorrectFormat() - { - var taskCode = _storeTaskBusiness.PublicGenerateTaskCode(); - - Assert.NotNull(taskCode); - Assert.Equal(18, taskCode.Length); - Assert.True(long.TryParse(taskCode[..14], out _)); - Assert.True(int.TryParse(taskCode[14..], out var randomPart)); - Assert.InRange(randomPart, 1000, 9999); - } - - [Fact] - public void GenerateTaskCode_MultipleCalls_GeneratesUniqueCodes() - { - var codes = new HashSet(); - for (int i = 0; i < 100; i++) - { - codes.Add(_storeTaskBusiness.PublicGenerateTaskCode()); - } - - Assert.Equal(100, codes.Count); - } - - #endregion - - #region CreateTask 测试 - - [Fact] - public void CreateTask_ValidInput_ReturnsSuccessResult() - { - var dto = new CreateTaskDto - { - materialCode = "MAT001", - materialBarcode = "MAT001BAR", - palletBarcode = "PLT001", - amount = 100, - startPoint = "START", - endPoint = "END", - taskType = TaskTypeEnum.InStore, - taskCategory = TaskCategoryEnum.Material - }; - - var pathDetails = new List - { - new BasePathDetails - { - objId = 1, - pathCode = "PATH1", - startPoint = "START", - endPoint = "MID", - deviceType = 0 - }, - new BasePathDetails - { - objId = 2, - pathCode = "PATH2", - startPoint = "MID", - endPoint = "END", - deviceType = 0 - } - }; - - var pathInfo = new BasePathInfo - { - objId = 1, - pathCode = "MAIN_PATH", - pathName = "主输送线", - pathType = 1, - pathCategory = 1, - startPoint = "START", - endPoint = "END", - pathDetails = pathDetails - }; - - _mockBasePathInfoService - .Setup(x => x.GetBasePathInfo(It.IsAny>>())) - .Returns(new List { pathInfo }); - - var result = _storeTaskBusiness.CreateTask(dto); - - Assert.Equal(BusinessStatusEnum.成功, result.code); - Assert.NotNull(result.data); - Assert.NotNull(result.data.taskCode); - Assert.Equal(2, result.data.taskDetails.Count); - Assert.Equal(2, result.data.taskQueue.taskSteps); - } - - [Fact] - public void CreateTask_PathNotFound_ReturnsErrorResult() - { - var dto = new CreateTaskDto - { - materialCode = "MAT001", - palletBarcode = "PLT001", - startPoint = "INVALID", - endPoint = "INVALID", - taskType = TaskTypeEnum.InStore, - taskCategory = TaskCategoryEnum.Material - }; - - _mockBasePathInfoService - .Setup(x => x.GetBasePathInfo(It.IsAny>>())) - .Returns(new List()); - - var result = _storeTaskBusiness.CreateTask(dto); - - Assert.Equal(BusinessStatusEnum.方法执行异常, result.code); - Assert.Contains("输送路径为 NULL", result.msg); - } - - #endregion - - #region FilterLocation 测试 - - [Fact] - public void FilterLocation_ValidInput_ReturnsSuccessResult() - { - var dto = new FilterLocationDto - { - materialCode = "MAT001", - taskType = TaskTypeEnum.InStore, - taskCategory = TaskCategoryEnum.Material - }; - - var locationInfos = new List - { - new BaseLocationInfo - { - locationCode = "LOC001", - locationRows = 1, - locationColumns = 1, - locationLayers = 1, - locationStatus = 0, - materialCode = "MAT001", - isFlag = 1 - } - }; - - var storeInfo = new BaseStoreInfo - { - storeCode = "STORE001", - storeName = "测试仓库", - storeType = 1, - isFlag = 1, - locationInfos = locationInfos - }; - - _mockBaseStoreInfoService - .Setup(x => x.GetBasePathInfo( - It.IsAny>>(), - It.IsAny>>())) - .Returns(new List { storeInfo }); - - var result = _storeTaskBusiness.FilterLocation(dto); - - Assert.Equal(BusinessStatusEnum.成功, result.code); - Assert.NotNull(result.data); - Assert.NotNull(result.data.storeInfo); - Assert.NotNull(result.data.locationInfo); - Assert.Single(result.data.locationInfos); - } - - [Fact] - public void FilterLocation_NoAvailableStore_ReturnsErrorResult() - { - var dto = new FilterLocationDto - { - materialCode = "MAT001", - taskType = TaskTypeEnum.InStore, - taskCategory = TaskCategoryEnum.Material - }; - - _mockBaseStoreInfoService - .Setup(x => x.GetBasePathInfo( - It.IsAny>>(), - It.IsAny>>())) - .Returns(new List()); - - var result = _storeTaskBusiness.FilterLocation(dto); - - Assert.Equal(BusinessStatusEnum.方法执行异常, result.code); - Assert.Contains("未获取到可用仓库", result.msg); - } - - #endregion - - #region SaveTask 测试 - - [Fact] - public void SaveTask_ValidInput_ReturnsSuccessResult() - { - var dto = new SaveTaskDto - { - taskQueue = new LiveTaskQueue - { - taskCode = "TASK001", - materialCode = "MAT001", - palletBarcode = "PLT001", - startPoint = "A", - endPoint = "B", - taskType = 1, - taskCategory = 1 - } - }; - - _mockLiveTaskQueueService - .Setup(x => x.InsertTaskQueue(It.IsAny())) - .Returns(true); - - var result = _storeTaskBusiness.SaveTask(dto); - - Assert.Equal(BusinessStatusEnum.成功, result.code); - Assert.NotNull(result.data); - Assert.True(result.data.isRes); - } - - [Fact] - public void SaveTask_InsertFails_ReturnsFalse() - { - var dto = new SaveTaskDto - { - taskQueue = new LiveTaskQueue - { - taskCode = "TASK001", - materialCode = "MAT001", - palletBarcode = "PLT001", - startPoint = "A", - endPoint = "B", - taskType = 1, - taskCategory = 1 - } - }; - - _mockLiveTaskQueueService - .Setup(x => x.InsertTaskQueue(It.IsAny())) - .Returns(false); - - var result = _storeTaskBusiness.SaveTask(dto); - - Assert.Equal(BusinessStatusEnum.成功, result.code); - Assert.NotNull(result.data); - Assert.False(result.data.isRes); - } - - #endregion - - #region GetTaskSuccessMessage 测试 - - [Fact] - public void GetTaskSuccessMessage_ReturnsCorrectMessage() - { - var message = _storeTaskBusiness.PublicGetTaskSuccessMessage( - "TASK001", - "主输送线", - TaskTypeEnum.InStore, - TaskCategoryEnum.Material); - - Assert.Equal("包材入库任务创建成功:TASK001;关联路径:主输送线", message); - } - - [Fact] - public void GetTaskSuccessMessage_ProductOutStore_ReturnsCorrectMessage() - { - var message = _storeTaskBusiness.PublicGetTaskSuccessMessage( - "TASK002", - "成品出库线", - TaskTypeEnum.OutStore, - TaskCategoryEnum.Product); - - Assert.Equal("成品出库任务创建成功:TASK002;关联路径:成品出库线", message); - } - - #endregion -} diff --git a/Sln.Wcs.Business/BaseBusiness.cs b/Sln.Wcs.Business/BaseBusiness.cs deleted file mode 100644 index 309f6b8..0000000 --- a/Sln.Wcs.Business/BaseBusiness.cs +++ /dev/null @@ -1,64 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business.InStore -* 唯一标识:6D5BA916-0FBB-4B9D-BBE9-692F39B7F962 -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-07 08:48:17 -* 版本:V1.0.0 -* 描述: -* -*-------------------------------------------------------------------- -* 修改人: -* 时间: -* 修改说明: -* -* 版本:V1.0.0 -*--------------------------------------------------------------------*/ - -#endregion << 版 本 注 释 >> - -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.Util; - -namespace Sln.Wcs.Business; - -public abstract class BaseBusiness:EntityWrapper -{ - - /// - /// 校验物料 - /// - /// - /// - public abstract ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto); - - /// - /// 创建任务 - /// - /// - public abstract CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto ); - - /// - /// 筛选目标库位 - /// - /// - /// - public abstract FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto); - - /// - /// 保存任务 - /// - /// - /// - public abstract SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto); - -} \ No newline at end of file diff --git a/Sln.Wcs.Business/InStore/MaterialInStore.cs b/Sln.Wcs.Business/InStore/MaterialInStore.cs deleted file mode 100644 index 8d0e12d..0000000 --- a/Sln.Wcs.Business/InStore/MaterialInStore.cs +++ /dev/null @@ -1,203 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business -* 唯一标识:A6C78343-F3B7-49DB-A582-768186595E02 -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-06 18:13:10 -* 版本: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.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Business.InStore; - -/// -/// 包材入库 -/// -public class MaterialInStore:BaseBusiness -{ - private readonly IBasePathInfoService _basePathInfoService; - private readonly ILiveTaskQueueService _liveTaskQueueService; - private readonly IBaseStoreInfoService _baseStoreInfoService; - - public MaterialInStore(IBasePathInfoService basePathInfoService, ILiveTaskQueueService liveTaskQueueService, IBaseStoreInfoService baseStoreInfoService) - { - _basePathInfoService = basePathInfoService; - _liveTaskQueueService = liveTaskQueueService; - _baseStoreInfoService = baseStoreInfoService; - } - - public override ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto) - { - throw new NotImplementedException(); - } - - /// - /// 创建任务 - /// - /// - /// - /// - public override CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto) - { - CreateTaskResultDto resultDto = new CreateTaskResultDto(); - try - { - #region CreateTaskDto 参数校验 - - if (string.IsNullOrEmpty(createTaskDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.palletBarcode)) - { - throw new InvalidOperationException($"托盘条码不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint)) - { - throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL"); - } - - #endregion - - createTaskDto.taskType = TaskTypeEnum.InStore; - createTaskDto.taskCategory = TaskCategoryEnum.Material; - //获取包材入库路径 - Expression> exp = x=>x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && x.pathType == (int)createTaskDto.taskType && x.pathCategory == (int)createTaskDto.taskCategory; - BasePathInfo pathInfo = _basePathInfoService.GetBasePathInfo(exp).FirstOrDefault() ?? throw new InvalidOperationException($"包材入库输送路径为 NULL"); - - #region 路径转为任务 - - string taskCode = "2026050700001"; //需根据现场实际定义生成规则 - - List taskDetails = pathInfo.pathDetails.Select( item => base.LiveTaskDetailWrapper(taskCode,createTaskDto,item)).ToList(); - - var taskQueue = base.LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo); - taskQueue.taskSteps = taskDetails.Count; - taskQueue.taskDetails = taskDetails; - #endregion - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = $"包材入库任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; - resultDto.data = new CreateTaskResultModel() - { - taskCode = taskCode, - taskQueue = taskQueue, - taskDetails = taskDetails, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - return resultDto; - } - - /// - /// 筛选库位 - /// - /// - /// - /// - public override FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto) - { - FilterLocationResultDto resultDto = new FilterLocationResultDto(); - try - { - - #region 参数校验 - - if (string.IsNullOrEmpty(filterLocationDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - #endregion - - Expression> storeWhere = x => x.storeType == (int)StoreTypeEnum.Material; - Expression> locationWhere = x=>x.materialCode==filterLocationDto.materialCode && x.locationStatus == 0 && x.isFlag == 1; - - List 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 = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new FilterLocationResultModel() - { - storeInfo = storeInfo, - - locationInfos = storeInfo.locationInfos, - - locationInfo = locationInfo, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } - - /// - /// 保存任务 - /// - /// - /// - public override SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto) - { - SaveTaskResultDto resultDto = new SaveTaskResultDto(); - try - { - var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue); - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new SaveTaskResultModel() - { - isRes = inRes - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } -} \ No newline at end of file diff --git a/Sln.Wcs.Business/InStore/PalletInStore.cs b/Sln.Wcs.Business/InStore/PalletInStore.cs deleted file mode 100644 index 24ad1ae..0000000 --- a/Sln.Wcs.Business/InStore/PalletInStore.cs +++ /dev/null @@ -1,199 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business -* 唯一标识:B0E9FC96-6FA3-48E1-9BD9-9CF0360B168D -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-06 18:15:32 -* 版本: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.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Business.InStore; - -public class PalletInStore:BaseBusiness -{private readonly IBasePathInfoService _basePathInfoService; - private readonly ILiveTaskQueueService _liveTaskQueueService; - private readonly IBaseStoreInfoService _baseStoreInfoService; - - public PalletInStore(IBasePathInfoService basePathInfoService, ILiveTaskQueueService liveTaskQueueService, IBaseStoreInfoService baseStoreInfoService) - { - _basePathInfoService = basePathInfoService; - _liveTaskQueueService = liveTaskQueueService; - _baseStoreInfoService = baseStoreInfoService; - } - - public override ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto) - { - throw new NotImplementedException(); - } - - /// - /// 创建任务 - /// - /// - /// - /// - public override CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto) - { - CreateTaskResultDto resultDto = new CreateTaskResultDto(); - try - { - #region CreateTaskDto 参数校验 - - if (string.IsNullOrEmpty(createTaskDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.palletBarcode)) - { - throw new InvalidOperationException($"托盘条码不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint)) - { - throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL"); - } - - #endregion - - createTaskDto.taskType = TaskTypeEnum.InStore; - createTaskDto.taskCategory = TaskCategoryEnum.Pallet; - //获取托盘入库路径 - Expression> exp = x=>x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && x.pathType == (int)createTaskDto.taskType && x.pathCategory == (int)createTaskDto.taskCategory; - BasePathInfo pathInfo = _basePathInfoService.GetBasePathInfo(exp).FirstOrDefault() ?? throw new InvalidOperationException($"托盘入库输送路径为 NULL"); - - #region 路径转为任务 - - string taskCode = "2026050700001"; //需根据现场实际定义生成规则 - - List taskDetails = pathInfo.pathDetails.Select( item => base.LiveTaskDetailWrapper(taskCode,createTaskDto,item)).ToList(); - - var taskQueue = base.LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo); - taskQueue.taskSteps = taskDetails.Count; - taskQueue.taskDetails = taskDetails; - #endregion - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = $"托盘入库任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; - resultDto.data = new CreateTaskResultModel() - { - taskCode = taskCode, - taskQueue = taskQueue, - taskDetails = taskDetails, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - return resultDto; - } - - /// - /// 筛选库位 - /// - /// - /// - /// - public override FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto) - { - FilterLocationResultDto resultDto = new FilterLocationResultDto(); - try - { - - #region 参数校验 - - if (string.IsNullOrEmpty(filterLocationDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - #endregion - - Expression> storeWhere = x => x.storeType == (int)StoreTypeEnum.Material; - Expression> locationWhere = x=>x.materialCode==filterLocationDto.materialCode && x.locationStatus == 0 && x.isFlag == 1; - - List 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 = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new FilterLocationResultModel() - { - storeInfo = storeInfo, - - locationInfos = storeInfo.locationInfos, - - locationInfo = locationInfo, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } - - /// - /// 保存任务 - /// - /// - /// - public override SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto) - { - SaveTaskResultDto resultDto = new SaveTaskResultDto(); - try - { - var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue); - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new SaveTaskResultModel() - { - isRes = inRes - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } -} \ No newline at end of file diff --git a/Sln.Wcs.Business/InStore/ProductInStore.cs b/Sln.Wcs.Business/InStore/ProductInStore.cs deleted file mode 100644 index e047a16..0000000 --- a/Sln.Wcs.Business/InStore/ProductInStore.cs +++ /dev/null @@ -1,200 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business -* 唯一标识:1DC1227B-C3E0-4E56-803E-0C42C7065515 -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-06 18:13:44 -* 版本: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.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Business.InStore; - -public class ProductInStore:BaseBusiness -{ - private readonly IBasePathInfoService _basePathInfoService; - private readonly ILiveTaskQueueService _liveTaskQueueService; - private readonly IBaseStoreInfoService _baseStoreInfoService; - - public ProductInStore(IBasePathInfoService basePathInfoService, ILiveTaskQueueService liveTaskQueueService, IBaseStoreInfoService baseStoreInfoService) - { - _basePathInfoService = basePathInfoService; - _liveTaskQueueService = liveTaskQueueService; - _baseStoreInfoService = baseStoreInfoService; - } - - public override ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto) - { - throw new NotImplementedException(); - } - - /// - /// 创建任务 - /// - /// - /// - /// - public override CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto) - { - CreateTaskResultDto resultDto = new CreateTaskResultDto(); - try - { - #region CreateTaskDto 参数校验 - - if (string.IsNullOrEmpty(createTaskDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.palletBarcode)) - { - throw new InvalidOperationException($"成品条码不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint)) - { - throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL"); - } - - #endregion - - createTaskDto.taskType = TaskTypeEnum.InStore; - createTaskDto.taskCategory = TaskCategoryEnum.Product; - //获取成品入库路径 - Expression> exp = x=>x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && x.pathType == (int)createTaskDto.taskType && x.pathCategory == (int)createTaskDto.taskCategory; - BasePathInfo pathInfo = _basePathInfoService.GetBasePathInfo(exp).FirstOrDefault() ?? throw new InvalidOperationException($"成品入库输送路径为 NULL"); - - #region 路径转为任务 - - string taskCode = "2026050700001"; //需根据现场实际定义生成规则 - - List taskDetails = pathInfo.pathDetails.Select( item => base.LiveTaskDetailWrapper(taskCode,createTaskDto,item)).ToList(); - - var taskQueue = base.LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo); - taskQueue.taskSteps = taskDetails.Count; - taskQueue.taskDetails = taskDetails; - #endregion - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = $"成品入库任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; - resultDto.data = new CreateTaskResultModel() - { - taskCode = taskCode, - taskQueue = taskQueue, - taskDetails = taskDetails, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - return resultDto; - } - - /// - /// 筛选库位 - /// - /// - /// - /// - public override FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto) - { - FilterLocationResultDto resultDto = new FilterLocationResultDto(); - try - { - - #region 参数校验 - - if (string.IsNullOrEmpty(filterLocationDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - #endregion - - Expression> storeWhere = x => x.storeType == (int)StoreTypeEnum.Material; - Expression> locationWhere = x=>x.materialCode==filterLocationDto.materialCode && x.locationStatus == 0 && x.isFlag == 1; - - List 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 = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new FilterLocationResultModel() - { - storeInfo = storeInfo, - - locationInfos = storeInfo.locationInfos, - - locationInfo = locationInfo, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } - - /// - /// 保存任务 - /// - /// - /// - public override SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto) - { - SaveTaskResultDto resultDto = new SaveTaskResultDto(); - try - { - var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue); - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new SaveTaskResultModel() - { - isRes = inRes - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } -} \ No newline at end of file diff --git a/Sln.Wcs.Business/OutStore/MaterialOutStore.cs b/Sln.Wcs.Business/OutStore/MaterialOutStore.cs deleted file mode 100644 index dccf002..0000000 --- a/Sln.Wcs.Business/OutStore/MaterialOutStore.cs +++ /dev/null @@ -1,203 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business -* 唯一标识:F9D6319A-1B6A-4036-A197-6D5EAE31D711 -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-06 18:13:28 -* 版本: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.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Business.OutStore; - -/// -/// 包材出库 -/// -public class MaterialOutStore:BaseBusiness -{ - private readonly IBasePathInfoService _basePathInfoService; - private readonly ILiveTaskQueueService _liveTaskQueueService; - private readonly IBaseStoreInfoService _baseStoreInfoService; - - public MaterialOutStore(IBasePathInfoService basePathInfoService, ILiveTaskQueueService liveTaskQueueService, IBaseStoreInfoService baseStoreInfoService) - { - _basePathInfoService = basePathInfoService; - _liveTaskQueueService = liveTaskQueueService; - _baseStoreInfoService = baseStoreInfoService; - } - - public override ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto) - { - throw new NotImplementedException(); - } - - /// - /// 创建任务 - /// - /// - /// - /// - public override CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto) - { - CreateTaskResultDto resultDto = new CreateTaskResultDto(); - try - { - #region CreateTaskDto 参数校验 - - if (string.IsNullOrEmpty(createTaskDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.palletBarcode)) - { - throw new InvalidOperationException($"托盘条码不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint)) - { - throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL"); - } - - #endregion - - createTaskDto.taskType = TaskTypeEnum.OutStore; - createTaskDto.taskCategory = TaskCategoryEnum.Material; - //获取包材出库路径 - Expression> exp = x=>x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && x.pathType == (int)createTaskDto.taskType && x.pathCategory == (int)createTaskDto.taskCategory; - BasePathInfo pathInfo = _basePathInfoService.GetBasePathInfo(exp).FirstOrDefault() ?? throw new InvalidOperationException($"包材出库输送路径为 NULL"); - - #region 路径转为任务 - - string taskCode = "2026050700001"; //需根据现场实际定义生成规则 - - List taskDetails = pathInfo.pathDetails.Select( item => base.LiveTaskDetailWrapper(taskCode,createTaskDto,item)).ToList(); - - var taskQueue = base.LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo); - taskQueue.taskSteps = taskDetails.Count; - taskQueue.taskDetails = taskDetails; - #endregion - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = $"包材出库任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; - resultDto.data = new CreateTaskResultModel() - { - taskCode = taskCode, - taskQueue = taskQueue, - taskDetails = taskDetails, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - return resultDto; - } - - /// - /// 筛选库位 - /// - /// - /// - /// - public override FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto) - { - FilterLocationResultDto resultDto = new FilterLocationResultDto(); - try - { - - #region 参数校验 - - if (string.IsNullOrEmpty(filterLocationDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - #endregion - - Expression> storeWhere = x => x.storeType == (int)StoreTypeEnum.Material; - Expression> locationWhere = x=>x.materialCode==filterLocationDto.materialCode && x.locationStatus == 1 && x.isFlag == 1; - - List 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 = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new FilterLocationResultModel() - { - storeInfo = storeInfo, - - locationInfos = storeInfo.locationInfos, - - locationInfo = locationInfo, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } - - /// - /// 保存任务 - /// - /// - /// - public override SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto) - { - SaveTaskResultDto resultDto = new SaveTaskResultDto(); - try - { - var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue); - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new SaveTaskResultModel() - { - isRes = inRes - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } -} \ No newline at end of file diff --git a/Sln.Wcs.Business/OutStore/PalletOutStore.cs b/Sln.Wcs.Business/OutStore/PalletOutStore.cs deleted file mode 100644 index bedb8e9..0000000 --- a/Sln.Wcs.Business/OutStore/PalletOutStore.cs +++ /dev/null @@ -1,200 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business -* 唯一标识:1377DAE2-C6B2-4B2D-A553-905D3588649F -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-06 18:15:46 -* 版本: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.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Business.OutStore; - -public class PalletOutStore:BaseBusiness -{ - private readonly IBasePathInfoService _basePathInfoService; - private readonly ILiveTaskQueueService _liveTaskQueueService; - private readonly IBaseStoreInfoService _baseStoreInfoService; - - public PalletOutStore(IBasePathInfoService basePathInfoService, ILiveTaskQueueService liveTaskQueueService, IBaseStoreInfoService baseStoreInfoService) - { - _basePathInfoService = basePathInfoService; - _liveTaskQueueService = liveTaskQueueService; - _baseStoreInfoService = baseStoreInfoService; - } - - public override ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto) - { - throw new NotImplementedException(); - } - - /// - /// 创建任务 - /// - /// - /// - /// - public override CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto) - { - CreateTaskResultDto resultDto = new CreateTaskResultDto(); - try - { - #region CreateTaskDto 参数校验 - - if (string.IsNullOrEmpty(createTaskDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.palletBarcode)) - { - throw new InvalidOperationException($"托盘条码不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint)) - { - throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL"); - } - - #endregion - - createTaskDto.taskType = TaskTypeEnum.OutStore; - createTaskDto.taskCategory = TaskCategoryEnum.Material; - //获取托盘出库路径 - Expression> exp = x=>x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && x.pathType == (int)createTaskDto.taskType && x.pathCategory == (int)createTaskDto.taskCategory; - BasePathInfo pathInfo = _basePathInfoService.GetBasePathInfo(exp).FirstOrDefault() ?? throw new InvalidOperationException($"托盘出库输送路径为 NULL"); - - #region 路径转为任务 - - string taskCode = "2026050700001"; //需根据现场实际定义生成规则 - - List taskDetails = pathInfo.pathDetails.Select( item => base.LiveTaskDetailWrapper(taskCode,createTaskDto,item)).ToList(); - - var taskQueue = base.LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo); - taskQueue.taskSteps = taskDetails.Count; - taskQueue.taskDetails = taskDetails; - #endregion - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = $"托盘出库任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; - resultDto.data = new CreateTaskResultModel() - { - taskCode = taskCode, - taskQueue = taskQueue, - taskDetails = taskDetails, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - return resultDto; - } - - /// - /// 筛选库位 - /// - /// - /// - /// - public override FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto) - { - FilterLocationResultDto resultDto = new FilterLocationResultDto(); - try - { - - #region 参数校验 - - if (string.IsNullOrEmpty(filterLocationDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - #endregion - - Expression> storeWhere = x => x.storeType == (int)StoreTypeEnum.Pallet; - Expression> locationWhere = x=>x.materialCode==filterLocationDto.materialCode && x.locationStatus == 1 && x.isFlag == 1; - - List 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 = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new FilterLocationResultModel() - { - storeInfo = storeInfo, - - locationInfos = storeInfo.locationInfos, - - locationInfo = locationInfo, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } - - /// - /// 保存任务 - /// - /// - /// - public override SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto) - { - SaveTaskResultDto resultDto = new SaveTaskResultDto(); - try - { - var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue); - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new SaveTaskResultModel() - { - isRes = inRes - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } -} \ No newline at end of file diff --git a/Sln.Wcs.Business/OutStore/ProductOutStore.cs b/Sln.Wcs.Business/OutStore/ProductOutStore.cs deleted file mode 100644 index 125d364..0000000 --- a/Sln.Wcs.Business/OutStore/ProductOutStore.cs +++ /dev/null @@ -1,200 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.Business -* 唯一标识:CA9C52F5-4F55-406E-BD31-EF2856EB75DE -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-05-06 18:14:10 -* 版本: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.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Business.OutStore; - -public class ProductOutStore:BaseBusiness -{ - private readonly IBasePathInfoService _basePathInfoService; - private readonly ILiveTaskQueueService _liveTaskQueueService; - private readonly IBaseStoreInfoService _baseStoreInfoService; - - public ProductOutStore(IBasePathInfoService basePathInfoService, ILiveTaskQueueService liveTaskQueueService, IBaseStoreInfoService baseStoreInfoService) - { - _basePathInfoService = basePathInfoService; - _liveTaskQueueService = liveTaskQueueService; - _baseStoreInfoService = baseStoreInfoService; - } - - public override ValidateMaterialResultDto ValidateMaterial(ValidateMaterialDto validateMaterialDto) - { - throw new NotImplementedException(); - } - - /// - /// 创建任务 - /// - /// - /// - /// - public override CreateTaskResultDto CreateTask(CreateTaskDto createTaskDto) - { - CreateTaskResultDto resultDto = new CreateTaskResultDto(); - try - { - #region CreateTaskDto 参数校验 - - if (string.IsNullOrEmpty(createTaskDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.palletBarcode)) - { - throw new InvalidOperationException($"托盘条码不允许为 NULL"); - } - - if (string.IsNullOrEmpty(createTaskDto.startPoint) || string.IsNullOrEmpty(createTaskDto.endPoint)) - { - throw new InvalidOperationException($"起始位置、终点位置不允许为 NULL"); - } - - #endregion - - createTaskDto.taskType = TaskTypeEnum.OutStore; - createTaskDto.taskCategory = TaskCategoryEnum.Material; - //获取托盘成品路径 - Expression> exp = x=>x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && x.pathType == (int)createTaskDto.taskType && x.pathCategory == (int)createTaskDto.taskCategory; - BasePathInfo pathInfo = _basePathInfoService.GetBasePathInfo(exp).FirstOrDefault() ?? throw new InvalidOperationException($"托盘成品输送路径为 NULL"); - - #region 路径转为任务 - - string taskCode = "2026050700001"; //需根据现场实际定义生成规则 - - List taskDetails = pathInfo.pathDetails.Select( item => base.LiveTaskDetailWrapper(taskCode,createTaskDto,item)).ToList(); - - var taskQueue = base.LiveTaskQueueWrapper(taskCode, createTaskDto, pathInfo); - taskQueue.taskSteps = taskDetails.Count; - taskQueue.taskDetails = taskDetails; - #endregion - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = $"托盘成品任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; - resultDto.data = new CreateTaskResultModel() - { - taskCode = taskCode, - taskQueue = taskQueue, - taskDetails = taskDetails, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - return resultDto; - } - - /// - /// 筛选库位 - /// - /// - /// - /// - public override FilterLocationResultDto FilterLocation(FilterLocationDto filterLocationDto) - { - FilterLocationResultDto resultDto = new FilterLocationResultDto(); - try - { - - #region 参数校验 - - if (string.IsNullOrEmpty(filterLocationDto.materialCode)) - { - throw new InvalidOperationException($"物料编号不允许为 NULL"); - } - - #endregion - - Expression> storeWhere = x => x.storeType == (int)StoreTypeEnum.Product; - Expression> locationWhere = x=>x.materialCode==filterLocationDto.materialCode && x.locationStatus == 1 && x.isFlag == 1; - - List 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 = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new FilterLocationResultModel() - { - storeInfo = storeInfo, - - locationInfos = storeInfo.locationInfos, - - locationInfo = locationInfo, - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } - - /// - /// 保存任务 - /// - /// - /// - public override SaveTaskResultDto SaveTask(SaveTaskDto saveTaskDto) - { - SaveTaskResultDto resultDto = new SaveTaskResultDto(); - try - { - var inRes = _liveTaskQueueService.InsertTaskQueue(saveTaskDto.taskQueue); - - resultDto.code = BusinessStatusEnum.成功; - resultDto.msg = "执行完成"; - resultDto.data = new SaveTaskResultModel() - { - isRes = inRes - }; - } - catch (Exception e) - { - resultDto.code = BusinessStatusEnum.方法执行异常; - resultDto.msg = e.Message; - } - - return resultDto; - } -} \ No newline at end of file diff --git a/Sln.Wcs.Business/StoreTaskBusiness.cs b/Sln.Wcs.Business/StoreTaskBusiness.cs index 366aa73..705793b 100644 --- a/Sln.Wcs.Business/StoreTaskBusiness.cs +++ b/Sln.Wcs.Business/StoreTaskBusiness.cs @@ -44,9 +44,9 @@ namespace Sln.Wcs.Business; /// public class StoreTaskBusiness : EntityWrapper { - protected readonly IBasePathInfoService _basePathInfoService; - protected readonly ILiveTaskQueueService _liveTaskQueueService; - protected readonly IBaseStoreInfoService _baseStoreInfoService; + private readonly IBasePathInfoService _basePathInfoService; + private readonly ILiveTaskQueueService _liveTaskQueueService; + private readonly IBaseStoreInfoService _baseStoreInfoService; /// /// 构造函数 @@ -83,16 +83,12 @@ public class StoreTaskBusiness : EntityWrapper CreateTaskResultDto resultDto = new CreateTaskResultDto(); try { - // 1. 参数校验(可扩展) ValidateCreateTaskParams(createTaskDto); - // 2. 获取输送路径 - BasePathInfo pathInfo = GetPathInfo(createTaskDto, createTaskDto.taskType, createTaskDto.taskCategory); + BasePathInfo pathInfo = GetPathInfo(createTaskDto); - // 4. 生成任务编号 string taskCode = GenerateTaskCode(); - // 5. 路径转为任务 List taskDetails = pathInfo.pathDetails .Select(item => LiveTaskDetailWrapper(taskCode, createTaskDto, item)) .ToList(); @@ -101,9 +97,8 @@ public class StoreTaskBusiness : EntityWrapper taskQueue.taskSteps = taskDetails.Count; taskQueue.taskDetails = taskDetails; - // 6. 返回结果 resultDto.code = Domain.Enum.BusinessStatusEnum.成功; - resultDto.msg = GetTaskSuccessMessage(taskCode, pathInfo.pathName, createTaskDto.taskType, createTaskDto.taskCategory); + resultDto.msg = $"{GetCategoryName(createTaskDto.taskCategory)}{GetTaskTypeName(createTaskDto.taskType)}任务创建成功:{taskCode};关联路径:{pathInfo.pathName}"; resultDto.data = new CreateTaskResultModel() { taskCode = taskCode, @@ -128,20 +123,15 @@ public class StoreTaskBusiness : EntityWrapper FilterLocationResultDto resultDto = new FilterLocationResultDto(); try { - // 1. 参数校验(可扩展) ValidateFilterLocationParams(filterLocationDto); - // 2. 获取库位状态(入库:未使用=0,出库:已使用=1) int locationStatus = filterLocationDto.taskType == TaskTypeEnum.InStore ? 0 : 1; - // 3. 构建查询条件 Expression> storeWhere = GetStoreWhere(filterLocationDto.taskType, filterLocationDto.taskCategory); Expression> locationWhere = GetLocationWhere(filterLocationDto, locationStatus); - // 4. 查询仓库和库位 List storeInfos = _baseStoreInfoService.GetBasePathInfo(storeWhere, locationWhere); - // 5. 选择最优仓库和库位 BaseStoreInfo? storeInfo = storeInfos .Where(s => s.locationInfos.Count > 0) .OrderBy(x => x.storeCode) @@ -235,16 +225,16 @@ public class StoreTaskBusiness : EntityWrapper /// /// 获取路径信息(可被子类重写定制路径查询逻辑) /// - protected virtual BasePathInfo GetPathInfo(CreateTaskDto createTaskDto, TaskTypeEnum taskType, TaskCategoryEnum taskCategory) + protected virtual BasePathInfo GetPathInfo(CreateTaskDto createTaskDto) { Expression> exp = x => x.startPoint == createTaskDto.startPoint && x.endPoint == createTaskDto.endPoint && - x.pathType == (int)taskType && - x.pathCategory == (int)taskCategory; + x.pathType == (int)createTaskDto.taskType && + x.pathCategory == (int)createTaskDto.taskCategory; return _basePathInfoService.GetBasePathInfo(exp) - .FirstOrDefault() ?? throw new InvalidOperationException($"{GetCategoryName(taskCategory)}{GetTaskTypeName(taskType)}输送路径为 NULL"); + .FirstOrDefault() ?? throw new InvalidOperationException($"{GetCategoryName(createTaskDto.taskCategory)}{GetTaskTypeName(createTaskDto.taskType)}输送路径为 NULL"); } /// @@ -252,15 +242,7 @@ public class StoreTaskBusiness : EntityWrapper /// protected virtual string GenerateTaskCode() { - return DateTime.Now.ToString("yyyyMMddHHmmss") + new Random().Next(1000, 9999); - } - - /// - /// 获取任务成功的消息(可被子类重写) - /// - protected virtual string GetTaskSuccessMessage(string taskCode, string pathName, TaskTypeEnum taskType, TaskCategoryEnum taskCategory) - { - return $"{GetCategoryName(taskCategory)}{GetTaskTypeName(taskType)}任务创建成功:{taskCode};关联路径:{pathName}"; + return DateTime.Now.ToString("yyyyMMddHHmmss") + new Random().Next(10, 99); } /// @@ -283,12 +265,10 @@ public class StoreTaskBusiness : EntityWrapper #endregion - #region 辅助方法 - /// /// 获取分类名称 /// - protected string GetCategoryName(TaskCategoryEnum taskCategory) + private string GetCategoryName(TaskCategoryEnum taskCategory) { return taskCategory switch { @@ -302,7 +282,7 @@ public class StoreTaskBusiness : EntityWrapper /// /// 获取任务类型名称 /// - protected string GetTaskTypeName(TaskTypeEnum taskType) + private string GetTaskTypeName(TaskTypeEnum taskType) { return taskType switch { @@ -311,6 +291,4 @@ public class StoreTaskBusiness : EntityWrapper _ => "未知" }; } - - #endregion } diff --git a/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs b/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs index 8183542..dcb8fa4 100644 --- a/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs +++ b/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs @@ -45,36 +45,15 @@ namespace Sln.Wcs.HikRoBotSdk.Config /// IConfiguration configuration public HikRoBotConfig(IConfiguration configuration) { - if (string.IsNullOrEmpty(configuration["sdk_api"])) - { - throw new Exception("sdk_api 配置不正确,请检查Apollo配置."); - } - if (string.IsNullOrEmpty(configuration["sdk_json_str"])) - { - throw new Exception("sdk_partner_id 配置不正确,请检查Apollo配置."); - } - //if (string.IsNullOrEmpty(configuration["sdk_accesskey"])) - //{ - // throw new Exception("sdk_accesskey 配置不正确,请检查Apollo配置."); - //} - //if (string.IsNullOrEmpty(configuration["sdk_secretkey"])) - //{ - // throw new Exception("sdk_secretkey 配置不正确,请检查Apollo配置."); - //} - //if (string.IsNullOrEmpty(configuration["sdk_partner_id"])) - //{ - // throw new Exception("sdk_partner_id 配置不正确,请检查Apollo配置."); - //} - //if (string.IsNullOrEmpty(configuration["sdk_version"])) - //{ - // throw new Exception("sdk_version 配置不正确,请检查Apollo配置."); - //} - - api = configuration["sdk_json_str"]; - //accesskey = configuration["sdk_accesskey"]; - //secretkey = configuration["sdk_secretkey"]; - //version = configuration["sdk_version"]; - //test = configuration["sdk_test"]; + // if (string.IsNullOrEmpty(configuration["sdk_api"])) + // { + // throw new Exception("sdk_api 配置不正确,请检查Apollo配置."); + // } + // if (string.IsNullOrEmpty(configuration["sdk_json_str"])) + // { + // throw new Exception("sdk_partner_id 配置不正确,请检查Apollo配置."); + // } + // api = configuration["sdk_json_str"]; } } diff --git a/Sln.Wcs.Model/Domain/LiveTaskQueue.cs b/Sln.Wcs.Model/Domain/LiveTaskQueue.cs index 4aaa20b..e22b6a0 100644 --- a/Sln.Wcs.Model/Domain/LiveTaskQueue.cs +++ b/Sln.Wcs.Model/Domain/LiveTaskQueue.cs @@ -155,7 +155,8 @@ public class LiveTaskQueue /// /// 明细集合 - /// + /// x [SugarColumn(IsIgnore = true)] + [Navigate(NavigateType.OneToMany, nameof(LiveTaskDetail.taskCode), nameof(taskCode))] public List taskDetails { get; set; } } \ No newline at end of file diff --git a/Sln.Wcs.Repository/Repository.cs b/Sln.Wcs.Repository/Repository.cs index 4c82bfc..80f56d8 100644 --- a/Sln.Wcs.Repository/Repository.cs +++ b/Sln.Wcs.Repository/Repository.cs @@ -37,6 +37,7 @@ namespace Sln.Wcs.Repository { itenant = db.AsTenant(); //用来处理事务 base.Context = db.AsTenant().GetConnectionScopeWithAttr(); //获取子Db + //base.Context = db.AsTenant().GetConnectionScope("core"); //如果不想通过注入多个仓储 //用到ChangeRepository或者Db.GetMyRepository需要看标题4写法 diff --git a/Sln.Wcs.Repository/service/ILiveTaskQueueService.cs b/Sln.Wcs.Repository/service/ILiveTaskQueueService.cs index 4eb70cb..e02b5d8 100644 --- a/Sln.Wcs.Repository/service/ILiveTaskQueueService.cs +++ b/Sln.Wcs.Repository/service/ILiveTaskQueueService.cs @@ -23,6 +23,7 @@ #endregion << 版 本 注 释 >> +using System.Linq.Expressions; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository.service.@base; @@ -31,4 +32,12 @@ namespace Sln.Wcs.Repository.service; public interface ILiveTaskQueueService:IBaseService { bool InsertTaskQueue(LiveTaskQueue taskQueue); + + /// + /// 获取任务队列:关联任务明细 + /// + /// + /// + /// + List getLiveTaskQueues(Expression> exp); } \ No newline at end of file diff --git a/Sln.Wcs.Repository/service/Impl/LiveTaskQueueServiceImpl.cs b/Sln.Wcs.Repository/service/Impl/LiveTaskQueueServiceImpl.cs index 89718db..6d4ebf7 100644 --- a/Sln.Wcs.Repository/service/Impl/LiveTaskQueueServiceImpl.cs +++ b/Sln.Wcs.Repository/service/Impl/LiveTaskQueueServiceImpl.cs @@ -23,6 +23,7 @@ #endregion << 版 本 注 释 >> +using System.Linq.Expressions; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository.service.@base; @@ -56,4 +57,42 @@ public class LiveTaskQueueServiceImpl: BaseServiceImpl, ILiveTask } return res; } + + public List getLiveTaskQueues(Expression> exp = null) + { + try + { + var res = _rep.Context.Queryable() + .Includes(x => x.taskDetails) // 先加载所有 + .Where(exp) + .ToList() + .Select(task => new LiveTaskQueue + { + objId = task.objId, + taskCode = task.taskCode, + materialCode = task.materialCode, + palletBarcode = task.palletBarcode, + materialBarcode = task.materialBarcode, + materialCount = task.materialCount, + taskType = task.taskType, + taskCategory = task.taskCategory, + startPoint = task.startPoint, + endPoint = task.endPoint, + pathCode = task.pathCode, + taskSteps = task.taskSteps, + isFlag = task.isFlag, + remark = task.remark, + taskDetails = task.taskDetails.AsQueryable() + //.Where(detailWhere) // 应用子表查询条件 + .Where(p => p.isFlag == 1) + .ToList() + }).ToList(); + + return res; + } + catch (Exception ex) + { + throw new InvalidOperationException($"通过导航查询方式获取任务信息及下属参数执行异常:{ex.Message}"); + } + } } \ No newline at end of file diff --git a/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs b/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs deleted file mode 100644 index 3ffb4f3..0000000 --- a/Sln.Wcs.Strategy/ITaskExecuteStrategy.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Sln.Wcs.Strategy; - -/// -/// 任务执行调度策略 - 按任务类别(包材/托盘/成品)并行调度, -/// AGV 阶段并发下发(多车),提升机阶段按设备串行下发 -/// -public interface ITaskExecuteStrategy -{ - /// - /// 启动任务调度,持续运行直到 cancellationToken 被取消 - /// - Task ExecuteAsync(CancellationToken cancellationToken = default); -} diff --git a/Sln.Wcs.Strategy/MaterialStrategy.cs b/Sln.Wcs.Strategy/MaterialStrategy.cs new file mode 100644 index 0000000..6d9ed83 --- /dev/null +++ b/Sln.Wcs.Strategy/MaterialStrategy.cs @@ -0,0 +1,175 @@ +using Sln.Wcs.Model.Domain; +using Sln.Wcs.Repository.service; +using Sln.Wcs.Serilog; + +namespace Sln.Wcs.Strategy; + +public class MaterialStrategy +{ + private readonly SerilogHelper _logger; + private readonly ILiveTaskQueueService _taskQueueService; + private readonly ILiveTaskDetailService _taskDetailService; + + private CancellationTokenSource? _cts; + private bool _isRunning; + + public MaterialStrategy( + SerilogHelper logger, + ILiveTaskQueueService taskQueueService, + ILiveTaskDetailService taskDetailService) + { + _logger = logger; + _taskQueueService = taskQueueService; + _taskDetailService = taskDetailService; + } + + public void Run() + { + _logger.Info("包材任务调度就绪,输入 start 启动,stop 停止,quit 退出"); + + while (true) + { + var input = Console.ReadLine()?.Trim().ToLower(); + + switch (input) + { + case "start": + Start(); + break; + case "stop": + Stop(); + break; + case "quit": + Stop(); + return; + default: + _logger.Info("未知指令,可用: start | stop | quit"); + break; + } + } + } + + private void Start() + { + if (_isRunning) + { + _logger.Info("调度已在运行中"); + return; + } + + _cts = new CancellationTokenSource(); + _isRunning = true; + + Task.Run(() => SchedulingLoop(_cts.Token)); + + _logger.Info("调度已启动"); + } + + private void Stop() + { + if (!_isRunning) + { + _logger.Info("调度未在运行"); + return; + } + + _cts?.Cancel(); + _isRunning = false; + _logger.Info("调度已停止"); + } + + private void SchedulingLoop(CancellationToken ct) + { + while (!ct.IsCancellationRequested) + { + var taskQueues = _taskQueueService.getLiveTaskQueues(x => + x.taskCategory == 1 && x.taskStatus == 1); + + _logger.Info($"查询待执行包材任务,共 {taskQueues.Count} 条"); + + if (taskQueues.Count > 0) + { + Parallel.ForEach(taskQueues, task => + { + ProcessTask(task, ct); + }); + } + + Thread.Sleep(1000); + } + + _logger.Info("调度循环已退出"); + } + + private void ProcessTask(LiveTaskQueue task, CancellationToken ct) + { + if (ct.IsCancellationRequested) return; + + _logger.Info($"开始执行任务 {task.taskCode},子任务数 {task.taskDetails.Count}"); + + task.taskStatus = 2; + _taskQueueService.Update(task); + + foreach (var detail in task.taskDetails.OrderBy(x => x.objId)) + { + if (ct.IsCancellationRequested) + { + _logger.Info($"任务 {task.taskCode} 被中断,当前步骤 {detail.objId} 未执行"); + return; + } + + _logger.Info($"子任务 {task.taskCode}-{detail.objId},设备类型 {detail.deviceType}"); + + if (detail.taskStatus == 2 || detail.taskStatus == 3) + { + _logger.Info($"子任务 {task.taskCode}-{detail.objId},已下发,不再重复下发"); + continue; + } + + var success = detail.deviceType switch + { + 1 => DispatchToAgv(detail), + 2 => DispatchToHoist(detail), + _ => true + }; + + if (success) + { + detail.taskStatus = 2; + _taskDetailService.Update(detail); + _logger.Info($"子任务 {task.taskCode}-{detail.objId} 下发成功"); + } + else + { + _logger.Error($"子任务 {task.taskCode}-{detail.objId} 下发失败,中断后续步骤"); + break; + } + } + + if (ct.IsCancellationRequested) return; + + task.taskStatus = 3; + _taskQueueService.Update(task); + _logger.Info($"任务 {task.taskCode} 执行完成"); + } + + private bool DispatchToAgv(LiveTaskDetail detail) + { + if (detail.taskCode == "2026051816004580") + { + Task.Delay(1000 * 3).Wait(); + } + _logger.Info($"AGV 下发: {detail.taskCode}-{detail.objId},起点 {detail.startPoint} → 终点 {detail.endPoint}"); + return true; + } + + private bool DispatchToHoist(LiveTaskDetail detail) + { + if (detail.taskCode == "2026050700001") + { + Task.Delay(1000 * 3).Wait(); + } + _logger.Info($"提升机下发: {detail.taskCode}-{detail.objId},起点 {detail.startPoint} → 终点 {detail.endPoint}"); + return true; + } +} diff --git a/Sln.Wcs.Strategy/TaskExecuteStrategy.cs b/Sln.Wcs.Strategy/TaskExecuteStrategy.cs deleted file mode 100644 index 6abba79..0000000 --- a/Sln.Wcs.Strategy/TaskExecuteStrategy.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System.Collections.Concurrent; -using Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask; -using Sln.Wcs.HikRoBotApi.Enum; -using Sln.Wcs.HikRoBotApi.Service; -using Sln.Wcs.HoistApi.Domain.Dto.HoistTaskExecutor; -using Sln.Wcs.HoistApi.Domain.Enum; -using Sln.Wcs.HoistApi.Service; -using Sln.Wcs.Model.Domain; -using Sln.Wcs.Repository.service; - -namespace Sln.Wcs.Strategy; - -public class TaskExecuteStrategy : ITaskExecuteStrategy -{ - private readonly ILiveTaskQueueService _taskQueueService; - private readonly ILiveTaskDetailService _taskDetailService; - private readonly IHikRoBotService _hikRobotService; - private readonly IHoistApiService _hoistService; - - // AGV 多车并发,默认最大 10 个并发 - private readonly SemaphoreSlim _agvSemaphore = new(10, 10); - - // 提升机按设备串行,每台提升机一次只能执行一个任务 - private readonly ConcurrentDictionary _hoistSemaphores = new(); - - public TaskExecuteStrategy( - ILiveTaskQueueService taskQueueService, - ILiveTaskDetailService taskDetailService, - IHikRoBotService hikRobotService, - IHoistApiService hoistService) - { - _taskQueueService = taskQueueService; - _taskDetailService = taskDetailService; - _hikRobotService = hikRobotService; - _hoistService = hoistService; - } - - public Task ExecuteAsync(CancellationToken cancellationToken = default) - { - return Task.WhenAll( - ProcessCategory(1, cancellationToken), // 包材 - ProcessCategory(2, cancellationToken), // 成品 - ProcessCategory(3, cancellationToken) // 托盘 - ); - } - - /// - /// 按任务类别轮询待执行任务,同一类别内多个任务并行处理 - /// - private async Task ProcessCategory(int taskCategory, CancellationToken ct) - { - while (!ct.IsCancellationRequested) - { - try - { - var pendingTasks = _taskQueueService.Query(x => - x.taskStatus == 1 && x.taskCategory == taskCategory); - - if (pendingTasks.Count > 0) - { - await Parallel.ForEachAsync(pendingTasks, ct, async (task, innerCt) => - { - await ProcessTask(task, innerCt); - }); - } - } - catch (Exception ex) - { - Console.WriteLine($"任务类别 {taskCategory} 调度异常: {ex.Message}"); - } - - await Task.Delay(1000, ct); - } - } - - /// - /// 处理单个任务:按顺序遍历明细步骤,依次下发到对应设备 - /// - private async Task ProcessTask(LiveTaskQueue task, CancellationToken ct) - { - try - { - var details = _taskDetailService.Query(x => - x.taskCode == task.taskCode && x.taskStatus == 1) - .OrderBy(x => x.objId) - .ToList(); - - foreach (var detail in details) - { - if (ct.IsCancellationRequested) return; - - var success = await DispatchDetail(detail); - if (!success) break; - } - - // 检查是否还有待执行的明细,若无则更新队列状态为执行中 - var remainingPending = _taskDetailService.Query(x => - x.taskCode == task.taskCode && x.taskStatus == 1); - - if (remainingPending.Count == 0) - { - task.taskStatus = 2; - _taskQueueService.Update(task); - } - } - catch (Exception ex) - { - Console.WriteLine($"任务 {task.taskCode} 处理异常: {ex.Message}"); - } - } - - /// - /// 根据设备类型分发明细到对应设备 API - /// - private Task DispatchDetail(LiveTaskDetail detail) - { - return detail.deviceType switch - { - 1 => DispatchToAgv(detail), - 2 => DispatchToHoist(detail), - _ => Task.FromResult(false) // ConveyorLine 暂不处理 - }; - } - - /// - /// 下发 AGV 任务,通过 HikRoBotApi(AGV 多车可并发) - /// - private async Task DispatchToAgv(LiveTaskDetail detail) - { - await _agvSemaphore.WaitAsync(); - try - { - var dto = new GenAgvSchedulingTaskDto - { - reqCode = detail.taskCode, - reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), - clientCode = "WCS", - taskCode = detail.taskCode, - taskTyp = detail.taskType switch { 1 => "1", 2 => "2", _ => "0" }, - taskMode = detail.taskType switch { 1 => "2", 2 => "1", _ => "0" }, - wbCode = detail.startPoint, - ctnrCode = detail.palletBarcode, - materialLot = detail.materialBarcode, - positionCodePath = new List - { - new() { positionCode = detail.startPoint, type = "00" }, - new() { positionCode = detail.endPoint, type = "00" } - } - }; - - var result = _hikRobotService.GetGenAgvSchedulingTask(dto); - if (result.code.Equals(HikRoBotStatusEnum.成功)) - { - detail.taskStatus = 2; - _taskDetailService.Update(detail); - return true; - } - - Console.WriteLine($"AGV 任务 {detail.taskCode} 下发失败: [{result.code}] {result.msg}"); - return false; - } - finally - { - _agvSemaphore.Release(); - } - } - - /// - /// 下发提升机任务,通过 HoistApi(每台提升机串行) - /// - private async Task DispatchToHoist(LiveTaskDetail detail) - { - var hoistCode = detail.startPoint ?? "default"; - var semaphore = _hoistSemaphores.GetOrAdd(hoistCode, _ => new SemaphoreSlim(1, 1)); - - await semaphore.WaitAsync(); - try - { - var dto = new HoistTaskExeDto - { - hoistCode = hoistCode, - taskCode = detail.taskCode, - startPoint = int.TryParse(detail.startPoint, out var s) ? s : 0, - endPoint = int.TryParse(detail.endPoint, out var e) ? e : 0 - }; - - var result = _hoistService.HoistTaskExecutor(dto); - if (result.code.Equals(HoistStatusEnum.成功)) - { - detail.taskStatus = 2; - _taskDetailService.Update(detail); - return true; - } - - Console.WriteLine($"提升机 {hoistCode} 任务 {detail.taskCode} 下发失败: [{result.code}] {result.msg}"); - return false; - } - finally - { - semaphore.Release(); - } - } -} diff --git a/Sln.Wcs.sln b/Sln.Wcs.sln index 67a0951..554a345 100644 --- a/Sln.Wcs.sln +++ b/Sln.Wcs.sln @@ -28,8 +28,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Business", "Sln.Wcs EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Strategy", "Sln.Wcs.Strategy\Sln.Wcs.Strategy.csproj", "{F7658F97-F78A-4612-A1A5-490F2CDE49DD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Business.Tests", "Sln.Wcs.Business.Tests\Sln.Wcs.Business.Tests.csproj", "{0911EA85-F152-453E-BB7D-4C7079361443}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -88,10 +86,6 @@ Global {F7658F97-F78A-4612-A1A5-490F2CDE49DD}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7658F97-F78A-4612-A1A5-490F2CDE49DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7658F97-F78A-4612-A1A5-490F2CDE49DD}.Release|Any CPU.Build.0 = Release|Any CPU - {0911EA85-F152-453E-BB7D-4C7079361443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0911EA85-F152-453E-BB7D-4C7079361443}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0911EA85-F152-453E-BB7D-4C7079361443}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0911EA85-F152-453E-BB7D-4C7079361443}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sln.Wcs/MaterialInStoreTest.cs b/Sln.Wcs/MaterialInStoreTest.cs index 585df70..3673eeb 100644 --- a/Sln.Wcs/MaterialInStoreTest.cs +++ b/Sln.Wcs/MaterialInStoreTest.cs @@ -23,18 +23,19 @@ #endregion << 版 本 注 释 >> +using Sln.Wcs.Business; 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.InStore; +using Sln.Wcs.Business.Domain.Enum; namespace Sln.Wcs; public class MaterialInStoreTest { - private readonly MaterialInStore _service; + private readonly StoreTaskBusiness _service; - public MaterialInStoreTest(MaterialInStore service) + public MaterialInStoreTest(StoreTaskBusiness service) { _service = service; } @@ -47,22 +48,31 @@ public class MaterialInStoreTest palletBarcode = "20260507000001" }); - var info = _service.CreateTask(new CreateTaskDto() + for (int i = 0; i < 10; i++) { - materialCode = "20260507000001", - materialBarcode = "20260507000001", - palletBarcode = "20260507000001", - amount = 1, - startPoint = "13#_L1_01", - endPoint = "15#_L3_03", - }); + var materialBarcode = $"2026050700000{i + 1}"; + var palletBarcode = $"PALLET{i + 1:D2}"; - var res = _service.SaveTask(new SaveTaskDto() - { - taskCode = info.data.taskCode, - taskQueue = info.data.taskQueue, - taskDetails = info.data.taskDetails, - }); + var info = _service.CreateTask(new CreateTaskDto() + { + materialCode = "20260507000001", + materialBarcode = materialBarcode, + palletBarcode = palletBarcode, + amount = 1, + startPoint = "13#_L1_01", + endPoint = "15#_L3_03", + taskCategory = TaskCategoryEnum.Material, + taskType = TaskTypeEnum.InStore + }); + _service.SaveTask(new SaveTaskDto() + { + taskCode = info.data.taskCode, + taskQueue = info.data.taskQueue, + taskDetails = info.data.taskDetails, + }); + + Console.WriteLine($"[MaterialInStoreTest] 第 {i + 1} 条任务创建完成: {info.data.taskCode}"); + } } } \ No newline at end of file diff --git a/Sln.Wcs/Program.cs b/Sln.Wcs/Program.cs index 042944d..203f000 100644 --- a/Sln.Wcs/Program.cs +++ b/Sln.Wcs/Program.cs @@ -2,10 +2,12 @@ using System.Reflection; using Com.Ctrip.Framework.Apollo; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using NeoSmart.Caching.Sqlite; using Sln.Wcs.Repository; using Sln.Wcs.Serilog; using Sln.Wcs.Plc; +using Sln.Wcs.Strategy; using ZiggyCreatures.Caching.Fusion; using ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson; @@ -28,6 +30,13 @@ namespace Sln.Wcs log.Info($"系统启动成功,日志存放位置:{config["logPath"]}"); + // MaterialInStoreTest? service = serviceProvider.GetService(); + // service?.Run(); + + var service = serviceProvider.GetService(); + service.Run(); + + Task.Delay(-1).Wait(); } private static void ConfigureServices(IServiceCollection services) @@ -46,6 +55,7 @@ namespace Sln.Wcs Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HoistSdk.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Plc.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Business.dll")), + Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Strategy.dll")), }; services.Scan(scan => scan.FromAssemblies(assemblies) @@ -55,6 +65,8 @@ namespace Sln.Wcs .WithTransientLifetime()); services.AddSingleton(typeof(SerilogHelper)); + + services.AddSingleton(typeof(MaterialInStoreTest)); services.AddSqlSugarSetup(); diff --git a/Sln.Wcs/Sln.Wcs.csproj b/Sln.Wcs/Sln.Wcs.csproj index f049ba9..b6568e1 100644 --- a/Sln.Wcs/Sln.Wcs.csproj +++ b/Sln.Wcs/Sln.Wcs.csproj @@ -35,6 +35,7 @@ + -- 2.38.5 From 5be020c3e6d8194bf2f5f29e99f4d4ac6eff22a2 Mon Sep 17 00:00:00 2001 From: WenJY Date: Thu, 21 May 2026 15:42:22 +0800 Subject: [PATCH 3/3] =?UTF-8?q?change=20-=20=E6=B5=B7=E5=BA=B7=20AGVS=20?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=B7=E6=B1=82=E5=A4=B4=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E3=80=81=E7=A6=81=E7=94=A8=20SSL=20=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/Impl/HikRoBotService.cs | 21 +- Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs | 39 ++- .../GenAgvSchedulingTaskDto.cs | 256 +++++++++--------- .../GenAgvSchedulingTaskResultDto.cs | 11 +- Sln.Wcs.HikRoBotSdk/HIkRoBotSdk.cs | 10 +- Sln.Wcs/Program.cs | 20 +- 6 files changed, 209 insertions(+), 148 deletions(-) diff --git a/Sln.Wcs.HikRoBotApi/Service/Impl/HikRoBotService.cs b/Sln.Wcs.HikRoBotApi/Service/Impl/HikRoBotService.cs index ecdd3d2..7ddd699 100644 --- a/Sln.Wcs.HikRoBotApi/Service/Impl/HikRoBotService.cs +++ b/Sln.Wcs.HikRoBotApi/Service/Impl/HikRoBotService.cs @@ -1,6 +1,5 @@ using Sln.Wcs.HikRoBotApi.Domain.Dto.CancelTask; using Sln.Wcs.HikRoBotApi.Domain.Dto.ContinueTask; -using Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask; using Sln.Wcs.HikRoBotApi.Enum; using Sln.Wcs.HikRoBotApi.Util; using Sln.Wcs.HikRoBotSdk; @@ -10,6 +9,9 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; +using Sln.Wcs.HikRoBotSdk.Dto.GenAgvSchedulingTask; +using GenAgvSchedulingTaskDto = Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask.GenAgvSchedulingTaskDto; +using GenAgvSchedulingTaskResultDto = Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask.GenAgvSchedulingTaskResultDto; #region << 版 本 注 释 >> /*-------------------------------------------------------------------- @@ -65,10 +67,19 @@ namespace Sln.Wcs.HikRoBotApi.Service.Impl throw new ArgumentException($"输入参数为空。"); } + // var data = new HikRoBotSdk.Dto.GenAgvSchedulingTask.GenAgvSchedulingTaskDto() + // { + // reqCode = genAgvSchedulingTask.reqCode, + // taskTyp = genAgvSchedulingTask.taskTyp, + // }; var data = new HikRoBotSdk.Dto.GenAgvSchedulingTask.GenAgvSchedulingTaskDto() { - reqCode = genAgvSchedulingTask.reqCode, - taskTyp = genAgvSchedulingTask.taskTyp, + taskType = "PF-FMR-COMMON", + targetRoutes = new List() + { + new targetRoute(){type = "STORAGE",code = "R5001A02011"}, + new targetRoute(){type = "STORAGE",code = "R5001A01011"} + } }; var resp = this.hikRoBotSdk.GenAgvSchedulingTask(data); @@ -83,8 +94,8 @@ namespace Sln.Wcs.HikRoBotApi.Service.Impl { code = resp.code, message = resp.message, - reqCode = resp.reqCode, - data = resp.data + //reqCode = resp.reqCode, + //data = resp.data }, }; diff --git a/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs b/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs index dcb8fa4..0e43bed 100644 --- a/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs +++ b/Sln.Wcs.HikRoBotSdk/Config/HikRoBotConfig.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Flurl.Http; #region << 版 本 注 释 >> /*-------------------------------------------------------------------- @@ -32,11 +33,10 @@ namespace Sln.Wcs.HikRoBotSdk.Config public class HikRoBotConfig { public readonly string api = ""; - public readonly string partnerId; - public readonly string accesskey; - public readonly string secretkey; - public readonly string version; - public readonly string test; + public readonly string contentType = ""; + public readonly string userAgent=""; + public readonly string xlrRequestId="";//随机生成 + public readonly string xlrVersion=""; /// /// 注入海康 SDK 配置参数 @@ -45,15 +45,26 @@ namespace Sln.Wcs.HikRoBotSdk.Config /// IConfiguration configuration public HikRoBotConfig(IConfiguration configuration) { - // if (string.IsNullOrEmpty(configuration["sdk_api"])) - // { - // throw new Exception("sdk_api 配置不正确,请检查Apollo配置."); - // } - // if (string.IsNullOrEmpty(configuration["sdk_json_str"])) - // { - // throw new Exception("sdk_partner_id 配置不正确,请检查Apollo配置."); - // } - // api = configuration["sdk_json_str"]; + if (string.IsNullOrEmpty(configuration["HikRoBot_Url"])) + { + throw new Exception("HikRoBot_Url 配置不正确,请检查Apollo配置."); + } + if (string.IsNullOrEmpty(configuration["HikRoBot_Content-Type"])) + { + throw new Exception("HikRoBot_Content-Type 配置不正确,请检查Apollo配置."); + } + if (string.IsNullOrEmpty(configuration["HikRoBot_User-Agent"])) + { + throw new Exception("HikRoBot_User-Agent 配置不正确,请检查Apollo配置."); + } + if (string.IsNullOrEmpty(configuration["HikRoBot_X-lr-version"])) + { + throw new Exception("HikRoBot_X-lr-version 配置不正确,请检查Apollo配置."); + } + api = configuration["HikRoBot_Url"]; + contentType = configuration["HikRoBot_ContentType"]; + userAgent = configuration["HikRoBot_User-Agent"]; + xlrVersion = configuration["HikRoBot_X-lr-version"]; } } diff --git a/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskDto.cs b/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskDto.cs index 0113ea8..4b3f7a1 100644 --- a/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskDto.cs +++ b/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskDto.cs @@ -30,129 +30,139 @@ namespace Sln.Wcs.HikRoBotSdk.Dto.GenAgvSchedulingTask { public class GenAgvSchedulingTaskDto { - //这里写请求参数 - /// - /// 请求编号,每个请求都要一个唯一编号, 同一个请求重复提交, 使用同一编号。; - /// - public string reqCode { get; set; } + + public string taskType{get;set;} + + public List targetRoutes{get;set;} + + // /// + // /// 请求编号,每个请求都要一个唯一编号, 同一个请求重复提交, 使用同一编号。; + // /// + // public string reqCode { get; set; } + // + // /// + // /// 请求时间截 格式: “yyyy-MM-dd HH:mm:ss”。 + // /// + // public string reqTime { get; set; } + // + // /// + // /// 客户端编号,如PDA,HCWMS等。 + // /// + // public string clientCode { get; set; } + // + // /// + // /// 令牌号, 由调度系统颁发 + // /// + // public string tokenCode { get; set; } + // + // /// + // /// 任务类型, + // /// 业务流程 + // /// 5层柜体来料验收拆分 柜体物料 提升机输送线对接位-验收拆分区 WMS F501 2 + // /// 5层柜体来料入库 柜体物料 验收拆分区-原材料周转区 WMS F502 2 + // /// 5层辅料立体库物料入库 辅料料箱 回转输送线回库口-辅料库货架 WMS F503 1 + // /// 5层辅料立体库分拣出库 辅料料箱 辅料库货架-回转输送线出库口 WMS F504 1 + // /// 5层辅料立体库分拣回库 辅料料箱 回转输送线回库口-辅料库货架 WMS F505 1 + // /// 5层辅料配送流程 辅料料箱 物料分拣位-装配区领料工位 WMS F506 空值 + // /// 5层背板安装区物料配送 柜体物料 原材料周转区-背板安装区 WMS F507 2 + // /// 5层半成品下线 半成品柜 背板安装区-半成品周转区 WMS F508 2 + // /// 5层半成品检验 半成品柜 半成品周转区-检测台 WMS F509 2 + // /// 5层成品柜体入库 成品柜体 检验台-成品区 WMS F510 2 + // /// 5层成品柜体出库 成品柜体 成品区-提升机输送线对接点 WMS F511 2 + // /// + // public string taskTyp { get; set; } + // + // /// + // /// 容器类型(叉车/CTU专用)叉车项目必传 + // /// + // public string ctnrTyp { get; set; } + // + // /// + // /// 容器编号(叉车/CTU专用) + // /// + // public string ctnrCode { get; set; } + // + // /// + // /// 容器数量(叉车堆叠专用),默认值1,仅记录堆叠的数量不记录堆叠的每个容器号 + // /// + // public string ctnrNum { get; set; } + // + // /// + // /// 任务模式 0-普通move 1-出库move 2-入库move 3-移库move + // /// + // public string taskMode { get; set; } + // + // /// + // /// 工作位,一般为机台或工作台位置,与RCS-2000端配置的位置名称一致, 工作位名称为字母\数字\或组合, 不超过32位。 + // /// + // public string wbCode { get; set; } + // + // /// + // /// 位置路径:AGV关键路径位置集合,与任务类型中模板配置的位置路径一一对应。待现场地图部署、配置完成后可获取。 + // /// + // public List positionCodePath { get; set; } + // + // /// + // /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 + // /// + // public string podDir { get; set; } + // + // /// + // /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 + // /// + // public string podTyp { get; set; } + // + // /// + // /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 + // /// + // public string podCode { get; set; } + // + // /// + // /// 物料批次或货架上的物料唯一编码, + // /// + // public string materialLot { get; set; } + // + // /// + // /// 物料类型, 仅移载机器人协议专用必填, 其它车型任务不填 + // /// + // public string materialType { get; set; } + // + // /// + // /// 优先级,从(1~127)级,最大优先级最高。为空时,采用任务模板的优先级。 + // /// + // public string priority { get; set; } + // + // /// + // /// 任务单号,选填, 不填系统自动生成,UUID小于等于64位 + // /// + // public string taskCode { get; set; } + // + // /// + // /// AGV编号,填写表示指定某一编号的AGV执行该任务 + // /// + // public string agvCode { get; set; } + // + // /// + // /// 组编号 + // /// + // public string groupId { get; set; } + // + // /// + // /// 设备类型 + // /// + // public string agvTyp { get; set; } + // + // /// + // /// 区域/策略中挑选货架以及根据物料批次挑选货架时的先进先出规则 + // /// + // public string positionSelStrategy { get; set; } + // + // public string data { get; set; } + } - /// - /// 请求时间截 格式: “yyyy-MM-dd HH:mm:ss”。 - /// - public string reqTime { get; set; } - - /// - /// 客户端编号,如PDA,HCWMS等。 - /// - public string clientCode { get; set; } - - /// - /// 令牌号, 由调度系统颁发 - /// - public string tokenCode { get; set; } - - /// - /// 任务类型, - /// 业务流程 - /// 5层柜体来料验收拆分 柜体物料 提升机输送线对接位-验收拆分区 WMS F501 2 - /// 5层柜体来料入库 柜体物料 验收拆分区-原材料周转区 WMS F502 2 - /// 5层辅料立体库物料入库 辅料料箱 回转输送线回库口-辅料库货架 WMS F503 1 - /// 5层辅料立体库分拣出库 辅料料箱 辅料库货架-回转输送线出库口 WMS F504 1 - /// 5层辅料立体库分拣回库 辅料料箱 回转输送线回库口-辅料库货架 WMS F505 1 - /// 5层辅料配送流程 辅料料箱 物料分拣位-装配区领料工位 WMS F506 空值 - /// 5层背板安装区物料配送 柜体物料 原材料周转区-背板安装区 WMS F507 2 - /// 5层半成品下线 半成品柜 背板安装区-半成品周转区 WMS F508 2 - /// 5层半成品检验 半成品柜 半成品周转区-检测台 WMS F509 2 - /// 5层成品柜体入库 成品柜体 检验台-成品区 WMS F510 2 - /// 5层成品柜体出库 成品柜体 成品区-提升机输送线对接点 WMS F511 2 - /// - public string taskTyp { get; set; } - - /// - /// 容器类型(叉车/CTU专用)叉车项目必传 - /// - public string ctnrTyp { get; set; } - - /// - /// 容器编号(叉车/CTU专用) - /// - public string ctnrCode { get; set; } - - /// - /// 容器数量(叉车堆叠专用),默认值1,仅记录堆叠的数量不记录堆叠的每个容器号 - /// - public string ctnrNum { get; set; } - - /// - /// 任务模式 0-普通move 1-出库move 2-入库move 3-移库move - /// - public string taskMode { get; set; } - - /// - /// 工作位,一般为机台或工作台位置,与RCS-2000端配置的位置名称一致, 工作位名称为字母\数字\或组合, 不超过32位。 - /// - public string wbCode { get; set; } - - /// - /// 位置路径:AGV关键路径位置集合,与任务类型中模板配置的位置路径一一对应。待现场地图部署、配置完成后可获取。 - /// - public List positionCodePath { get; set; } - - /// - /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 - /// - public string podDir { get; set; } - - /// - /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 - /// - public string podTyp { get; set; } - - /// - /// “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下” ,不指定方向可以为空 - /// - public string podCode { get; set; } - - /// - /// 物料批次或货架上的物料唯一编码, - /// - public string materialLot { get; set; } - - /// - /// 物料类型, 仅移载机器人协议专用必填, 其它车型任务不填 - /// - public string materialType { get; set; } - - /// - /// 优先级,从(1~127)级,最大优先级最高。为空时,采用任务模板的优先级。 - /// - public string priority { get; set; } - - /// - /// 任务单号,选填, 不填系统自动生成,UUID小于等于64位 - /// - public string taskCode { get; set; } - - /// - /// AGV编号,填写表示指定某一编号的AGV执行该任务 - /// - public string agvCode { get; set; } - - /// - /// 组编号 - /// - public string groupId { get; set; } - - /// - /// 设备类型 - /// - public string agvTyp { get; set; } - - /// - /// 区域/策略中挑选货架以及根据物料批次挑选货架时的先进先出规则 - /// - public string positionSelStrategy { get; set; } - - public string data { get; set; } + public class targetRoute + { + public string type{get;set;} + public string code{get;set;} } } diff --git a/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskResultDto.cs b/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskResultDto.cs index d386294..6fbc3c6 100644 --- a/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskResultDto.cs +++ b/Sln.Wcs.HikRoBotSdk/Dto/GenAgvSchedulingTask/GenAgvSchedulingTaskResultDto.cs @@ -43,14 +43,21 @@ namespace Sln.Wcs.HikRoBotSdk.Dto.GenAgvSchedulingTask /// public string message { get; set; } + public data data { get; set; } + /// /// 请求编号 /// - public string reqCode { get; set; } + public string errorCode { get; set; } /// /// 自定义返回(返回任务单号) /// - public string data { get; set; } + public bool success { get; set; } + } + + public class data + { + public string robotTaskCode { get; set; } } } diff --git a/Sln.Wcs.HikRoBotSdk/HIkRoBotSdk.cs b/Sln.Wcs.HikRoBotSdk/HIkRoBotSdk.cs index 31ceae6..88d636a 100644 --- a/Sln.Wcs.HikRoBotSdk/HIkRoBotSdk.cs +++ b/Sln.Wcs.HikRoBotSdk/HIkRoBotSdk.cs @@ -7,6 +7,7 @@ using Sln.Wcs.HikRoBotSdk.Dto.GenAgvSchedulingTask; using System; using System.Collections.Generic; using System.Linq; +using System.Security.Authentication; using System.Text; using System.Threading.Tasks; @@ -55,10 +56,15 @@ namespace Sln.Wcs.HikRoBotSdk /// public GenAgvSchedulingTaskResultDto GenAgvSchedulingTask(GenAgvSchedulingTaskDto genAgvSchedulingTask) { - + string url = $"{hikRoBotConfig.api}/task/submit"; + var request = url + .WithHeader("Content-Type", hikRoBotConfig.contentType) + .WithHeader("User-Agent",hikRoBotConfig.userAgent) + .WithHeader("X-lr-request-id", System.Guid.NewGuid().ToString("N")) + .WithHeader("X-lr-version", hikRoBotConfig.xlrVersion); Console.WriteLine($"请求报文:{JsonConvert.SerializeObject(genAgvSchedulingTask)}"); - return this.hikRoBotConfig.api.PostJsonAsync(genAgvSchedulingTask).Result.GetJsonAsync().Result; + return request.PostJsonAsync(genAgvSchedulingTask).Result.GetJsonAsync().Result; } /// diff --git a/Sln.Wcs/Program.cs b/Sln.Wcs/Program.cs index 203f000..6050bfb 100644 --- a/Sln.Wcs/Program.cs +++ b/Sln.Wcs/Program.cs @@ -1,9 +1,13 @@ using System.Reflection; using Com.Ctrip.Framework.Apollo; +using Flurl.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NeoSmart.Caching.Sqlite; +using Sln.Wcs.HikRoBotApi.Domain.Dto.GenAgvSchedulingTask; +using Sln.Wcs.HikRoBotApi.Service; +using Sln.Wcs.HikRoBotApi.Service.Impl; using Sln.Wcs.Repository; using Sln.Wcs.Serilog; using Sln.Wcs.Plc; @@ -18,6 +22,11 @@ namespace Sln.Wcs static async Task Main(string[] args) { + TimeZoneInfo chinaZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"); + DateTimeOffset utcNow = DateTimeOffset.UtcNow; + DateTimeOffset beijingTime = TimeZoneInfo.ConvertTime(utcNow, chinaZone); + string beijingTimeString = beijingTime.ToString("yyyy-MM-dd HH:mm"); + Console.WriteLine(beijingTimeString); var services = new ServiceCollection(); ConfigureServices(services); @@ -32,9 +41,16 @@ namespace Sln.Wcs // MaterialInStoreTest? service = serviceProvider.GetService(); // service?.Run(); + + //禁用 SSL + FlurlHttp.ConfigureClientForUrl("https://172.16.12.11") + .ConfigureInnerHandler(handler => + { + handler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true; + }); - var service = serviceProvider.GetService(); - service.Run(); + // var service = serviceProvider.GetService(); + // var res = service.GetGenAgvSchedulingTask(new GenAgvSchedulingTaskDto()); Task.Delay(-1).Wait(); } -- 2.38.5