From 8ecae083b6700f00c74f5bf85eb801e2de85665b Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 14 Jun 2023 17:33:45 +0800 Subject: [PATCH] =?UTF-8?q?WMS=20=E5=BA=93=E6=88=BF=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=EF=BC=8C=E7=94=9F=E6=88=90=E4=BB=BB=E5=8A=A1=EF=BC=8C=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Consts/WmsWareHouseConst.cs | 17 ++ .../Dto/Inputs/TaskExecuteAfterUpInput.cs | 19 ++ .../Dto/Inputs/TaskExecuteUpInput.cs | 24 +++ .../Entity/WmsDistaskH.cs | 26 ++- .../Entity/WmsPretaskH.cs | 4 + .../Entity/WmsPretaskH.part.cs | 17 ++ .../Mapper/Mapper.cs | 8 +- WarehouseMgr/Tnb.WarehouseMgr/Dp.cs | 40 ++-- .../Tnb.WarehouseMgr/WareHouseService.cs | 176 +++++++++++++++++- .../WmsCarryMoveInStockService.cs | 3 +- 10 files changed, 303 insertions(+), 31 deletions(-) create mode 100644 WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteAfterUpInput.cs create mode 100644 WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteUpInput.cs create mode 100644 WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.part.cs diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/WmsWareHouseConst.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/WmsWareHouseConst.cs index 79c77dab..ae6fb528 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/WmsWareHouseConst.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Consts/WmsWareHouseConst.cs @@ -1,4 +1,5 @@ using System; +using System.CodeDom; using System.Collections.Generic; using System.Linq; using System.Text; @@ -22,6 +23,18 @@ namespace Tnb.WarehouseMgr.Entities.Consts /// public const string PRETASK_BILL_STATUS_DXF_ID = "26126822610469"; /// + /// 预任务单据状态-已下发Id + /// + public const string PRETASK_BILL_STATUS_YXF_ID = "26126830290469"; + /// + /// 预任务单据状态-已开始Id + /// + public const string PRETASK_BILL_STATUS_START_ID = "26126834032677"; + /// + /// 任务单据状态-已下达Id + /// + public const string TASK_BILL_STATUS_YXD_ID = "26126853976101"; + /// /// 预任务生成业务类型-载具移入Id /// public const string BIZTYPE_MOVEIN_ID = "26121988909861"; @@ -29,5 +42,9 @@ namespace Tnb.WarehouseMgr.Entities.Consts /// 单据状态-作业中 /// public const string BILLSTATUS_ON_ID = "25065143245845"; + /// + /// 预任务类型-入库TypeId + /// + public const string WMS_PRETASK_INSTOCK_TYPE_ID = "26126748597797"; } } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteAfterUpInput.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteAfterUpInput.cs new file mode 100644 index 00000000..46f82a66 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteAfterUpInput.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Dto.Inputs +{ + /// + /// 任务执行取操作输入参数 + /// + public class TaskExecuteAfterUpInput + { + /// + /// 任务执行Ids + /// + public List DisTaskIds { get; set; } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteUpInput.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteUpInput.cs new file mode 100644 index 00000000..496364b5 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Dto/Inputs/TaskExecuteUpInput.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Entities.Dto.Inputs +{ + /// + /// 任务执行输入参数 + /// + public class TaskExecuteUpInput + { + /// + /// 生成任务Ids + /// + public List disTaskIds { get; set; } + /// + /// 设备Ids + /// + public List EqpIds { get; set; } + + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsDistaskH.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsDistaskH.cs index 7b211f7f..d70bdc54 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsDistaskH.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsDistaskH.cs @@ -92,12 +92,12 @@ public partial class WmsDistaskH : BaseEntity /// /// 预任务申请ID /// - public string pertask_id { get; set; } = string.Empty; + public string pretask_id { get; set; } = string.Empty; /// /// 预任务申请单号 /// - public string pertask_code { get; set; } = string.Empty; + public string pretask_code { get; set; } = string.Empty; /// /// 是否签收 @@ -182,7 +182,7 @@ public partial class WmsDistaskH : BaseEntity /// /// 协议内容 /// - public string agreement { get; set; } = string.Empty; + public string? agreement { get; set; } /// /// 扩展字段 @@ -194,4 +194,24 @@ public partial class WmsDistaskH : BaseEntity /// public DateTime? timestamp { get; set; } + /// + /// 流程任务Id + /// + public string? f_flowtaskid { get; set; } + + /// + /// 流程引擎Id + /// + public string? f_flowid { get; set; } + + /// + /// 起始库位编号 + /// + public string startlocation_code { get; set; } = string.Empty; + + /// + /// 目标库位编号 + /// + public string endlocation_code { get; set; } = string.Empty; + } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.cs index 7e4066e6..c416a809 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.cs @@ -153,5 +153,9 @@ public partial class WmsPretaskH : BaseEntity /// 目标库位编号 /// public string endlocation_code { get; set; } = string.Empty; + /// + /// 优先级 + /// + public int priority { get; set; } = 1; } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.part.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.part.cs new file mode 100644 index 00000000..5136949b --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsPretaskH.part.cs @@ -0,0 +1,17 @@ +using JNPF.Common.Contracts; +using JNPF.Common.Security; +using SqlSugar; + +namespace Tnb.WarehouseMgr.Entities; + +/// +/// 预任务申请主表 +/// +public partial class WmsPretaskH +{ + /// + /// 单次搬运数量 + /// + [SugarColumn(IsIgnore = true)] + public int move_num { get; set; } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Mapper/Mapper.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Mapper/Mapper.cs index 5c372afe..c40a0dc2 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Mapper/Mapper.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Mapper/Mapper.cs @@ -8,11 +8,9 @@ namespace Tnb.WarehouseMgr.Entities.Mapper { public void Register(TypeAdapterConfig config) { - //config.ForType() - // .Map(dest => dest.id, src => src.bill_id); - //config.ForType() - // .Map(dest => dest.id, src => src.bill_id); - + config.ForType() + .Map(dest => dest.pretask_id, src => src.id) + .Map(dest => dest.pretask_code, src => src.bill_code); } } } \ No newline at end of file diff --git a/WarehouseMgr/Tnb.WarehouseMgr/Dp.cs b/WarehouseMgr/Tnb.WarehouseMgr/Dp.cs index 563c7590..245a7fc0 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/Dp.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/Dp.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using JNPF.Common.Extension; using JNPF.Templates; using Microsoft.AspNetCore.Mvc; using NPOI.SS.Formula.Functions; @@ -16,9 +17,11 @@ namespace Tnb.WarehouseMgr /// public class Dp { + private HashSet set = new HashSet(); private const int Max = int.MaxValue; private int Min = int.MaxValue; private int Deep = 0; + /// /// 动态规划函数 /// @@ -26,43 +29,46 @@ namespace Tnb.WarehouseMgr /// /// /// - public void DpFunc(List roads, List subRoads, List pointIds, Dictionary isVisited, string sPointId, string ePointId) + public void DpFunc(List roads, List pointIds, Dictionary isVisited, string sPointId, string ePointId, dynamic ArrivedEpoint) { - Deep++; - var sRoads = roads.FindAll(x => x.startpoint_id == sPointId).ToList(); var sRoads_EPointIds = sRoads.Select(x => x.endpoint_id).ToList(); - + if (!isVisited[sPointId]) { - Console.WriteLine($"code={roads.Find(x => x.startpoint_id == sPointId).startpoint_code}"); pointIds.Add(sPointId); + set.Add(roads.Find(x => x.startpoint_id == sPointId).startpoint_code); + isVisited[sPointId] = true; } - var eSubRoads = sRoads.FindAll(x => x.endpoint_id == ePointId); - if (eSubRoads?.Count > 0) + + if (sRoads_EPointIds.Contains(ePointId)) //判断是否到达终点 { + ArrivedEpoint.isArrivedEpoint = true; pointIds.Add(ePointId); - Console.WriteLine($"Deep={Deep}"); foreach (var kvp in isVisited) { isVisited[kvp.Key] = true; } return; } - - subRoads = roads.FindAll(x => sRoads_EPointIds.Contains(x.startpoint_id)).ToList(); - if (subRoads?.Count > 0 && !isVisited[sPointId]) + if (sRoads_EPointIds?.Count > 0) { - isVisited[sPointId] = true; - for (int i = 0; i < subRoads.Count; i++) + var subRoads = roads.FindAll(x => sRoads_EPointIds.Contains(x.startpoint_id) && !isVisited[x.endpoint_id]); + if (subRoads?.Count > 0) { - var sIdx = subRoads[i].startpoint_id; - if (!isVisited[sIdx]) + for (int i = 0; i < subRoads.Count; i++) { - DpFunc(roads, subRoads, pointIds, isVisited, sIdx, ePointId); + var sIdx = subRoads[i].startpoint_id; + if (!isVisited[sIdx]) + { + DpFunc(roads, pointIds, isVisited, sIdx, ePointId, ArrivedEpoint); + } } } - + } + if (!ArrivedEpoint.isArrivedEpoint) + { + pointIds.Remove(sPointId); } } } diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs index df750f22..32f5d28c 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Dynamic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using Aop.Api.Domain; using Aspose.Cells.Drawing; using Dm; using JNPF.Common.Contracts; @@ -15,6 +17,7 @@ using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.Extras.CollectiveOAuth.Config; using JNPF.FriendlyException; +using JNPF.Systems.Entitys.Dto.Module; using JNPF.Systems.Interfaces.System; using Mapster; using Microsoft.AspNetCore.Hosting; @@ -30,6 +33,7 @@ using Tnb.Common.Utils; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; +using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; @@ -211,6 +215,165 @@ namespace Tnb.WarehouseMgr { return Task.FromResult(true); } + /// + /// 生成任务执行 + /// + /// + [HttpPost] + public async Task GenTaskExecute() + { + //任务链属性处理内部函数 + async Task _taskChainAttrHandle(List items, List areaPreTasks, int moveNum) + { + if (moveNum == 1 || (moveNum > areaPreTasks.Count && areaPreTasks.Count == 1)) + { + items.ForEach(x => + { + x.is_chain = 0; + x.chain_type = "0"; + }); + } + else if ((moveNum > areaPreTasks.Count && areaPreTasks.Count > 1) || moveNum < areaPreTasks.Count) + { + items.ForEach(x => x.is_chain = 1); + items[0].chain_type = "1"; + for (int i = 0; i < items.Count; i++) + { + if (i == 0 || i == items.Count - 1) continue; + items[i].chain_type = "2"; + } + items[items.Count - 1].chain_type = "3"; + } + } + + //获取所有未下发的预任务申请 + var preTasks = await _db.Queryable().InnerJoin((a, b) => a.startlocation_id == b.location_id) + .InnerJoin((a, b, c) => a.area_id == c.id) + .Where(a => a.status == WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID) + .OrderBy(a => new { priority = SqlFunc.Desc(a.priority), a.bill_code }) + .Select((a, b, c) => new WmsPretaskH + { + move_num = c.move_num + }, true) + .ToListAsync(); + if (preTasks.Count > 0) + { + //根据预任务管理区分组,获取到所有分组后的预任务,遍历每个预任务 是否为任务链,通过管理区ID + var preTaskGroups = preTasks.GroupBy(g => g.area_code).ToList(); + List disTasks = new(); + foreach (var itGroup in preTaskGroups) + { + var moveNum = itGroup.First().move_num; + var items = itGroup.Adapt>(); + var areaPreTasks = itGroup.ToList(); + if (moveNum == 1) + { + items.ForEach(x => + { + x.is_chain = 0; + x.chain_type = "0"; + }); + } + else if (moveNum > 1) + { + //搬运数量==预任务数,可以生成任务执行,为任务链 + if (moveNum == areaPreTasks.Count) + { + await _taskChainAttrHandle(items, areaPreTasks, moveNum); + } + else if (moveNum > areaPreTasks.Count && areaPreTasks.Count == 1) //搬运数量>预任务数,且预任务数等于1,不是任务链,预任务数据平替到任务执行 + { + await _taskChainAttrHandle(items, areaPreTasks, moveNum); + } + else if (moveNum > areaPreTasks.Count && areaPreTasks.Count > 1) //搬运数量>预任务数,且预任务数大于1,可以执行时,可以生成任务执行,为任务链 + { + await _taskChainAttrHandle(items, areaPreTasks, moveNum); + } + else if (false) //搬运数量>预任务数,且预任务数大于1,不可以执行时,先空着 + { + } + else if (moveNum < areaPreTasks.Count) //搬运数量<预任务数, 按照预任务先后顺序,生成对应搬运数量的任务组 + { + await _taskChainAttrHandle(items, areaPreTasks, moveNum); + } + } + disTasks.AddRange(items); + } + try + { + await _db.Ado.BeginTranAsync(); + + disTasks.ForEach(x => x.id = SnowflakeIdHelper.NextId()); + var row = await _db.Insertable(disTasks).ExecuteCommandAsync(); + if (row > 0) + { + var preTaskIds = preTasks.Select(x => x.id).ToList(); + row = await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_YXF_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); + } + + await _db.Ado.CommitTranAsync(); + } + catch (Exception) + { + await _db.Ado.RollbackTranAsync(); + } + } + } + /// + /// 任务执行 + /// + /// + /// + [HttpPost] + public async Task TaskExecute(TaskExecuteUpInput input) + { + try + { + await _db.Ado.BeginTranAsync(); + + //更任务执行 + for (int i = 0, cnt = input.disTaskIds.Count; i < cnt; i++) + { + await _db.Updateable().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID, device_id = input.EqpIds[i] }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync(); + } + var preTaskIds = await _db.Queryable().Where(it => input.disTaskIds.Contains(it.id)).Select(it => it.pretask_id).ToListAsync(); + if (preTaskIds.Count > 0) + { + //更预任务申请表状态 + await _db.Updateable().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_START_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync(); + } + + await _db.Ado.CommitTranAsync(); + } + catch (Exception) + { + await _db.Ado.RollbackTranAsync(); + } + } + /// + /// 任务执行取操作返回(后续操作) + /// + /// + [HttpPost] + public async Task TaskExecuteAfter() + { + //更新任务执行表单据状态 + //清空载具库位数据 + //清空起始库位,状态改为空闲、锁定状态,未锁定 + } + /// + /// 任务完成 + /// + /// + [HttpPost] + public async Task TaskComplate() + { + //更新任务执行表,单据状态为 完成 + //更新预任务申请表,单据状态为 已完成 + //更新载具,锁定状态为未锁定,更新载具的库位当前任务的目标库位 + //更新库位信息,使用状态为 使用,锁定状态为未锁定 + //更新业务主表的单据状态 + } /// /// 生成预任务 @@ -255,7 +418,7 @@ namespace Tnb.WarehouseMgr /// /// /// - + [NonAction] public async Task> PathAlgorithms(string pStartId, string pEndId) { var roads = await _db.Queryable().ToListAsync(); @@ -264,18 +427,20 @@ namespace Tnb.WarehouseMgr } #region PrivateMethods + + private bool isArrivedEpoint = false; private async Task> LocPathCalcAlgorithms(string pStartId, string pEndId, List roads) { var points = await _db.Queryable().ToListAsync(); List results = new(); - List subRoads = new(); Dictionary isVisited = roads.Select(x => x.startpoint_id).Distinct().ToDictionary(x => x, x => false); List pointIds = new(); List codes = new(); Dp dp = new(); - - dp.DpFunc(roads, subRoads, pointIds, isVisited, pStartId, pEndId); + dynamic obj = new ExpandoObject(); + obj.isArrivedEpoint = false; + dp.DpFunc(roads, pointIds, isVisited, pStartId, pEndId, obj); foreach (var pid in pointIds) { var point = points.Find(x => x.id == pid); @@ -284,6 +449,7 @@ namespace Tnb.WarehouseMgr results.Add(point); } } + return results; #region dijkstra //var points = await _db.Queryable().ToListAsync(); @@ -348,7 +514,7 @@ namespace Tnb.WarehouseMgr //MatchPoint(results, roads, shortestPathPoints, isVisited, pStartId, pEndId); //results.Add(endObj); #endregion - return results; + } /// /// 获取匹配的最短路径节点 diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryMoveInStockService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryMoveInStockService.cs index dd757bfd..105a102e 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryMoveInStockService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsCarryMoveInStockService.cs @@ -100,6 +100,7 @@ namespace Tnb.WarehouseMgr preTask.bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(); preTask.status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID; preTask.biz_type = WmsWareHouseConst.BIZTYPE_MOVEIN_ID; + preTask.task_type = WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID; preTask.carry_id = input.data[nameof(preTask.carry_id)]?.ToString()!; preTask.carry_code = input.data[nameof(preTask.carry_code)]?.ToString()!; preTask.area_id = sPoint?.area_id; @@ -118,7 +119,7 @@ namespace Tnb.WarehouseMgr preTaskUpInput.CarryId = input.data[nameof(WmsCarryD.carry_id)]?.ToString()!; preTaskUpInput.CarryStartLocationId = points.FirstOrDefault().location_id; preTaskUpInput.CarryStartLocationCode = points.FirstOrDefault().location_code; - preTaskUpInput.LocationIds = points.Select(x => x.id).ToList(); + preTaskUpInput.LocationIds = points.Select(x => x.location_id).ToList(); preTaskUpInput.PreTaskRecords = preTasks.Adapt>(); preTaskUpInput.PreTaskRecords.ForEach(x => x.id = SnowflakeIdHelper.NextId()); await _wareHouseService.GenTaskHandleAfter(preTaskUpInput);