diff --git a/DOAN.Model/MES/recipe/Dto/PfRecipeIssueLogDto.cs b/DOAN.Model/MES/recipe/Dto/PfRecipeIssueLogDto.cs index 1196a2d..e429f33 100644 --- a/DOAN.Model/MES/recipe/Dto/PfRecipeIssueLogDto.cs +++ b/DOAN.Model/MES/recipe/Dto/PfRecipeIssueLogDto.cs @@ -19,25 +19,70 @@ namespace DOAN.Model.MES.recipe.Dto /// public class PfRecipeIssueLogDto { - public string Receiver { get; set; } + /// + /// 下达记录ID(主键) + /// + public int Id { get; set; } + /// + /// 配方码 + /// + public string RecipeCode { get; set; } + + /// + /// 版本编号 + /// + public string Version { get; set; } + + /// + /// 下达时间 + /// + + public DateTime? IssueTime { get; set; } + + + /// + /// 工单号 + /// + + public string Workorder { get; set; } + + /// + /// 产品码 + /// + + public string ProductCode { get; set; } + + /// + /// 产品名称 + /// + + public string ProductName { get; set; } + + + /// + /// 创建人 + /// + public string CreatedBy { get; set; } + /// + /// 创建时间 + /// + public DateTime? CreatedTime { get; set; } + /// + /// 更新人 + /// + public string UpdatedBy { get; set; } + /// + /// 更新时间 + /// + public DateTime? UpdatedTime { get; set; } - public int Id { get; set; } - - public string RecipeCode { get; set; } - - public string Version { get; set; } - - public DateTime? IssueTime { get; set; } - - public string IssuedBy { get; set; } - } } \ No newline at end of file diff --git a/DOAN.Model/MES/recipe/PfRecipeIssueLog.cs b/DOAN.Model/MES/recipe/PfRecipeIssueLog.cs index 573491a..34f78dd 100644 --- a/DOAN.Model/MES/recipe/PfRecipeIssueLog.cs +++ b/DOAN.Model/MES/recipe/PfRecipeIssueLog.cs @@ -7,10 +7,50 @@ namespace DOAN.Model.MES.recipe [SugarTable("pf_recipe_issue_log")] public class PfRecipeIssueLog { + + /// - /// 接收方 + /// 下达记录ID(主键) /// - public string Receiver { get; set; } + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 配方码 + /// + [SugarColumn(ColumnName = "recipe_code")] + public string RecipeCode { get; set; } + + /// + /// 版本编号 + /// + public string Version { get; set; } + + /// + /// 下达时间 + /// + [SugarColumn(ColumnName = "issue_time")] + public DateTime? IssueTime { get; set; } + + + /// + /// 工单号 + /// + [SugarColumn(ColumnName = "workorder")] + public string Workorder { get; set; } + + /// + /// 产品码 + /// + [SugarColumn(ColumnName = "productcode")] + public string ProductCode { get; set; } + + /// + /// 产品名称 + /// + [SugarColumn(ColumnName = "productname")] + public string ProductName { get; set; } + /// /// 创建人 @@ -36,34 +76,5 @@ namespace DOAN.Model.MES.recipe [SugarColumn(ColumnName = "updated_time")] public DateTime? UpdatedTime { get; set; } - /// - /// 下达记录ID(主键) - /// - [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] - public int Id { get; set; } - - /// - /// 配方码 - /// - [SugarColumn(ColumnName = "recipe_code")] - public string RecipeCode { get; set; } - - /// - /// 版本编号 - /// - public string Version { get; set; } - - /// - /// 下达时间 - /// - [SugarColumn(ColumnName = "issue_time")] - public DateTime? IssueTime { get; set; } - - /// - /// 下达人 - /// - [SugarColumn(ColumnName = "issued_by")] - public string IssuedBy { get; set; } - } } \ No newline at end of file diff --git a/DOAN.Service/Mobile/IService/IPADReportWorkService.cs b/DOAN.Service/Mobile/IService/IPADReportWorkService.cs index 301c52b..9642d47 100644 --- a/DOAN.Service/Mobile/IService/IPADReportWorkService.cs +++ b/DOAN.Service/Mobile/IService/IPADReportWorkService.cs @@ -20,6 +20,6 @@ public interface IPADReportWorkService int UpdateProReportwork(ProReportwork parm); - int StartWorkOrder(string workorder); + Task StartWorkOrder(string workorder); int FinishWorkOrder(string workorder); } \ No newline at end of file diff --git a/DOAN.Service/Mobile/PADReportWorkService.cs b/DOAN.Service/Mobile/PADReportWorkService.cs index 0c8daa2..50bc1f5 100644 --- a/DOAN.Service/Mobile/PADReportWorkService.cs +++ b/DOAN.Service/Mobile/PADReportWorkService.cs @@ -1,8 +1,10 @@ +using DOAN.Infrastructure.Helper; using DOAN.Model; using DOAN.Model.MES.base_; using DOAN.Model.MES.mm; using DOAN.Model.MES.product; using DOAN.Model.MES.product.Dto; +using DOAN.Model.MES.recipe; using DOAN.Repository; using DOAN.Service.MES.mm.line; using DOAN.Service.Mobile.IService; @@ -162,7 +164,7 @@ namespace DOAN.Service.Mobile return Update(model, true); } - public int StartWorkOrder(string workorder) + public async Task StartWorkOrder(string workorder) { var result = 0; // 获取同一天 同一组 同一线 的所有工单 把状态2 设为init 1 @@ -184,9 +186,53 @@ namespace DOAN.Service.Mobile }); //TODO 拼接MQTT消息,发送给设备,工单信息和配方信息 - Context.Queryable + var RecipeMesg= Context.Queryable().LeftJoin((rpr, r) => rpr.RecipeCode == r.RecipeCode) + .Where((rpr, r) => rpr.Productcode == handleWorkorder.ProductionCode) + .Where((rpr, r) => r.Status == 1) + .Select((rpr, r) => new + { + RecipeCode = r.RecipeCode, + Version = r.Version, + ParamList = Context.Queryable().Where(it => it.RecipeCode == r.RecipeCode && it.Version == r.Version).ToList() + }).First(); + if( RecipeMesg==null) + { + throw new Exception("未找到对应的配方信息,请检查产品与配方的关联关系,或配方状态是否有效"); + } + + // 合并两个对象为匿名对象 + var combinedObject = new + { + WorkorderInfo = handleWorkorder, + RecipeInfo = RecipeMesg + }; + string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(combinedObject, Newtonsoft.Json.Formatting.Indented); + //插入配方派发日志 + PfRecipeIssueLog pfRecipeIssueLog = new PfRecipeIssueLog(); + pfRecipeIssueLog.RecipeCode = RecipeMesg.RecipeCode; + pfRecipeIssueLog.Version = RecipeMesg.Version; + pfRecipeIssueLog.IssueTime = DateTime.Now; + pfRecipeIssueLog.Workorder = handleWorkorder.Workorder; + pfRecipeIssueLog.ProductCode = handleWorkorder.ProductionCode; + pfRecipeIssueLog.ProductName = handleWorkorder.ProductionName; + pfRecipeIssueLog.CreatedBy = "PDA"; + pfRecipeIssueLog.CreatedTime = DateTime.Now; + Context.Insertable(pfRecipeIssueLog).ExecuteCommand(); + + + MqttHelper _mqttHelper=new MqttHelper("mqtt://192.168.50.163", 8883); + + // 连接 + await _mqttHelper.ConnectAsync(); + + // 发送多条消息 + + await _mqttHelper.PublishMessageAsync("MES/Workorder/Start", jsonString); + + // 断开连接 + await _mqttHelper.DisconnectAsync(); return result; diff --git a/Infrastructure/DOAN.Infrastructure.csproj b/Infrastructure/DOAN.Infrastructure.csproj index afa789c..a42dadc 100644 --- a/Infrastructure/DOAN.Infrastructure.csproj +++ b/Infrastructure/DOAN.Infrastructure.csproj @@ -18,6 +18,7 @@ + diff --git a/Infrastructure/Helper/MqttHelper.cs b/Infrastructure/Helper/MqttHelper.cs new file mode 100644 index 0000000..063634f --- /dev/null +++ b/Infrastructure/Helper/MqttHelper.cs @@ -0,0 +1,169 @@ +using MQTTnet; +using MQTTnet.Formatter; +using MQTTnet.Protocol; +using System; +using System.Threading.Tasks; +namespace DOAN.Infrastructure.Helper +{ + + /// + /// MQTT 消息发送工具类 + /// + public class MqttHelper : IDisposable + { + // MQTT Broker 配置(可外部设置或配置文件读取) + public string MqttBrokerUrl { get; set; } = "broker.hivemq.com"; + public int MqttBrokerPort { get; set; } = 1883; + public string MqttUsername { get; set; } = null; + public string MqttPassword { get; set; } = null; + + private IMqttClient _mqttClient; + + private bool _disposed = false; + + /// + /// 构造函数 - 使用默认配置 + /// + public MqttHelper() { } + + /// + /// 构造函数 - 自定义配置 + /// + public MqttHelper(string brokerUrl, int brokerPort, string username = null, string password = null) + { + MqttBrokerUrl = brokerUrl; + MqttBrokerPort = brokerPort; + MqttUsername = username; + MqttPassword = password; + } + + /// + /// 连接到 MQTT Broker + /// + public async Task ConnectAsync() + { + try + { + if (_mqttClient?.IsConnected == true) + { + Console.WriteLine("MQTT 客户端已经连接"); + return true; + } + + var factory = new MqttClientFactory(); + _mqttClient = factory.CreateMqttClient(); + + var options = new MqttClientOptionsBuilder() + .WithTcpServer(MqttBrokerUrl, MqttBrokerPort) + .WithCredentials(MqttUsername, MqttPassword) + .WithCleanSession() + .Build(); + + Console.WriteLine($"正在连接到 MQTT Broker: {MqttBrokerUrl}:{MqttBrokerPort}..."); + await _mqttClient.ConnectAsync(options); + + Console.WriteLine("✅ MQTT 连接成功!"); + return true; + } + catch (Exception ex) + { + Console.WriteLine($"❌ MQTT 连接失败: {ex.Message}"); + return false; + } + } + + /// + /// 发送消息到指定主题 + /// + /// 目标主题 + /// 消息内容 + /// QoS 级别,默认为 AtLeastOnce(1) + /// 是否保留消息,默认为 false + public async Task PublishMessageAsync(string topic, string messageContent, + MqttQualityOfServiceLevel qosLevel = MqttQualityOfServiceLevel.AtLeastOnce, + bool retain = false) + { + try + { + if (_mqttClient?.IsConnected != true) + { + Console.WriteLine("MQTT 客户端未连接,尝试重新连接..."); + if (!await ConnectAsync()) + { + Console.WriteLine("❌ 重连失败,无法发送消息"); + return false; + } + } + + var message = new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(messageContent) + .WithQualityOfServiceLevel(qosLevel) + .WithRetainFlag(retain) + .Build(); + + Console.WriteLine($"正在向主题 '{topic}' 发送消息: {messageContent}"); + await _mqttClient.PublishAsync(message); + + Console.WriteLine("✅ 消息发送成功!"); + return true; + } + catch (Exception ex) + { + Console.WriteLine($"❌ 消息发送失败: {ex.Message}"); + return false; + } + } + + /// + /// 发送消息(使用默认主题配置) + /// + /// 消息内容 + /// QoS 级别 + /// 是否保留消息 + public async Task PublishMessageAsync(string messageContent, + MqttQualityOfServiceLevel qosLevel = MqttQualityOfServiceLevel.AtLeastOnce, + bool retain = false) + { + return await PublishMessageAsync("product/topic", messageContent, qosLevel, retain); + } + + /// + /// 断开 MQTT 连接 + /// + public async Task DisconnectAsync() + { + try + { + if (_mqttClient?.IsConnected == true) + { + await _mqttClient.DisconnectAsync(); + Console.WriteLine("🔌 MQTT 已断开连接"); + } + } + catch (Exception ex) + { + Console.WriteLine($"❌ 断开连接时发生错误: {ex.Message}"); + } + } + + /// + /// 检查是否已连接 + /// + public bool IsConnected => _mqttClient?.IsConnected == true; + + /// + /// 释放资源 + /// + public void Dispose() + { + if (!_disposed) + { + DisconnectAsync().Wait(); + _mqttClient?.Dispose(); + _disposed = true; + } + } + } + +}