Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs

768 lines
35 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
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;
using JNPF.Common.Core.Manager;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Security;
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;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis;
using NPOI.HPSF;
using NPOI.OpenXmlFormats.Wordprocessing;
using Polly.Timeout;
using Senparc.NeuChar.Helpers;
using Senparc.Weixin.Work.AdvancedAPIs.OaDataOpen;
using Spire.Pdf.Widget;
using SqlSugar;
using Tnb.BasicData.Entities;
using Tnb.BasicData.Entities.Enums;
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.Entity;
using Tnb.WarehouseMgr.Entities.Enums;
using Tnb.WarehouseMgr.Interfaces;
namespace Tnb.WarehouseMgr
{
/// <summary>
/// 库房业务类(出入库)
/// </summary>
public class WareHouseService : BaseWareHouseService, IWareHouseService
{
private readonly ISqlSugarClient _db;
private readonly IDictionaryDataService _dictionaryDataService;
private readonly IBillRullService _billRullService;
private readonly IUserManager _userManager;
public WareHouseService(ISqlSugarRepository<WmsInstockH> repository, IDictionaryDataService dictionaryDataService, IBillRullService billRullService, IUserManager userManager)
{
_db = repository.AsSugarClient();
_dictionaryDataService = dictionaryDataService;
_billRullService = billRullService;
_userManager = userManager;
}
/// <summary>
/// 根据载具Id带出库位、仓库信息
/// </summary>
/// <param name="carryId">载具id</param>
/// <remarks>
/// returns:
/// <br/>{
/// <br/> carry_id:载具Id
/// <br/> carry_name:载具名称
/// <br/> location_id:库位Id
/// <br/> location_name:库位名称
/// <br/> warehouse_id:库房Id
/// <br/> warehouse_name库房名称
/// <br/>}
/// </remarks>
[HttpGet]
public async Task<dynamic> GetLocationAndWorkHouseByCarryId([FromRoute] string carryId)
{
var items = await _db.Queryable<WmsCarryH>().LeftJoin<BasLocation>((a, b) => a.location_id == b.id)
.LeftJoin<BasWarehouse>((a, b, c) => b.wh_id == c.id)
.Where(a => a.id == carryId)
.Select((a, b, c) => new
{
carry_id = a.id,
carry_name = a.carry_name,
location_id = b.id,
location_name = b.location_name,
warehouse_id = c.id,
warehouse_name = c.whname,
})
.ToListAsync();
return items ?? Enumerable.Empty<dynamic>();
}
/// <summary>
/// 库房业务,入库、出库申请新增修改功能
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task ApplyFor(InOutStockApplyforUpInput input)
{
if (input == null) throw new ArgumentNullException(nameof(input));
async Task<bool> _updateLocalFunc<TStockD, TStockCode>(InOutStockApplyforUpInput input)
where TStockD : BaseEntity<string>, new()
where TStockCode : BaseEntity<string>, IInOutStockCode, new()
{
var instockD = input.Adapt<TStockD>();
var stockCodes = input.InstockCodes?.Adapt<List<TStockCode>>();
if (stockCodes?.Count > 0)
{
stockCodes.ForEach(x =>
{
if (x.id.IsNullOrWhiteSpace())
{
x.id = SnowflakeIdHelper.NextId();
}
x.bill_d_id = instockD.id;
});
}
return await Update(instockD, stockCodes!);
}
var isOk = input.inoutStockType switch
{
EnumInOutStockType.In => await _updateLocalFunc<WmsInstockD, WmsInstockCode>(input),
EnumInOutStockType.Out => await _updateLocalFunc<WmsOutstockD, WmsOutstockCode>(input),
_ => throw new ArgumentOutOfRangeException(nameof(input.inoutStockType), $"Not expected EnumInOutStockType value: {input.inoutStockType}"),
};
if (!isOk) throw Oops.Oh(ErrorCode.COM1001);
}
/// <summary>
/// 根据明细Id获取出入库明细信息
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<dynamic?> GetInOutStockCodesById([FromQuery] InOutStockDetailQuery input)
{
dynamic? result = input.inoutStockType switch
{
EnumInOutStockType.In => await FetchInOutStockCodesById<WmsInstockD, InStockDetailOutput, WmsInstockCode>(input.bill_d_id),
EnumInOutStockType.Out => await FetchInOutStockCodesById<WmsOutstockD, OutStockDetailOutput, WmsOutstockCode>(input.bill_d_id),
_ => throw new ArgumentOutOfRangeException(nameof(input.inoutStockType), $"Not expected EnumInOutStockType value: {input.inoutStockType}"),
};
return result ?? Enumerable.Empty<dynamic>();
}
/// <summary>
/// 入库策略
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<List<BasLocation>> InStockStrategy([FromQuery] InStockStrategyQuery input)
{
var items = new List<BasLocation>();
try
{
items = await _db.Queryable<BasLocation>().Where(it => it.wh_id == input.warehouse_id && it.is_lock == 0 && it.is_type == "0" && it.is_use == ((int)EnumCarryStatus.).ToString()).OrderBy(it => new { it.layers, it.loc_line, it.loc_column }, OrderByType.Asc).ToListAsync();
}
catch (Exception)
{
throw;
}
return items.Take(input.Size).ToList();
}
/// <summary>
/// 出库策略
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<dynamic> OutStockStrategy()
{
return await Task.FromResult<dynamic>(true);
}
/// <summary>
/// 生成任务执行
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task GenTaskExecute()
{
//获取所有未下发的预任务申请
var preTasks = await _db.Queryable<WmsPretaskH>().InnerJoin<WmsCarryH>((a, b) => a.startlocation_id == b.location_id && a.carry_id == b.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();
var ids = preTasks.Select(x => x.id).Distinct().ToList();
var preTaskCodes = await _db.Queryable<WmsPretaskCode>().Where(it => ids.Contains(it.bill_id)).ToListAsync();
if (preTasks.Count > 0)
{
//根据预任务管理区分组,获取到所有分组后的预任务,遍历每个预任务 是否为任务链通过管理区ID
var preTaskGroups = preTasks.GroupBy(g => g.area_code).ToList();
List<WmsDistaskH> disTasks = new();
List<WmsDistaskCode> distaskCodes = new();
foreach (var itGroup in preTaskGroups)
{
var moveNum = itGroup.First().move_num;
var items = itGroup.Adapt<List<WmsDistaskH>>();
for (int i = 0, cnt = items.Count; i < cnt; i++)
{
items[i].id = SnowflakeIdHelper.NextId();
items[i].status = WmsWareHouseConst.TASK_BILL_STATUS_DZX_ID;
}
if (moveNum >= 1)
{
var areaPreTasks = itGroup.ToList();
var groupCode = await _billRullService.GetBillNumber(WmsWareHouseConst.WMS_TASK_EXECUTE_ENCODE);
if (moveNum == 1 || (moveNum > areaPreTasks.Count && areaPreTasks.Count == 1))
{
items.ForEach(x =>
{
x.is_chain = 0;
});
items[0].groups = groupCode;
items[0].bill_code = $"{groupCode}-1";
}
else if ((moveNum >= areaPreTasks.Count && areaPreTasks.Count > 1) || moveNum < areaPreTasks.Count)
{
items.ForEach(x => x.is_chain = 1);
var itemsCount = items.Count;
var mod = items.Count % moveNum > 0 ? itemsCount / moveNum + 1 : itemsCount / moveNum;
var start = 0;
var end = Math.Min(itemsCount, moveNum);
var arrary = items.ToArray();
var dic = new Dictionary<int, WmsDistaskH[]>();
for (int i = 1; i <= mod; i++)
{
while (start < itemsCount)
{
var subArray = arrary[start..end];
dic[i] = subArray;
start = end;
end = Math.Min((end + moveNum), arrary.Length);
}
}
foreach (var (i, v) in dic)
{
foreach (var it in v)
{
it.groups = groupCode;
it.bill_code = $"{groupCode}-{i}";
}
}
}
}
if (preTaskCodes?.Count > 0)
{
foreach (var disTask in items)
{
var curPreTaskCodes = preTaskCodes.FindAll(x => x.bill_id == disTask.pretask_id);
var curDisTaskCodes = curPreTaskCodes.Adapt<List<WmsDistaskCode>>();
curDisTaskCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.bill_id = disTask.id;
x.create_time = DateTime.Now;
});
distaskCodes.AddRange(curDisTaskCodes);
}
}
disTasks.AddRange(items);
}
try
{
await _db.Ado.BeginTranAsync();
//disTasks.ForEach(x => x.id = SnowflakeIdHelper.NextId());
var row = await _db.Insertable(disTasks).ExecuteCommandAsync();
if (preTaskCodes?.Count > 0)
{
row = await _db.Insertable(distaskCodes).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++)
{
if (input.EqpIds?.Count > 0)
{
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();
}
else
{
await _db.Updateable<WmsDistaskH>().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_YXD_ID }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
}
//await _db.Updateable<WmsDistaskH>().SetColumns(it => setColVal).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();
throw;
}
}
/// <summary>
/// 任务执行取操作返回(后续操作)
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task TaskExecuteAfter(TaskExecuteAfterUpInput input)
{
//更新任务执行表单据状态
try
{
await _db.Ado.BeginTranAsync();
await _db.Updateable<WmsDistaskH>().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_RUNING_ID }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
//清空载具库位数据
var carryAndLocIds = await _db.Queryable<WmsDistaskH>().Where(it => input.disTaskIds.Contains(it.id)).Select(it => new { it.carry_id, it.startlocation_id }).ToListAsync();
if (carryAndLocIds?.Count > 0)
{
var carryIds = carryAndLocIds.Select(x => x.carry_id).ToList();
await _db.Updateable<WmsCarryH>().SetColumns(it => new WmsCarryH { location_id = null, location_code = null }).Where(it => carryIds.Contains(it.id)).ExecuteCommandAsync();
}
//更新起始库位,状态改为空闲、锁定状态,未锁定
if (carryAndLocIds?.Count > 0)
{
var startLocationIds = carryAndLocIds.Select(x => x.startlocation_id).ToList();
await _db.Updateable<BasLocation>().SetColumns(it => new BasLocation { is_use = ((int)EnumCarryStatus.).ToString(), is_lock = 0 }).Where(it => startLocationIds.Contains(it.id)).ExecuteCommandAsync();
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
}
}
/// <summary>
/// 任务完成
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task TaskComplate(TaskCompleUpInput input)
{
try
{
await _db.Ado.BeginTranAsync();
//更新任务执行表,单据状态为 完成
await _db.Updateable<WmsDistaskH>().SetColumns(it => new WmsDistaskH { status = WmsWareHouseConst.TASK_BILL_STATUS_COMPLE_ID }).Where(it => input.disTaskIds.Contains(it.id)).ExecuteCommandAsync();
var disTasks = await _db.Queryable<WmsDistaskH>().InnerJoin<WmsCarryH>((a, b) => a.carry_id == b.id).Where(a => input.disTaskIds.Contains(a.id)).Select((a, b) => new WmsDistaskH { carry_status = b.carry_status }, true).ToListAsync();
if (disTasks?.Count > 0)
{
// 更新预任务申请表,单据状态为 已完成
var preTaskIds = disTasks.Select(x => x.pretask_id).ToList();
await _db.Updateable<WmsPretaskH>().SetColumns(it => new WmsPretaskH { status = WmsWareHouseConst.PRETASK_BILL_STATUS_COMPLE_ID }).Where(it => preTaskIds.Contains(it.id)).ExecuteCommandAsync();
//更新电梯任务数量
var eles = await _db.Queryable<WmsElevatorH>().Where(it => disTasks.Select(x => x.area_code).Contains(it.area_code)).ToListAsync();
if (eles?.Count > 0)
await _db.Updateable(eles).ReSetValue(it => it.task_nums--).ExecuteCommandAsync();
//更新载具,锁定状态为未锁定,更新载具的库位当前任务的目标库位
var multiList = disTasks.Select(it => (it.carry_id, it.endlocation_id, it.endlocation_code)).ToList();
for (int i = 0; i < multiList.Count; i++)
{
await _db.Updateable<WmsCarryH>().SetColumns(it => new WmsCarryH { is_lock = 0, location_id = multiList[i].endlocation_id, location_code = multiList[i].endlocation_code }).Where(it => it.id == multiList[i].carry_id).ExecuteCommandAsync();
//更新条码的库位和仓库信息
var carryCodes = await _db.Queryable<WmsCarryCode>().Where(it => it.id == multiList[i].carry_id).ToListAsync();
if (carryCodes?.Count > 0)
{
var loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == multiList[i].endlocation_id);
await _db.Updateable<WmsCarryCode>().SetColumns(it => new WmsCarryCode { warehouse_id = loc.wh_id, location_id = multiList[i].endlocation_id, location_code = multiList[i].endlocation_code }).Where(it => it.id == multiList[i].carry_id).ExecuteCommandAsync();
}
}
//更新库位信息,使用状态为 使用,锁定状态为未锁定
var multis = disTasks.Select(it => (it.endlocation_id, it.carry_status)).ToList();
for (int i = 0; i < multis.Count; i++)
{
var carryStatus = multis[i].carry_status;
if (multis[i].carry_status == ((int)EnumCarryStatus.).ToString())
{
carryStatus = ((int)EnumCarryStatus.).ToString();
}
var cStatus = carryStatus.ParseToInt();
await _db.Updateable<BasLocation>().SetColumns(it => new BasLocation { is_use = cStatus.ToString(), is_lock = 0 }).Where(it => it.id == multis[i].endlocation_id).ExecuteCommandAsync();
}
//更新业务主表的单据状态
foreach (var dt in disTasks)
{
var disTaskCodes = await _db.Queryable<WmsDistaskCode>().Where(it => it.bill_id == dt.id).ToListAsync();
var upInput = new WareHouseUpInput { bizTypeId = dt.biz_type, requireId = dt.require_id!, distaskCodes = disTaskCodes, carryIds = disTasks.Select(x => x.carry_id).ToList() };
upInput.loginType = !_userManager.LoginType.IsNullOrEmpty() ? "app" : "web";
if (dt.is_sign == 1 && dt.chain_type == "3")
{
await DoUpdate(upInput);
}
}
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
/// 出入库策略启用、禁用状态修改
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task ModifyPoliciesStatus(ModifyPoliciesStatusInput input)
{
async Task _updateStatus<T>(ModifyPoliciesStatusInput input) where T : BaseEntity<string>, IUpdatePoliciesStatus, new()
{
T obj = new() { status = input.status };
await _db.Updateable(obj).UpdateColumns(it => it.status).Where(it => input.ids.Contains(it.id)).ExecuteCommandAsync();
}
switch (input.strategyType)
{
case EnumInOutStockType.In:
await _updateStatus<WmsInstockPolicies>(input);
break;
case EnumInOutStockType.Out:
await _updateStatus<WmsOutstockPolicies>(input);
break;
}
}
/// <summary>
/// 生成预任务
/// </summary>
/// <param name="preTasks">预任务集合</param>
/// <param name="preTaskCodes">预任务编码集合</param>
/// <returns></returns>
public async Task<bool> GenPreTask(List<WmsPretaskH> preTasks, List<WmsPretaskCode> preTaskCodes)
{
var grpList = preTasks.OrderBy(o => o.bill_code).GroupBy(g => g.carry_id).ToList();
if (grpList?.Count > 0)
{
foreach (var grp in grpList)
{
var arr = grp.ToArray();
if (arr.Length > 1)
{
var subArr = arr[..^1];
System.Array.ForEach(subArr, a => a.chain_type = "1");
}
}
}
var row = await _db.Insertable(preTasks).ExecuteCommandAsync();
if (preTaskCodes?.Count > 0)
{
row = await _db.Insertable(preTaskCodes).ExecuteCommandAsync();
}
var eleP = preTasks.Find(x => x.area_code.Contains("ELE"));
if (eleP != null)
{
row = await _db.Updateable<WmsElevatorH>().SetColumns(it => it.task_nums == it.task_nums + 1).Where(it => it.area_code == eleP.area_code).ExecuteCommandAsync();
}
return row > 0;
}
/// <summary>
/// 生成预任务后续处理
/// </summary>
/// <returns></returns>
[NonAction]
public async Task GenInStockTaskHandleAfter(GenPreTaskUpInput input, Expression<Func<WmsCarryH, WmsCarryH>> setCarryColumnsExp, Expression<Func<BasLocation, BasLocation>> setLocaionColumbExp)
{
try
{
await _db.Ado.BeginTranAsync();
//根据生成的预任务,插入预任务操作记录
if (input.PreTaskRecord != null)
{
await _db.Insertable(input.PreTaskRecord).ExecuteCommandAsync();
}
if (input.PreTaskHandleCodes.Count > 0)
{
await _db.Insertable(input.PreTaskHandleCodes).ExecuteCommandAsync();
}
//根据载具ID更新是否锁定和赋值起始库位
if (setCarryColumnsExp != null)
{
Expression<Func<WmsCarryH, bool>> whereExp = input.CarryIds?.Count > 0 ? it => input.CarryIds.Contains(it.id) : it => it.id == input.CarryId;
await _db.Updateable<WmsCarryH>().SetColumns(setCarryColumnsExp).Where(whereExp).ExecuteCommandAsync();
}
//根据所有库位更新库位的锁定状态为“锁定”
if (setLocaionColumbExp != null && input.LocationIds?.Count > 0)
{
await _db.Updateable<BasLocation>().SetColumns(setLocaionColumbExp).Where(it => input.LocationIds.Contains(it.id)).ExecuteCommandAsync();
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
/// 路径算法
/// </summary>
/// <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();
var points = await LocPathCalcAlgorithms(pStartId, pEndId, roads);
if (points.FindAll(x => x.location_code != null && x.location_code.Contains("ELE"))?.Count > 0)
{
//查询当前电梯点
var curEleDs = await _db.Queryable<WmsElevatorD>().Where(it => points.Select(x => x.id).Contains(it.point_id)).ToListAsync();
//如果有电梯点,则会进行电梯的均匀分配
if (curEleDs?.Count > 0)
{
//当前电梯
var curEle = await _db.Queryable<WmsElevatorH>().SingleAsync(it => it.id == curEleDs.First().bill_id);
//同电梯组电梯
var sGpEle = await _db.Queryable<WmsElevatorH>().Where(it => it.elevator_group == curEle.elevator_group && it.id != curEle.id).ToListAsync();
//判断电梯组中各电梯任务数
if (sGpEle.FindAll(x => x.task_nums < curEle.task_nums)?.Count > 0)
{
var sGpDs = await _db.Queryable<WmsElevatorD>().Where(it => it.bill_id == sGpEle.First().id).ToListAsync();
if (sGpDs?.Count > 0)
{
var sGpPoints = await _db.Queryable<WmsPointH>().Where(it => sGpDs.Select(x => x.point_id).Contains(it.id)).ToListAsync();
var sFEndId = sGpDs.Single(x => x.floor == curEleDs.First().floor).point_id;
var eFStartId = sGpDs.Single(x => x.floor == curEleDs.Last().floor).point_id;
var sFPoints = await LocPathCalcAlgorithms(pStartId, sFEndId, roads);
List<WmsPointH> elePoints = new();
foreach (var pt in curEleDs)
{
var elePoint = sGpPoints.Find(x => x.floor == pt.floor);
if (elePoint != null)
elePoints.Add(elePoint);
}
var eFPoints = await LocPathCalcAlgorithms(eFStartId, pEndId, roads);
elePoints.Remove(elePoints.First());
elePoints.Remove(elePoints.Last());
points.Clear();
points.AddRange(sFPoints);
points.AddRange(elePoints);
points.AddRange(eFPoints);
}
}
}
}
return points;
}
#region PrivateMethods
private async Task<List<WmsPointH>> LocPathCalcAlgorithms(string pStartId, string pEndId, List<WmsRoad> roads)
{
#region dp
//List<WmsPointH> results = new();
//var points = await _db.Queryable<WmsPointH>().ToListAsync();
//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();
//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);
// if (point != null)
// {
// results.Add(point);
// }
//}
//return results;
#endregion
#region dijkstra
var points = await _db.Queryable<WmsPointH>().ToListAsync();
var startObj = points.Find(x => x.id == pStartId);
var endObj = points.Find(x => x.id == pEndId);
var sIndex = points.IndexOf(startObj);
var eIndex = points.IndexOf(endObj);
if (eIndex < sIndex)
{
var tempIndex = sIndex;
sIndex = eIndex;
eIndex = tempIndex;
var temp = points[sIndex];
points[sIndex] = points[eIndex];
points[eIndex] = temp;
}
var vexs = points.Select(p => p.id).ToArray();
EData[] edges = new EData[roads.Count];
for (int i = 0; i < edges.Length; i++)
{
var start = roads[i].startpoint_id;
var end = roads[i].endpoint_id;
var weight = roads[i].distance;
edges[i] = new EData(start, end, weight);
}
Dijkstra pG = new(vexs, edges);
int[] prev = new int[pG.mVexs.Length];
int[] dist = new int[pG.mVexs.Length];
List<WmsPointH> vertexs = new() { startObj };
pG.CalcDijkstra(sIndex, prev, dist);
var pointIds = points.Select(p => p.id).ToList();
Stack<string> result = new();
GetPoints(pointIds, prev, result, eIndex);
List<WmsPointH> results = new() { startObj };
if (points?.Count > 0)
{
points.Where(it => result.Contains(it.id));
foreach (var i in result)
{
WmsPointH? point = points?.Find(x => x.id == i);
if (point != null)
{
results.Add(point);
}
}
}
return results;
#endregion
}
/// <summary>
/// 获取匹配的最短路径节点
/// </summary>
/// <param name="results"></param>
/// <param name="roads"></param>
/// <param name="shortestPathPoints"></param>
/// <param name="isVisited"></param>
/// <param name="pStartId"></param>
/// <param name="pEndId"></param>
private void MatchPoint(List<WmsPointH> results, List<WmsRoad> roads, List<WmsPointH> shortestPathPoints, Dictionary<string, bool> isVisited, string pStartId, string pEndId)
{
var sRoads = roads.Where(x => x.startpoint_id == pStartId).ToList();
for (int j = 0; j < sRoads.Count; j++)
{
var sPoint = shortestPathPoints.Find(x => x.id == sRoads[j].endpoint_id);
if (sPoint != null && isVisited.ContainsKey(sPoint.id) && !isVisited[sPoint.id] && sPoint.id != pEndId)
{
var code = sPoint.point_code;
results.Add(sPoint);
isVisited[sPoint.id] = true;
MatchPoint(results, roads, shortestPathPoints, isVisited, sPoint.id, pEndId);
}
}
}
/// <summary>
/// 根据终止节点获取最短路径顶点
/// </summary>
/// <param name="pointIds"></param>
/// <param name="prev"></param>
/// <param name="result"></param>
/// <param name="eIdx"></param>
private static void GetPoints(List<string> pointIds, int[] prev, Stack<string> result, int eIdx)
{
var index = eIdx;
while (index != 0)
{
result.Push(pointIds[index]);
index = prev[index];
}
}
private async Task<bool> Update<T1, T2>(T1 entity, List<T2> entities) where T1 : BaseEntity<string>, new() where T2 : BaseEntity<string>, new()
{
var isOk = false;
try
{
await _db.Ado.BeginTranAsync();
isOk = await _db.Updateable(entity).ExecuteCommandHasChangeAsync();
if (entities?.Count > 0)
{
var row = await _db.Storageable(entities).ExecuteCommandAsync();
isOk = row > 0;
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
}
return isOk;
}
/// <summary>
/// 根据明细Id获取出入库明细信息
/// </summary>
/// <typeparam name="TStockD">出入库明细</typeparam>
/// <typeparam name="TOutput">明细输出类</typeparam>
/// <typeparam name="TStockCode">出入库条码</typeparam>
/// <param name="billDId">明细Id</param>
/// <returns></returns>
private async Task<dynamic?> FetchInOutStockCodesById<TStockD, TOutput, TStockCode>(string billDId)
where TStockD : BaseEntity<string>, new()
where TOutput : IInOutStockDetail<TStockCode>, new()
where TStockCode : BaseEntity<string>, IInOutStockCode, new()
{
var dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID);
var data = await _db.Queryable<TStockD>()
.Where(a => a.id == billDId)
.Select(a => new TOutput
{
CodeDetails = SqlFunc.Subqueryable<TStockCode>().Where(it => it.bill_d_id == a.id).ToList(),
}, true)
.Mapper(it => it.line_status = it.line_status != null && dic.ContainsKey(key: it.line_status) ? dic[it.line_status]?.ToString() : "")
.ToListAsync();
return data;
}
#endregion
}
}