WMS 库房业务,生成任务,任务执行

This commit is contained in:
alex
2023-06-14 17:33:45 +08:00
parent edf3f135b1
commit 8ecae083b6
10 changed files with 303 additions and 31 deletions

View File

@@ -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
/// </summary>
public const string PRETASK_BILL_STATUS_DXF_ID = "26126822610469";
/// <summary>
/// 预任务单据状态-已下发Id
/// </summary>
public const string PRETASK_BILL_STATUS_YXF_ID = "26126830290469";
/// <summary>
/// 预任务单据状态-已开始Id
/// </summary>
public const string PRETASK_BILL_STATUS_START_ID = "26126834032677";
/// <summary>
/// 任务单据状态-已下达Id
/// </summary>
public const string TASK_BILL_STATUS_YXD_ID = "26126853976101";
/// <summary>
/// 预任务生成业务类型-载具移入Id
/// </summary>
public const string BIZTYPE_MOVEIN_ID = "26121988909861";
@@ -29,5 +42,9 @@ namespace Tnb.WarehouseMgr.Entities.Consts
/// 单据状态-作业中
/// </summary>
public const string BILLSTATUS_ON_ID = "25065143245845";
/// <summary>
/// 预任务类型-入库TypeId
/// </summary>
public const string WMS_PRETASK_INSTOCK_TYPE_ID = "26126748597797";
}
}

View File

@@ -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
{
/// <summary>
/// 任务执行取操作输入参数
/// </summary>
public class TaskExecuteAfterUpInput
{
/// <summary>
/// 任务执行Ids
/// </summary>
public List<string> DisTaskIds { get; set; }
}
}

View File

@@ -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
{
/// <summary>
/// 任务执行输入参数
/// </summary>
public class TaskExecuteUpInput
{
/// <summary>
/// 生成任务Ids
/// </summary>
public List<string> disTaskIds { get; set; }
/// <summary>
/// 设备Ids
/// </summary>
public List<string> EqpIds { get; set; }
}
}

View File

@@ -92,12 +92,12 @@ public partial class WmsDistaskH : BaseEntity<string>
/// <summary>
/// 预任务申请ID
/// </summary>
public string pertask_id { get; set; } = string.Empty;
public string pretask_id { get; set; } = string.Empty;
/// <summary>
/// 预任务申请单号
/// </summary>
public string pertask_code { get; set; } = string.Empty;
public string pretask_code { get; set; } = string.Empty;
/// <summary>
/// 是否签收
@@ -182,7 +182,7 @@ public partial class WmsDistaskH : BaseEntity<string>
/// <summary>
/// 协议内容
/// </summary>
public string agreement { get; set; } = string.Empty;
public string? agreement { get; set; }
/// <summary>
/// 扩展字段
@@ -194,4 +194,24 @@ public partial class WmsDistaskH : BaseEntity<string>
/// </summary>
public DateTime? timestamp { get; set; }
/// <summary>
/// 流程任务Id
/// </summary>
public string? f_flowtaskid { get; set; }
/// <summary>
/// 流程引擎Id
/// </summary>
public string? f_flowid { get; set; }
/// <summary>
/// 起始库位编号
/// </summary>
public string startlocation_code { get; set; } = string.Empty;
/// <summary>
/// 目标库位编号
/// </summary>
public string endlocation_code { get; set; } = string.Empty;
}

View File

@@ -153,5 +153,9 @@ public partial class WmsPretaskH : BaseEntity<string>
/// 目标库位编号
/// </summary>
public string endlocation_code { get; set; } = string.Empty;
/// <summary>
/// 优先级
/// </summary>
public int priority { get; set; } = 1;
}

View File

@@ -0,0 +1,17 @@
using JNPF.Common.Contracts;
using JNPF.Common.Security;
using SqlSugar;
namespace Tnb.WarehouseMgr.Entities;
/// <summary>
/// 预任务申请主表
/// </summary>
public partial class WmsPretaskH
{
/// <summary>
/// 单次搬运数量
/// </summary>
[SugarColumn(IsIgnore = true)]
public int move_num { get; set; }
}

View File

@@ -8,11 +8,9 @@ namespace Tnb.WarehouseMgr.Entities.Mapper
{
public void Register(TypeAdapterConfig config)
{
//config.ForType<InOutStockApplyforUpInput, WmsInstockD>()
// .Map(dest => dest.id, src => src.bill_id);
//config.ForType<InOutStockApplyforUpInput, WmsOutstockD>()
// .Map(dest => dest.id, src => src.bill_id);
config.ForType<WmsPretaskH, WmsDistaskH>()
.Map(dest => dest.pretask_id, src => src.id)
.Map(dest => dest.pretask_code, src => src.bill_code);
}
}
}

View File

@@ -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
/// </summary>
public class Dp
{
private HashSet<string> set = new HashSet<string>();
private const int Max = int.MaxValue;
private int Min = int.MaxValue;
private int Deep = 0;
/// <summary>
/// 动态规划函数
/// </summary>
@@ -26,43 +29,46 @@ namespace Tnb.WarehouseMgr
/// <param name="sPointId"></param>
/// <param name="ePointId"></param>
/// <returns></returns>
public void DpFunc(List<WmsRoad> roads, List<WmsRoad> subRoads, List<string> pointIds, Dictionary<string, bool> isVisited, string sPointId, string ePointId)
public void DpFunc(List<WmsRoad> roads, List<string> pointIds, Dictionary<string, bool> 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);
}
}
}

View File

@@ -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<dynamic>(true);
}
/// <summary>
/// 生成任务执行
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task GenTaskExecute()
{
//任务链属性处理内部函数
async Task _taskChainAttrHandle(List<WmsDistaskH> items, List<WmsPretaskH> 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<WmsPretaskH>().InnerJoin<WmsCarryH>((a, b) => a.startlocation_id == b.location_id)
.InnerJoin<WmsAreaH>((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<WmsDistaskH> disTasks = new();
foreach (var itGroup in preTaskGroups)
{
var moveNum = itGroup.First().move_num;
var items = itGroup.Adapt<List<WmsDistaskH>>();
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<WmsPretaskH>().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();
}
}
}
/// <summary>
/// 任务执行
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[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<WmsDistaskH>().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<WmsDistaskH>().Where(it => input.disTaskIds.Contains(it.id)).Select(it => it.pretask_id).ToListAsync();
if (preTaskIds.Count > 0)
{
//更预任务申请表状态
await _db.Updateable<WmsPretaskH>().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();
}
}
/// <summary>
/// 任务执行取操作返回(后续操作)
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task TaskExecuteAfter()
{
//更新任务执行表单据状态
//清空载具库位数据
//清空起始库位,状态改为空闲、锁定状态,未锁定
}
/// <summary>
/// 任务完成
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task TaskComplate()
{
//更新任务执行表,单据状态为 完成
//更新预任务申请表,单据状态为 已完成
//更新载具,锁定状态为未锁定,更新载具的库位当前任务的目标库位
//更新库位信息,使用状态为 使用,锁定状态为未锁定
//更新业务主表的单据状态
}
/// <summary>
/// 生成预任务
@@ -255,7 +418,7 @@ namespace Tnb.WarehouseMgr
/// <param name="pStartId"></param>
/// <param name="pEndId"></param>
/// <returns></returns>
[NonAction]
public async Task<List<WmsPointH>> PathAlgorithms(string pStartId, string pEndId)
{
var roads = await _db.Queryable<WmsRoad>().ToListAsync();
@@ -264,18 +427,20 @@ namespace Tnb.WarehouseMgr
}
#region PrivateMethods
private bool isArrivedEpoint = false;
private async Task<List<WmsPointH>> LocPathCalcAlgorithms(string pStartId, string pEndId, List<WmsRoad> roads)
{
var points = await _db.Queryable<WmsPointH>().ToListAsync();
List<WmsPointH> results = new();
List<WmsRoad> subRoads = new();
Dictionary<string, bool> isVisited = roads.Select(x => x.startpoint_id).Distinct().ToDictionary(x => x, x => false);
List<string> pointIds = new();
List<string> 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<WmsPointH>().ToListAsync();
@@ -348,7 +514,7 @@ namespace Tnb.WarehouseMgr
//MatchPoint(results, roads, shortestPathPoints, isVisited, pStartId, pEndId);
//results.Add(endObj);
#endregion
return results;
}
/// <summary>
/// 获取匹配的最短路径节点

View File

@@ -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<List<WmsHandleH>>();
preTaskUpInput.PreTaskRecords.ForEach(x => x.id = SnowflakeIdHelper.NextId());
await _wareHouseService.GenTaskHandleAfter(preTaskUpInput);