diff --git a/backend/BPA.MES.Base.Application/BPA.MES.Base.Application.xml b/backend/BPA.MES.Base.Application/BPA.MES.Base.Application.xml index f70912c..469fbf0 100644 --- a/backend/BPA.MES.Base.Application/BPA.MES.Base.Application.xml +++ b/backend/BPA.MES.Base.Application/BPA.MES.Base.Application.xml @@ -1431,6 +1431,16 @@ 工单状态(信息系统 --> 中控系统) + + + 任务下发成功 回调 + + + + + 上下料回调 + + 名 称 : @@ -1602,6 +1612,196 @@ 主键 + + + 任务完成回报Dto + + + + + 上游系统任务号,全局唯一 + + + + + 仓库编号 + + + + + 任务快仓系统编号 + + + + + + + + + + 内部任务类型 + + + + + 数据字段 + + + + + 上下料交互请求DTO + + + + + AGV编号 + + + + + 容器编号,如果一次上/下多个容器,则多个容器用英文逗号分隔 + + + + + 上游设备ID + + + + + 上游设备ID,多个用英文逗号分隔 + + + + + 快仓任务编号 + + + + + 消息ID + + + + + 交互阶段LOAD:上料阶段 UNLOAD:下料阶段 + + + + + 上游任务号 + + + + + 货到货 + + + + + AGV编号 + + + + + 容器编号 + + + + + 上料点位 + + + + + 上料货位编号 + + + + + 下料点位 + + + + + 下料货位编号 + + + + + 是否需要上料交互 + + + + + 点到点 + + + + + AGV编号 + + + + + 容器编号 + + + + + 上料点位 + + + + + 下料点位 + + + + + 是否需要上料交互 + + + + + 顶升完成 + + + + + 开始移动 + + + + + 放下完成 + + + + + 任务完成 + + + + + 任务取消 + + + + + 任务异常取消 + + + + + 任务异常完成 + + + + + 1) 辊筒货位到货位搬运 + + 名 称 :AGV线路管理 @@ -1662,6 +1862,69 @@ + + + 下发任务 + + + + + + + 取消任务 + + + + + + + + + + + + + + 任务回调 + + + + + + + AGV上下料交互请求 + + + + + + + 下发任务 + + + + + + + 取消任务 + + + + + + + 任务回调 + + + + + + + AGV上下料交互请求 + + + + 名 称 :AGV点位管理 @@ -4496,6 +4759,16 @@ 数量 + + + 成品数量限制 + + + + + 成品 + + 分页列表 @@ -4530,6 +4803,13 @@ + + + 获取成品剩余制作数量 + + + + 分页列表 @@ -4571,6 +4851,19 @@ + + + 生成工单时验证成品数量 + + + + + + 获取成品剩余制作数量 + + + + 名 称 :产品分组 @@ -5574,9 +5867,23 @@ + + + 获取物料统计 + + + + - 获取产品生产统计 + 获取成品生产统计 + + + + + + + 获取物料统计 @@ -5828,6 +6135,16 @@ 工单工艺步骤Id + + + 工单Id + + + + + 锅数 + + 状态 @@ -5931,6 +6248,21 @@ 主键 + + + 工单状态 + + + + + 起始时间 + + + + + 结束时间 + + 分页 @@ -5946,6 +6278,21 @@ 编码 + + + 工单状态 + + + + + 起始时间 + + + + + 结束时间 + + 工单下发 diff --git a/backend/BPA.MES.Base.Application/MQTT/MQTTService.cs b/backend/BPA.MES.Base.Application/MQTT/MQTTService.cs index adfa2c0..cd61c89 100644 --- a/backend/BPA.MES.Base.Application/MQTT/MQTTService.cs +++ b/backend/BPA.MES.Base.Application/MQTT/MQTTService.cs @@ -39,7 +39,6 @@ namespace BPA.MES.Base.Application try { payload.MessageId = messageId; - payload.MessageId = MessageID.WorkOrderIssued; payload.MsgVersion = new Version(1, 0, 0, 0); MsgPackage mp = new MsgPackage(); mp.Message = payload; @@ -68,6 +67,8 @@ namespace BPA.MES.Base.Application } return result; } + + } public class MqttResult diff --git a/backend/BPA.MES.Base.Application/MQTT/MessageID.cs b/backend/BPA.MES.Base.Application/MQTT/MessageID.cs index 9028fcd..e96980f 100644 --- a/backend/BPA.MES.Base.Application/MQTT/MessageID.cs +++ b/backend/BPA.MES.Base.Application/MQTT/MessageID.cs @@ -5,7 +5,10 @@ public const int DevcieControl = 1;//设备控制ID public const int WorkOrderIssued = 2;//工单下发ID public const int DeviceData = 3;//设备上报数据 + public const int TaskState = 4;//AGV任务状态上报 + public const int LoadAndUnload = 8;//AGV上下料上报 public const int PowerId = 12;// 权限验证 public const int StateChange = 13;//状态改变 } } + diff --git a/backend/BPA.MES.Base.Application/MQTT/Topics.cs b/backend/BPA.MES.Base.Application/MQTT/Topics.cs index 91a9d60..5144bdc 100644 --- a/backend/BPA.MES.Base.Application/MQTT/Topics.cs +++ b/backend/BPA.MES.Base.Application/MQTT/Topics.cs @@ -26,6 +26,17 @@ /// 工单状态(信息系统 --> 中控系统) /// public const string STWorkState = "BPAProline/CentralControl/Proline/WorkState"; - + + /// + /// 任务下发成功 回调 + /// + public const string ExecuteReplyTopic = "robotjob.report"; + + /// + /// 上下料回调 + /// + public const string LoadAndUnloadTopic = "rollerjob.upstreamrequest"; + + } } diff --git a/backend/BPA.MES.Base.Application/Services/AGVService/Dtos/AGVThirdPartyDto.cs b/backend/BPA.MES.Base.Application/Services/AGVService/Dtos/AGVThirdPartyDto.cs new file mode 100644 index 0000000..4f6f0ec --- /dev/null +++ b/backend/BPA.MES.Base.Application/Services/AGVService/Dtos/AGVThirdPartyDto.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.MES.Base.Application.Services.AGVService.Dtos +{ + + public class AGVExecuteReplyRequest + { + public AGVExecuteReplyDto Event { get; set; } + } + public class AGVExecuteReplyMQTT: IMessage + { + public AGVExecuteReplyDto Event { get; set; } + public int MessageId { get; set; } + public Version MsgVersion { get; set; } + } + + public class AGVLoadAndUnloadRequest + { + public AGVLoadAndUnloadDto Event { get; set; } + } + + public class AGVLoadAndUnloadMQTT : IMessage + { + public AGVLoadAndUnloadDto Event { get; set; } + public int MessageId { get; set; } + public Version MsgVersion { get; set; } + } + + /// + /// 任务完成回报Dto + /// + public class AGVExecuteReplyDto + { + /// + /// 上游系统任务号,全局唯一 + /// + public string robotJobId { get; set; } + + /// + /// 仓库编号 + /// + public long warehouseId { get; set; } + + /// + /// 任务快仓系统编号 + /// + public string jobId { get; set; } + + /// + /// + /// + public string state { get; set; } + + /// + /// 内部任务类型 + /// + public string jobType { get; set; } + + /// + /// 数据字段 + /// + public PointToPoint jobData { get; set; } + + } + + /// + /// 上下料交互请求DTO + /// + public class AGVLoadAndUnloadDto + { + /// + /// AGV编号 + /// + public string agvCode { get; set; } + + /// + /// 容器编号,如果一次上/下多个容器,则多个容器用英文逗号分隔 + /// + public string containerCode { get; set; } + + /// + /// 上游设备ID + /// + public long equipmentId { get; set; } + + /// + /// 上游设备ID,多个用英文逗号分隔 + /// + public string equipmentIds { get; set; } + + /// + /// 快仓任务编号 + /// + public string jobId { get; set; } + + /// + /// 消息ID + /// + public string msgId { get; set; } + + /// + /// 交互阶段LOAD:上料阶段 UNLOAD:下料阶段 + /// + public string command { get; set; } + + /// + /// 上游任务号 + /// + public string robotJobId { get; set; } + + } + + + /// + /// 货到货 + /// + public class GoodsToGoods + { + /// + /// AGV编号 + /// + public string agvCode { get; set; } + + /// + /// 容器编号 + /// + public string containerCode { get; set; } + + /// + /// 上料点位 + /// + public string startPointCode { get; set; } + + /// + /// 上料货位编号 + /// + public string startSlotCode { get; set; } + + /// + /// 下料点位 + /// + public string targetPointCode { get; set; } + + /// + /// 下料货位编号 + /// + public string targetSlotCode { get; set; } + + /// + /// 是否需要上料交互 + /// + public bool loadInteractive { get; set; } + } + + /// + /// 点到点 + /// + public class PointToPoint + { + /// + /// AGV编号 + /// + public string agvCode { get; set; } + + /// + /// 容器编号 + /// + public string containerCode { get; set; } + + /// + /// 上料点位 + /// + public string startPointCode { get; set; } + + /// + /// 下料点位 + /// + public string targetPointCode { get; set; } + + /// + /// 是否需要上料交互 + /// + public bool loadInteractive { get; set; } + } + + public enum AGVState + { + + //任务状态: + //1)货架/货位/点到点货架搬运任务枚举: + //LIFT_UP_DONE:顶升完成 + //MOVE_BEGIN:开始移动 + //PUT_DOWN_DONE:放下完成 + //DONE:任务完成 + //CANCEL:任务取消 + //ABNORMAL_CANCEL:任务异常取消 + //ABNORMAL_COMPLETED:任务异常完成 + //2)货位到货位/点到点辊筒料箱搬运任务枚举: + //ROLLER_LOAD_DOING:正在上料 + //ROLLER_LOAD_FINISH:上料完成 + //ROLLER_UNLOAD_DOING:正在下料 + //DONE:下料完成 + //ABNORMAL_CANCEL:任务异常取消 + //ABNORMAL_COMPLETED:任务异常完成 + //3)AGV移动任务枚举: + //DONE:任务完成 + //CANCEL:任务取消 + //ABNORMAL_CANCEL:任务异常取消 + //ABNORMAL_COMPLETED:任务异常完成 + //4) 纯料箱任务枚举: + //MOVE_BEGIN:开始移动(仅单插臂或单夹报,2.8.1后) + //ENTER_STATION:到站 + //DONE:任务完成 + //LOAD_COMPLETED:取料完成 + //UNLOAD_COMPLETED:放料完成 + //ABNORMAL_CANCEL:任务异常取消ABNORMAL_COMPLETED:任务异常完成 + //5) 小皮带任务枚举: + //DONE:任务完成 + //6) QuickPick任务枚举: + //ENTER_STATION:到站 + //DONE:任务完成 + //CANCEL:任务取消 + //LEAVE_STATION离站 + //ROLLBACK 回滚(有其他任务,当前任务可不执行) + + + /// + /// 顶升完成 + /// + LIFT_UP_DONE = 1, + + /// + /// 开始移动 + /// + MOVE_BEGIN = 2, + + /// + /// 放下完成 + /// + PUT_DOWN_DONE = 3, + + /// + /// 任务完成 + /// + DONE = 4, + + + /// + /// 任务取消 + /// + CANCEL = 5, + + /// + /// 任务异常取消 + /// + ABNORMAL_CANCEL = 6, + + /// + /// 任务异常完成 + /// + ABNORMAL_COMPLETED = 7 + + } + + public enum jobType + { + /// + /// 1) 辊筒货位到货位搬运 + /// + SLOT_ROLLER_MOVE = 1, + POINT_ROLLER_MOVE=2 + } + +} diff --git a/backend/BPA.MES.Base.Application/Services/AGVService/Services/AGVThirdPartyService.cs b/backend/BPA.MES.Base.Application/Services/AGVService/Services/AGVThirdPartyService.cs new file mode 100644 index 0000000..6662673 --- /dev/null +++ b/backend/BPA.MES.Base.Application/Services/AGVService/Services/AGVThirdPartyService.cs @@ -0,0 +1,124 @@ +using BPA.AGV; +using BPA.MES.Base.Application.Services.AGVService.Dtos; +using MQTTnet.Client; +using MQTTnet.Client.Publishing; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.MES.Base.Application.Services.AGVService.Services +{ + + [AllowAnonymous, NonUnify] + [ApiDescriptionSettings("AGV管理", Name = "AgvThirdParty", Tag = "AGV第三方api", KeepName = true, SplitCamelCase = true, KeepVerb = true)] + public class AGVThirdPartyService:IAGVThirdPartyService, ITransient, IDynamicApiController + { + private readonly AGVHandler _aGVHandler; + private readonly IMQTTService _MQTTService; + public AGVThirdPartyService(AGVHandler aGVHandler, IMQTTService MQTTService) + { + _aGVHandler = aGVHandler; + _MQTTService = MQTTService; + } + + /// + /// 下发任务 + /// + /// + /// + [HttpPost] + public async Task ExecuteAsync(KCExecuteRequest cExecuteRequest) + { + + if (cExecuteRequest.JobData != null) + cExecuteRequest = new KCExecuteRequest + { + Url = cExecuteRequest.Url,//http://[IP:Port]/api/quicktron/wcs/standardized.robot.job.submit + RobotJobId = Guid.NewGuid().ToString(), + WarehouseId = cExecuteRequest.WarehouseId, + JobPriority = cExecuteRequest.JobPriority, + JobPriorityType = cExecuteRequest.JobPriorityType, + JobData = new KCJobDataRequest + { + StartPoint = cExecuteRequest.JobData.StartPoint, + + EndPoint = cExecuteRequest.JobData.EndPoint, + } + }; + return await _aGVHandler.ExecuteAsync(cExecuteRequest); + } + + /// + /// 取消任务 + /// + /// + /// + [HttpPost] + public async Task CancelAsync(KCCancelRequest kCCancelRequest) + { + //http://[IP:Port]/api/quicktron/wcs/standardized.robot.job.cancel + return await _aGVHandler.CancelAsync(kCCancelRequest); + } + + /// + /// + /// + /// + /// + public async Task RollerJobExecuteAsync(RollerJobRequest rollerJobRequest) + { + //http://[IP:Port]/api/quicktron/wcs/standardized.roller.job.upstream.response + return await _aGVHandler.RollerJobExecuteAsync(rollerJobRequest); + } + + /// + /// 任务回调 + /// + /// + /// + [HttpPost] + public async Task ExecuteReplyAsync(AGVExecuteReplyRequest input) + { + try + { + + var data = new AGVExecuteReplyMQTT() + { + Event = input.Event, + }; + return await _MQTTService.MqttPublish(data, Topics.ExecuteReplyTopic, MessageID.TaskState); + } + catch (Exception e) + { + return false; + } + } + + + /// + /// AGV上下料交互请求 + /// + /// + /// + [HttpPost] + public async Task LoadAndUnloadAsync(AGVLoadAndUnloadRequest input) + { + try + { + var data = new AGVLoadAndUnloadMQTT() + { + Event = input.Event, + }; + return await _MQTTService.MqttPublish(data, Topics.LoadAndUnloadTopic, MessageID.LoadAndUnload); + } + catch (Exception e) + { + return false; + } + } + + } +} diff --git a/backend/BPA.MES.Base.Application/Services/AGVService/Services/IAGVThirdPartyService.cs b/backend/BPA.MES.Base.Application/Services/AGVService/Services/IAGVThirdPartyService.cs new file mode 100644 index 0000000..7f07cd8 --- /dev/null +++ b/backend/BPA.MES.Base.Application/Services/AGVService/Services/IAGVThirdPartyService.cs @@ -0,0 +1,44 @@ +using BPA.AGV; +using BPA.MES.Base.Application.Services.AGVService.Dtos; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.MES.Base.Application.Services.AGVService.Services +{ + public interface IAGVThirdPartyService + { + + /// + /// 下发任务 + /// + /// + /// + Task ExecuteAsync(KCExecuteRequest cExecuteRequest); + + /// + /// 取消任务 + /// + /// + /// + Task CancelAsync(KCCancelRequest kCCancelRequest); + + + /// + /// 任务回调 + /// + /// + /// + Task ExecuteReplyAsync(AGVExecuteReplyRequest input); + + + /// + /// AGV上下料交互请求 + /// + /// + /// + Task LoadAndUnloadAsync(AGVLoadAndUnloadRequest input); + } +} diff --git a/backend/BPA.MES.Base.Application/Services/OrderService/Dtos/OrderBaseDto.cs b/backend/BPA.MES.Base.Application/Services/OrderService/Dtos/OrderBaseDto.cs index b6ed9bc..6724fbe 100644 --- a/backend/BPA.MES.Base.Application/Services/OrderService/Dtos/OrderBaseDto.cs +++ b/backend/BPA.MES.Base.Application/Services/OrderService/Dtos/OrderBaseDto.cs @@ -61,4 +61,18 @@ namespace BPA.MES.Base.Application.Services.OrderService.Dtos public decimal Number { get; set; } public WorkOrderStatusEnum? Status { get; set; } } + + /// + /// 成品数量限制 + /// + public class OrderWorkLimit + { + /// + /// 成品 + /// + public string FinalslId { get; set; } + + public decimal Limit { get; set; } + + } } diff --git a/backend/BPA.MES.Base.Application/Services/OrderService/Service/IOrderService.cs b/backend/BPA.MES.Base.Application/Services/OrderService/Service/IOrderService.cs index 527a7e4..c06f8ca 100644 --- a/backend/BPA.MES.Base.Application/Services/OrderService/Service/IOrderService.cs +++ b/backend/BPA.MES.Base.Application/Services/OrderService/Service/IOrderService.cs @@ -45,6 +45,13 @@ namespace BPA.MES.Base.Application.Services.OrderService.Service /// Task OrderAssociationWork(List inputDto); + /// + /// 获取成品剩余制作数量 + /// + /// + /// + Task> GetFinalslLImit(string OrderId); + Task CodeFirst(); } } diff --git a/backend/BPA.MES.Base.Application/Services/OrderService/Service/OrderService.cs b/backend/BPA.MES.Base.Application/Services/OrderService/Service/OrderService.cs index b854b48..44486a3 100644 --- a/backend/BPA.MES.Base.Application/Services/OrderService/Service/OrderService.cs +++ b/backend/BPA.MES.Base.Application/Services/OrderService/Service/OrderService.cs @@ -220,6 +220,8 @@ namespace BPA.MES.Base.Application.Services.OrderService.Service { var result = false; var orderId = inputDto.Select(x => x.OrderId).First(); + //验证 + VerifyOrderProduct(inputDto); _dbContext.Ado.BeginTran(); try @@ -292,6 +294,72 @@ namespace BPA.MES.Base.Application.Services.OrderService.Service return true; } + /// + /// 生成工单时验证成品数量 + /// + /// + private void VerifyOrderProduct(List inputDto) + { + var orderId = inputDto.Select(x => x.OrderId).First(); + var data=_dbContext.Queryable((a,b)=>new JoinQueryInfos( + JoinType.Left,a.FinalslId==b.Id + )).Where((a,b)=>a.OrderId==orderId). + Select((a,b)=>new + { + orderId = a.OrderId, + ProductId = a.FinalslId, + productName = b.Name, + a.Number + }).ToList(); + foreach (var item in data) + { + var productCount = inputDto.Where(x => x.FinalslId == item.ProductId).Sum(x => x.Number); + var count= item.Number - productCount; + if (count<0) + { + throw Oops.Bah($"{item.productName}成品生成工单数量大于订单数量,多【{System.Math.Abs(count)}】"); + } + + if (count>0) + { + throw Oops.Bah($"{item.productName}成品生成工单数量小于订单数量,差【{count}】"); + } + + } + } + + /// + /// 获取成品剩余制作数量 + /// + /// + /// + public async Task> GetFinalslLImit(string OrderId) + { + var result = new List(); + var orderInfo=_dbContext.Queryable().Where(x=>x.OrderId==OrderId).ToList(); + + var list=_dbContext.Queryable((a,b)=>new JoinQueryInfos( + JoinType.Left,a.WorkId==b.Id)) + .Where((a, b) => a.OrderId==OrderId) + .Select((a,b)=>new OrderWorkLimit() + { + FinalslId=b.FinalId, + Limit=0 + }).ToList(); + + foreach (var item in orderInfo) + { + var data=list.Where(x=>x.FinalslId==item.FinalslId).ToList(); + + result.Add(new OrderWorkLimit() + { + FinalslId=item.FinalslId, + Limit=item.Number-data.Sum(x=>x.Limit), + }); + } + return result; + + } [HttpGet] public Task CodeFirst() diff --git a/backend/BPA.MES.Base.Application/Services/ReportService/Dtos/MaterialsInputDto.cs b/backend/BPA.MES.Base.Application/Services/ReportService/Dtos/MaterialsInputDto.cs new file mode 100644 index 0000000..d50cac4 --- /dev/null +++ b/backend/BPA.MES.Base.Application/Services/ReportService/Dtos/MaterialsInputDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.MES.Base.Application.Services.ReportService.Dtos +{ + public class MaterialsInputDto + { + public DateTime? StartTime { get; set; } + public DateTime? EndTime { get; set; } + public string MaterialsName { get; set; } + } +} diff --git a/backend/BPA.MES.Base.Application/Services/ReportService/Dtos/MaterialsOutDto.cs b/backend/BPA.MES.Base.Application/Services/ReportService/Dtos/MaterialsOutDto.cs new file mode 100644 index 0000000..bc12347 --- /dev/null +++ b/backend/BPA.MES.Base.Application/Services/ReportService/Dtos/MaterialsOutDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BPA.MES.Base.Application.Services.ReportService.Dtos +{ + public class MaterialsOutDto + { + public string MaterialId { get; set; } + public string MaterialName { get; set; } + public decimal Count { get; set; } + } +} diff --git a/backend/BPA.MES.Base.Application/Services/ReportService/IReportService.cs b/backend/BPA.MES.Base.Application/Services/ReportService/IReportService.cs index 0b4a3fe..b64eedc 100644 --- a/backend/BPA.MES.Base.Application/Services/ReportService/IReportService.cs +++ b/backend/BPA.MES.Base.Application/Services/ReportService/IReportService.cs @@ -15,5 +15,12 @@ namespace BPA.MES.Base.Application.Services.ReportService /// /// Task> GetProductReport(ProductInputDto inputDto); + + /// + /// 获取物料统计 + /// + /// + /// + Task> GetMaterialsReport(MaterialsInputDto inputDto); } } diff --git a/backend/BPA.MES.Base.Application/Services/ReportService/ReportService.cs b/backend/BPA.MES.Base.Application/Services/ReportService/ReportService.cs index 6f26627..a21d51e 100644 --- a/backend/BPA.MES.Base.Application/Services/ReportService/ReportService.cs +++ b/backend/BPA.MES.Base.Application/Services/ReportService/ReportService.cs @@ -18,7 +18,7 @@ namespace BPA.MES.Base.Application.Services.ReportService } /// - /// 获取产品生产统计 + /// 获取成品生产统计 /// /// /// @@ -46,5 +46,70 @@ namespace BPA.MES.Base.Application.Services.ReportService return res; } + + /// + /// 获取物料统计 + /// + /// + /// + [HttpPost] + public async Task> GetMaterialsReport(MaterialsInputDto inputDto) + { + var result = new List(); + var res = await _dbContext.Queryable + ((a, b, c) => + new JoinQueryInfos( + JoinType.Left, a.Id == b.WorkId, + JoinType.Left, a.FinalId == c.Id) + ) + .Where((a, b, c) => b.Status != WorkOrderStatusEnum.Draft) + .WhereIF(inputDto.StartTime.HasVal(), (a, b, c) => b.CreateTime >= inputDto.StartTime.Value) + .WhereIF(inputDto.EndTime.HasVal(), (a, b, c) => b.CreateTime >= inputDto.EndTime.Value) + .Select((a, b, c) => new + { + ProductId = a.FinalId, + Count = SqlFunc.AggregateSum(Convert.ToInt32(a.Number)), + c.RecipeId + + }).ToListAsync(); + var recipeId = res.Select(x => x.RecipeId).ToList(); + + var recipes = await _dbContext.Queryable() + .Where(x => recipeId.Contains(x.RecipesId)) + .Select(x => new + { + x.MaterialId, + x.Weight, + x.RecipesId + }) .ToListAsync(); + + var materialsId= recipes.Select(x => x.MaterialId).ToList(); + + var materials = await _dbContext.Queryable() + .Where(x=> materialsId.Contains(x.Id)) + .WhereIF(!string.IsNullOrEmpty(inputDto.MaterialsName),x=>x.Name.Contains(inputDto.MaterialsName)) + .ToListAsync(); + + foreach (var item in materials) + { + var count = 0; + foreach (var item2 in res.GroupBy(x=>x.RecipeId)) + { + var data = recipes.Where(x=>x.RecipesId==item2.Key &&x.MaterialId==item.Id).FirstOrDefault(); + count=item2.First().Count*Convert.ToInt32(data==null? 0: data.Weight); + + } + + result.Add(new MaterialsOutDto() + { + MaterialId=item.Id, + MaterialName=item.Name, + Count= count, + }); + } + + return result; + } + } } diff --git a/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoCraftstepRecordDto.cs b/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoCraftstepRecordDto.cs index f9fd97a..710c7f1 100644 --- a/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoCraftstepRecordDto.cs +++ b/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoCraftstepRecordDto.cs @@ -49,6 +49,14 @@ /// public string WorkCraftstepId { get; set; } /// + /// 工单Id + /// + public string WorkId { get; set; } + /// + /// 锅数 + /// + public string PotNum { get; set; } + /// /// 状态 /// public RecipeStatus Status { get; set; } diff --git a/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoDto.cs b/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoDto.cs index e193795..73947d0 100644 --- a/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoDto.cs +++ b/backend/BPA.MES.Base.Application/Services/WorkInfoService/Dtos/WorkInfoDto.cs @@ -73,6 +73,18 @@ /// 主键 /// public string Id { get; set; } + /// + /// 工单状态 + /// + public WorkOrderStatusEnum?[] Status { get; set; } + /// + /// 起始时间 + /// + public DateTime? StartTime { get; set; } + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } } /// /// 分页 @@ -87,6 +99,18 @@ /// 编码 /// public string Id { get; set; } + /// + /// 工单状态 + /// + public WorkOrderStatusEnum?[] Status { get; set; } + /// + /// 起始时间 + /// + public DateTime? StartTime { get; set; } + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } } /// /// 工单下发 diff --git a/backend/BPA.MES.Base.Application/Services/WorkInfoService/Services/WorkInfoService.cs b/backend/BPA.MES.Base.Application/Services/WorkInfoService/Services/WorkInfoService.cs index 36d066c..16ada5e 100644 --- a/backend/BPA.MES.Base.Application/Services/WorkInfoService/Services/WorkInfoService.cs +++ b/backend/BPA.MES.Base.Application/Services/WorkInfoService/Services/WorkInfoService.cs @@ -140,6 +140,9 @@ namespace BPA.MES.Base.Application.Services.WorkInfoService.Services .LeftJoin((a, b, c, d) => d.Id == SqlFunc.Subqueryable().Where(s => s.WorkId == a.Id).OrderByDesc(s => s.CreateTime).Select(s => s.Id)) .WhereIF(!string.IsNullOrEmpty(input.Name), (a, b, c, d) => b.Name.Contains(input.Name)) .WhereIF(!string.IsNullOrEmpty(input.Id), (a, b, c, d) => a.Id.Contains(input.Id)) + .WhereIF(input.Status != null, (a, b, c, d) => input.Status.Contains(d.Status)) + .WhereIF(input.StartTime!=null,(a, b, c, d) => input.StartTime<= Convert.ToDateTime(a.CreateTime)) + .WhereIF(input.EndTime != null, (a, b, c, d) => input.EndTime.Value.AddHours(23).AddMinutes(59).AddSeconds(59) >= Convert.ToDateTime(a.CreateTime)) .Select((a, b, c, d) => new WorkInfoOutput { Id = a.Id.SelectAll(), @@ -163,6 +166,9 @@ namespace BPA.MES.Base.Application.Services.WorkInfoService.Services .LeftJoin((a, b, c, d) => d.Id == SqlFunc.Subqueryable().Where(s => s.WorkId == a.Id).OrderByDesc(s => s.CreateTime).Select(s => s.Id)) .WhereIF(!string.IsNullOrEmpty(input.Name), (a, b, c, d) => b.Name.Contains(input.Name)) .WhereIF(!string.IsNullOrEmpty(input.Id), (a, b, c, d) => a.Id.Contains(input.Id)) + .WhereIF(input.Status != null, (a, b, c, d) => input.Status.Contains(d.Status)) + .WhereIF(input.StartTime != null, (a, b, c, d) => input.StartTime <= Convert.ToDateTime(a.CreateTime)) + .WhereIF(input.EndTime != null, (a, b, c, d) => input.EndTime.Value.AddHours(23).AddMinutes(59).AddSeconds(59) >= Convert.ToDateTime(a.CreateTime)) .Select((a, b, c, d) => new WorkInfoOutput { Id = a.Id.SelectAll(), @@ -359,15 +365,30 @@ namespace BPA.MES.Base.Application.Services.WorkInfoService.Services [HttpPost] public async Task UpdateWorkCraftStepsStatus(WorkInfoCraftstepRecordUpdateInput input) { - WorkInfoCraftstepRecordEntity entity = new() + + + var entityFrist = await _dbContext.Queryable().Where(x => x.Id == input.WorkCraftstepId).FirstAsync(); + if (!string.IsNullOrEmpty(input.WorkId)) { - Id = input.WorkCraftstepId, - Status = input.Status, - UpdateTime = DateTime.Now - }; - bool res = await _dbContext.Updateable(entity).IgnoreColumns(true).ExecuteCommandHasChangeAsync(); - return res; + bool res = await _dbContext.Updateable() + .SetColumns(x=>x.Status==input.Status) + .SetColumns(x=>x.UpdateTime==DateTime.Now).IgnoreColumns(true).Where(x=>x.WorkId==input.WorkId && x.PotNum==input.PotNum).ExecuteCommandHasChangeAsync(); + return res; + } + else + { + WorkInfoCraftstepRecordEntity entity = new() + { + Id = input.WorkCraftstepId, + Status = input.Status, + UpdateTime = DateTime.Now, + Step = entityFrist.Step + }; + bool res = await _dbContext.Updateable(entity).IgnoreColumns(true).ExecuteCommandHasChangeAsync(); + return res; + } } + /// /// 强制结束工单 /// diff --git a/backend/BPA.MES.Base.Core/BPA.MES.Base.Core.csproj b/backend/BPA.MES.Base.Core/BPA.MES.Base.Core.csproj index 58e025d..c91d436 100644 --- a/backend/BPA.MES.Base.Core/BPA.MES.Base.Core.csproj +++ b/backend/BPA.MES.Base.Core/BPA.MES.Base.Core.csproj @@ -13,6 +13,9 @@ + + + diff --git a/backend/BPA.MES.Base.Web.Core/Startup.cs b/backend/BPA.MES.Base.Web.Core/Startup.cs index c34c1d9..8cc2834 100644 --- a/backend/BPA.MES.Base.Web.Core/Startup.cs +++ b/backend/BPA.MES.Base.Web.Core/Startup.cs @@ -1,11 +1,21 @@ -using BPA.MES.Base.Application; +using System; +using System.Threading.Tasks; +using BPA.AGV; +using BPA.ApiClient; +using BPA.MES.Base.Application; using BPA.MES.Base.Application.Subscriber; using BPA.MES.Base.Core; +using BPA.MQTTClient; using Furion; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using MQTTnet.Client; +using MQTTnet.Client.Connecting; +using MQTTnet.Client.Disconnecting; +using MQTTnet.Client.Options; +using Newtonsoft.Json.Linq; using Yitter.IdGenerator; namespace BPA.MES.Base.Web.Core; @@ -14,6 +24,7 @@ public class Startup : AppStartup { public void ConfigureServices(IServiceCollection services) { + services.AddConsoleFormatter(); services.AddJwt(enableGlobalAuthorize: true); services.AddCorsAccessor(); @@ -30,6 +41,50 @@ public class Startup : AppStartup builder.AddSubscriber(typeof(ToDoEventSubscriber)); }); services.AddRemoteRequest(); + + services.AddWebApiClient(); + services.AddAGV(op => + { + op.Header = new KCOption() + { + AppKey = "43", + AppSecret = "12", + RequestId = "43", + Timestamp = "2234234324", + Version = "2.9" + }; + op.Sign = "123456"; + }); + + //services.AddMqttClientHostedService(op => + //{ + // op.Port = 1883; + // op.Server = "10.2.1.21"; + // op.UserName = "emqx_u_block"; + // op.Password = "emqx_p_admin8765490789"; + // op.mqttClientConnectedHandlerDelegate = new MqttClientConnectedHandlerDelegate(async e => + // { + // Console.WriteLine("MQTT连接成功"); + // }); + // op.mqttClientDisconnectedHandlerDelegate = new MqttClientDisconnectedHandlerDelegate(async e => + // { + // Console.WriteLine("MQTT断开连接"); + // await Task.Delay(TimeSpan.FromSeconds(5)); + // try + // { + // //var options = builder.Build().Services.GetService(); + // //await builder.Build().Services.GetService().ConnectAsync(options); + // } + // catch (global::System.Exception) + // { + // } + // }); + // op.MqttApplicationMessageReceivedHandler = new MQTTnet.Client.Receiving.MqttApplicationMessageReceivedHandlerDelegate(async e => + // { + + // }); + //}); + services.AddControllers() .AddInjectWithUnifyResult(); } diff --git a/frontend/config/proxy.ts b/frontend/config/proxy.ts index 152426e..6f8a8a0 100644 --- a/frontend/config/proxy.ts +++ b/frontend/config/proxy.ts @@ -6,7 +6,7 @@ export default { dev: { '/api/': { - target: 'http://10.2.1.26:21674/api', + target: 'http://localhost:5002', pathRewrite: { '/api': '/api' }, diff --git a/frontend/config/routes.ts b/frontend/config/routes.ts index ee8e89b..3807487 100644 --- a/frontend/config/routes.ts +++ b/frontend/config/routes.ts @@ -71,6 +71,7 @@ path: '/report', icon: 'SettingOutlined', name: '统计报表', routes: [ { path: '/report/product', name: '成品统计', component: './report/product' }, + { path: '/report/material', name: '原料统计', component: './report/material' }, ] }, { path: '*', layout: false, component: './404' }, diff --git a/frontend/src/api/orderService.ts b/frontend/src/api/orderService.ts index ae48440..0d17f47 100644 --- a/frontend/src/api/orderService.ts +++ b/frontend/src/api/orderService.ts @@ -76,6 +76,17 @@ export default { }); }, + /** + * 获取成品可制造数量 + * @param parms + * @returns + */ + getFinalslLImit(parms:string) { + return request('/api/order/getfinalsllimit/'+parms, { + method: 'get', + }); + }, + } diff --git a/frontend/src/api/reportService.ts b/frontend/src/api/reportService.ts index 4b51d7e..f77ab36 100644 --- a/frontend/src/api/reportService.ts +++ b/frontend/src/api/reportService.ts @@ -8,13 +8,27 @@ export default { * @param parms * @returns */ - PagedList(parms: ReportType.ProductReportInput) { + PagedList(parms: ReportType.ReportInput) { return request('/api/report/getproductreport', { method: 'POST', data: { ...parms, }, }); + }, + + /** + * 获取原料统计 + * @param parms + * @returns + */ + PagedMaterialList(parms: ReportType.ReportInput) { + return request('/api/report/getmaterialsreport', { + method: 'POST', + data: { + ...parms, + }, + }); } } diff --git a/frontend/src/pages/dict/index.tsx b/frontend/src/pages/dict/index.tsx index 2c8fe4e..7687cf1 100644 --- a/frontend/src/pages/dict/index.tsx +++ b/frontend/src/pages/dict/index.tsx @@ -157,7 +157,7 @@ export default () => { { title: '主键', dataIndex: 'id', - // hideInTable: true, + hideInTable: true, hideInForm: true, search: true, }, @@ -167,9 +167,7 @@ export default () => { ellipsis: true, hindeInForm: true, search: false, - // hideInTable: true, - - + hideInTable: true, }, { title: '编码', diff --git a/frontend/src/pages/order/index.tsx b/frontend/src/pages/order/index.tsx index 9ba5dda..be37db0 100644 --- a/frontend/src/pages/order/index.tsx +++ b/frontend/src/pages/order/index.tsx @@ -222,7 +222,7 @@ export default () => { if (res.data) { message.success('添加成功'); actionRef.current?.reload(); - setIsModalOpen(false); + setIsWorkModalOpen(false); } else { message.error(res.errors || '添加失败'); } @@ -478,7 +478,7 @@ export default () => { }, ]} > - {productSelect.map((item) => ( {item.value} @@ -522,10 +522,16 @@ export default () => { labelCol={{ span: 8 }} rules={[{ required: true, message: '请输入数量!', },]} > - + +