diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsInstockD.cs b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsInstockD.cs index 09dd88fc..a1e08fec 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsInstockD.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr.Entities/Entity/WmsInstockD.cs @@ -17,22 +17,17 @@ public partial class WmsInstockD : BaseEntity /// /// 所属组织ID /// - public string org_id { get; set; } = string.Empty; + public string? org_id { get; set; } /// /// 入库单ID /// public string bill_id { get; set; } = string.Empty; - /// - /// 行号 - /// - public int bill_line { get; set; } - /// /// 执行状态 /// - public int line_status { get; set; } + public string line_status { get; set; } = string.Empty; /// /// 物品ID @@ -52,7 +47,7 @@ public partial class WmsInstockD : BaseEntity /// /// 单位代码 /// - public string unit_code { get; set; } = string.Empty; + public string? unit_code { get; set; } /// /// 入库需求数量 @@ -67,12 +62,12 @@ public partial class WmsInstockD : BaseEntity /// /// 原因 /// - public string reason { get; set; } = string.Empty; + public string? reason { get; set; } /// /// 入库仓库ID /// - public string warehouse_id { get; set; } = string.Empty; + public string? warehouse_id { get; set; } /// /// 不含税单价 @@ -162,12 +157,12 @@ public partial class WmsInstockD : BaseEntity /// /// 创建用户 /// - public string create_id { get; set; } = string.Empty; + public string? create_id { get; set; } /// /// 创建时间 /// - public DateTime create_time { get; set; } = DateTime.Now; + public DateTime? create_time { get; set; } /// /// 修改用户 @@ -184,4 +179,9 @@ public partial class WmsInstockD : BaseEntity /// public string? code_batch { get; set; } + /// + /// 打印模板ID + /// + public string? print_id { get; set; } + } diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCollocationSchemeSevice.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCollocationSchemeSevice.cs new file mode 100644 index 00000000..372cf65d --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsCollocationSchemeSevice.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Interfaces +{ + /// + /// 齐套搭配方案服务接口 + /// + public interface IWmsCollocationSchemeSevice + { + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsInStockService.cs b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsInStockService.cs new file mode 100644 index 00000000..1f4f080a --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr.Interfaces/IWmsInStockService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.WarehouseMgr.Interfaces +{ + /// + /// 入库申请服务接口 + /// + public interface IWmsInStockService + { + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr/BaseService.cs b/WarehouseMgr/Tnb.WarehouseMgr/BaseService.cs new file mode 100644 index 00000000..62cc06af --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/BaseService.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Aspose.Cells.Drawing; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.VisualDev; +using Microsoft.AspNetCore.Mvc; + +namespace Tnb.WarehouseMgr +{ + [ApiDescriptionSettings(Tag = ModuleConsts.Tag, Area = ModuleConsts.Area, Order = 700)] + [Route("api/[area]/[controller]/[action]")] + public class BaseService : IOverideVisualDevService, IDynamicApiController, ITransient + { + public OverideVisualDevFunc OverideFuncs { get; } = new OverideVisualDevFunc(); + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs index 6a92fb54..9683dd70 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WareHouseService.cs @@ -7,10 +7,16 @@ using Aspose.Cells.Drawing; using JNPF.Common.Extension; using JNPF.DependencyInjection; using JNPF.DynamicApiController; +using JNPF.Extras.CollectiveOAuth.Config; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; +using NPOI.OpenXmlFormats.Wordprocessing; +using Polly.Timeout; +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.Interfaces; @@ -54,7 +60,7 @@ namespace Tnb.WarehouseMgr 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, @@ -159,5 +165,90 @@ namespace Tnb.WarehouseMgr .ToListAsync(); return items; } + /// + /// 路径算法 + /// + /// + /// + /// + [HttpGet] + public async Task PathAlgorithms(string pStartId, string pEndId) + { + var roads = await _db.Queryable().ToListAsync(); + await LocPathCalcAlgorithms(pStartId, pEndId, roads); + } + private async Task LocPathCalcAlgorithms(string pStartId, string pEndId, List roads) + { + var points = await _db.Queryable().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); + 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 vertexs = new() { startObj }; + pG.CalcDijkstra(sIndex, prev, dist); + var pointIds = points.Select(p => p.id).ToList(); + List result = new(); + GetPoints(pointIds, prev, result, eIndex); + var shortestPathPoints = points.FindAll(x => result.Contains(x.id)); + shortestPathPoints.Add(points.Find(x => x.id == pStartId)); + List results = new() { startObj }; + var isVisited = shortestPathPoints.ToDictionary(x => x.id, x => false); + isVisited[pStartId] = true; + MatchPoint(results, roads, shortestPathPoints, isVisited, pStartId, pEndId); + results.Add(endObj); + string str = null; + } + /// + /// 获取匹配的最短路径节点 + /// + /// + /// + /// + /// + /// + /// + private void MatchPoint(List results, List roads, List shortestPathPoints, Dictionary 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); + } + } + } + /// + /// 根据终止节点获取最短路径顶点 + /// + /// + /// + /// + /// + private static void GetPoints(List pointIds, int[] prev, List result, int eIdx) + { + var index = eIdx; + while (index != 0) + { + result.Add(pointIds[index]); + index = prev[index]; + } + } } } diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsCollocationSchemeSevice.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsCollocationSchemeSevice.cs new file mode 100644 index 00000000..606eb09a --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsCollocationSchemeSevice.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Aspose.Cells.Drawing; +using JNPF.Common.Dtos.VisualDev; +using JNPF.Common.Extension; +using JNPF.DependencyInjection; +using JNPF.DynamicApiController; +using JNPF.FriendlyException; +using JNPF.VisualDev; +using JNPF.VisualDev.Entitys; +using JNPF.VisualDev.Interfaces; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.WarehouseMgr.Entities; +using Tnb.WarehouseMgr.Interfaces; + +namespace Tnb.WarehouseMgr +{ + /// + /// 齐套配套方案服务 + /// + [OverideVisualDev(ModuleId)] + public class WmsCollocationSchemeSevice : BaseService, IWmsCollocationSchemeSevice + { + private const string ModuleId = "26167204892965"; + private readonly ISqlSugarClient _db; + private readonly IRunService _runService; + private readonly IVisualDevService _visualDevService; + private readonly ISqlSugarRepository _repository; + + + + public WmsCollocationSchemeSevice( + ISqlSugarRepository repository, + IRunService runService, + IVisualDevService visualDevService + ) + { + _repository = repository; + _db = repository.AsSugarClient(); + _runService = runService; + _visualDevService = visualDevService; + OverideFuncs.CreateAsync = Create; + } + + private async Task Create(VisualDevModelDataCrInput input) + { + string materialCode = ""; + int seq = 0; + + if (input.data.ContainsKey(nameof(WmsCollocationSchemeH.material_code))) + { + materialCode = input.data[nameof(WmsCollocationSchemeH.material_code)]?.ToString(); + } + if (input.data.ContainsKey(nameof(WmsCollocationSchemeH.seq)) && input.data[nameof(WmsCollocationSchemeH.seq)] != null) + { + seq = input.data[nameof(WmsCollocationSchemeH.seq)].ParseToInt(); + } + if (!materialCode.IsNullOrEmpty() && seq > 0) + { + var item = await _repository.GetFirstAsync(it => it.material_code == materialCode && it.seq == seq); + if (item != null) + { + throw new AppFriendlyException($"物料+顺序【{materialCode}{seq}】,在数据库中已存在", 500); + } + } + try + { + VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(ModuleId, true); + await _runService.Create(templateEntity, input); + } + catch (Exception) + { + return Task.FromResult(false); + } + return await Task.FromResult(true); + } + } +} diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsFeedingService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsFeedingService.cs index 8073fd6d..03e99b46 100644 --- a/WarehouseMgr/Tnb.WarehouseMgr/WmsFeedingService.cs +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsFeedingService.cs @@ -18,10 +18,7 @@ namespace Tnb.WarehouseMgr /// /// 投料记录 /// - [ApiDescriptionSettings(Tag = ModuleConsts.Tag, Area = ModuleConsts.Area, Order = 700)] - [Route("api/[area]/[controller]/[action]")] - - public class WmsFeedingService : IWmsFeedingService, IDynamicApiController, ITransient + public class WmsFeedingService : BaseService, IWmsFeedingService { private readonly ISqlSugarClient _db; private static Dictionary dicMaterial = new Dictionary(); diff --git a/WarehouseMgr/Tnb.WarehouseMgr/WmsInStockService.cs b/WarehouseMgr/Tnb.WarehouseMgr/WmsInStockService.cs new file mode 100644 index 00000000..3df9e321 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/WmsInStockService.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.WarehouseMgr.Entities; +using Tnb.WarehouseMgr.Interfaces; + +namespace Tnb.WarehouseMgr +{ + /// + /// 入库申请服务 + /// + public class WmsInStockService : BaseService, IWmsInStockService + { + private readonly ISqlSugarClient _db; + + public WmsInStockService(ISqlSugarRepository repository) + { + _db = repository.AsSugarClient(); + } + /// + /// 根据入库申请单ID获取申请单明细信息 + /// + /// + /// + [HttpGet] + public async Task GetInStockDetailsListById([FromRoute] string billId) + { + var items = await _db.Queryable().Where(it => it.bill_id == billId).ToListAsync(); + return items; + } + } +} diff --git a/common/Tnb.Common/Utils/Dijkstra.cs b/common/Tnb.Common/Utils/Dijkstra.cs new file mode 100644 index 00000000..183f4b13 --- /dev/null +++ b/common/Tnb.Common/Utils/Dijkstra.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JNPF.Common.Contracts; +using NPOI.SS.Formula.Functions; + +namespace Tnb.Common.Utils +{ + /// + /// 迪杰斯特拉(最短路径算法) + /// + public class Dijkstra where T : BaseEntity, new() + { + public static int MAX = int.MaxValue; + + public int mEdgNum; // 边的数量 + public VNode[] mVexs; // 顶点数组 + + /* + * 创建图 + * + * 参数说明: + * vexs -- 顶点数组 + * edges -- 边 + */ + public Dijkstra(string[] vexs, EData[] edges) + { + + // 初始化"顶点数"和"边数" + int vlen = vexs.Length; + int elen = edges.Length; + + // 初始化"顶点" + mVexs = new VNode[vlen]; + for (int i = 0; i < mVexs.Length; i++) + { + mVexs[i] = new VNode(); + mVexs[i].data = vexs[i]; + mVexs[i].firstEdge = null; + } + + // 初始化"边" + mEdgNum = elen; + for (int i = 0; i < elen; i++) + { + // 读取边的起始顶点和结束顶点 + string c1 = edges[i].start; + string c2 = edges[i].end; + int weight = edges[i].weight; + + // 读取边的起始顶点和结束顶点 + int p1 = GetPosition(c1); + int p2 = GetPosition(c2); + // 初始化node1 + ENode node1 = new ENode(); + node1.ivex = p2; + node1.weight = weight; + // 将node1链接到"p1所在链表的末尾" + if (mVexs[p1].firstEdge == null) + mVexs[p1].firstEdge = node1; + else + LinkLast(mVexs[p1].firstEdge, node1); + // 初始化node2 + ENode node2 = new ENode(); + node2.ivex = p1; + node2.weight = weight; + // 将node2链接到"p2所在链表的末尾" + if (mVexs[p2].firstEdge == null) + mVexs[p2].firstEdge = node2; + else + LinkLast(mVexs[p2].firstEdge, node2); + } + } + + /* + * 将node节点链接到list的最后 + */ + private void LinkLast(ENode list, ENode node) + { + ENode p = list; + + while (p.nextEdge != null) + p = p.nextEdge; + p.nextEdge = node; + } + + /* + * 返回ch位置 + */ + private int GetPosition(string ch) + { + for (int i = 0; i < mVexs.Length; i++) + if (mVexs[i].data == ch) + return i; + return -1; + } + + /* + * 获取边的权值;若start和end不是连通的,则返回无穷大。 + */ + private int GetWeight(int start, int end) + { + if (start == end) + return 0; + + ENode node = mVexs[start].firstEdge; + while (node != null) + { + if (end == node.ivex) + return node.weight; + node = node.nextEdge; + } + + return MAX; + } + + /* + * Dijkstra最短路径。 + * 即,统计图中"起点D"到其它各个顶点的最短路径。 + * + * 参数说明: + * vs -- 起始顶点(start vertex)。 + * prev -- 前驱顶点数组。即,prev[i]的值是"起点D"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。 + * dist -- 长度数组。即,dist[i]是"起点D"到"顶点i"的最短路径的长度。 + */ + public void CalcDijkstra(int vs, int[] prev, int[] dist) + { + //List vertexs = new(); //最短路径串联的点位列表 + // flag[i]=true表示"起点D"到"顶点i"的最短路径已成功获取。 + bool[] flag = new bool[mVexs.Length]; + + // 初始化 + for (int i = 0; i < mVexs.Length; i++) + { + flag[i] = false; // 顶点i的最短路径还没获取到。 + prev[i] = 0; // 顶点i的前驱顶点为0。 + dist[i] = GetWeight(vs, i); // 顶点i的最短路径为"起点D"到"顶点i"的权。 + } + + // 对"起点D"自身进行初始化 + flag[vs] = true; + dist[vs] = 0; + + // 遍历mVexs.Length-1次;每次找出一个顶点的最短路径。 + int k = 0; + for (int i = 1; i < mVexs.Length; i++) + { + // 寻找当前最小的路径 + // 即,在未获取最短路径的顶点中,找到离起点D最近的顶点(k)。 + int min = MAX; + for (int j = 0; j < mVexs.Length; j++) + { + if (flag[j] == false && dist[j] < min) + { + min = dist[j]; + k = j; + } + } + // 标记"顶点k"为已经获取到最短路径 + flag[k] = true; + // 更新当前最短路径和前驱顶点 + // 即,更新"未获取最短路径的顶点的最短路径和前驱顶点"。 + for (int j = 0; j < mVexs.Length; j++) + { + int tmp = GetWeight(k, j); + tmp = (tmp == MAX ? MAX : (min + tmp)); // 防止溢出 + if (flag[j] == false && (tmp < dist[j])) + { + dist[j] = tmp; + prev[j] = k; + } + } + } + + // 打印dijkstra最短路径的结果 + //Console.WriteLine("dijkstra({0}): \n", mVexs[vs].data); + //for (int i = 0; i < mVexs.Length; i++) + //{ + // Console.WriteLine("shortest({0}, {1})={2}\n", mVexs[vs].data, mVexs[i].data, dist[i]); + //} + //return vertexs; + } + } + + /// + /// 邻接表中表对应的链表的顶点 + /// + public class ENode + { + public int ivex; // 该边所指向的顶点的位置 + public int weight; // 该边的权 + public ENode nextEdge; // 指向下一条弧的指针 + } + + /// + /// 邻接表中表的顶点 + /// + public class VNode + { + public string data; // 顶点信息 + public ENode firstEdge; // 指向第一条依附该顶点的弧 + } + + /// + /// 边的结构体 + /// + public class EData + { + public string start; // 边的起点 + public string end; // 边的终点 + public int weight; // 边的权重 + + public EData(string start, string end, int weight) + { + this.start = start; + this.end = end; + this.weight = weight; + } + } +}