From 3edea778f65e7c6dbaabfef73d8b85bbb8fa9e26 Mon Sep 17 00:00:00 2001 From: SoulStar Date: Mon, 1 Jun 2026 11:00:13 +0800 Subject: [PATCH] =?UTF-8?q?feat=20-=20=E5=AE=9A=E6=97=B6=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SlnMesnac.Config/AppConfig.cs | 15 ++ .../service/Impl/RealReadDataImpl.cs | 9 + SlnMesnac.Rfid/TouchSocketSetup.cs | 2 +- SlnMesnac.TouchSocket/TcpServer.cs | 20 +- .../IndexPage/ChangeTypeViewModel.cs | 184 +++++++++++++++++- .../IndexPage/ProductionLineViewModel.cs | 7 + SlnMesnac.WPF/appsettings.json | 9 +- 7 files changed, 231 insertions(+), 15 deletions(-) diff --git a/SlnMesnac.Config/AppConfig.cs b/SlnMesnac.Config/AppConfig.cs index c09d404..dcf0497 100644 --- a/SlnMesnac.Config/AppConfig.cs +++ b/SlnMesnac.Config/AppConfig.cs @@ -87,6 +87,21 @@ namespace SlnMesnac.Config /// public string MESConfig { get; set; } + /// + /// 是否启用订单自动刷新 + /// + public bool AutoOrderRefresh { get; set; } = true; + + /// + /// 订单自动刷新间隔(秒) + /// + public int OrderRefreshInterval { get; set; } = 60; + + /// + /// 模拟MES返回数据(调试用,配置JSON字符串) + /// + public string MockMesResponse { get; set; } = string.Empty; + public AppConfig Value => this; } } diff --git a/SlnMesnac.Repository/service/Impl/RealReadDataImpl.cs b/SlnMesnac.Repository/service/Impl/RealReadDataImpl.cs index 2146181..9b3c121 100644 --- a/SlnMesnac.Repository/service/Impl/RealReadDataImpl.cs +++ b/SlnMesnac.Repository/service/Impl/RealReadDataImpl.cs @@ -19,5 +19,14 @@ namespace SlnMesnac.Repository.service.Impl } public SQLiteHelper _helper = new SQLiteHelper(); + + ///// + ///// 插入或者替换数据 + ///// + ///// + //public bool InsertOrReplaceMesData() + //{ + + //} } } diff --git a/SlnMesnac.Rfid/TouchSocketSetup.cs b/SlnMesnac.Rfid/TouchSocketSetup.cs index 4e7e023..215dbcb 100644 --- a/SlnMesnac.Rfid/TouchSocketSetup.cs +++ b/SlnMesnac.Rfid/TouchSocketSetup.cs @@ -43,7 +43,7 @@ namespace SlnMesnac.TouchSocket //var _apiServer = service.GetService(); //_apiServer.Init(); var _server = service.GetService(); - _server.Init(5656); + _server.Init(1145); var _httpclient = service.GetService(); var _appSetting = service.GetService(); //_server.Init(6001); diff --git a/SlnMesnac.TouchSocket/TcpServer.cs b/SlnMesnac.TouchSocket/TcpServer.cs index 25a17f6..9625f07 100644 --- a/SlnMesnac.TouchSocket/TcpServer.cs +++ b/SlnMesnac.TouchSocket/TcpServer.cs @@ -1,5 +1,4 @@ -using Serilog; -using SlnMesnac.Common; +using SlnMesnac.Common; using SlnMesnac.Model.dto; using SlnMesnac.Model.Enum; using SlnMesnac.Serilog; @@ -95,19 +94,20 @@ namespace SlnMesnac.TouchSocket }; _service.Received = (client, e) => { + Log.Information($"客户端{client.IP}发送数据 {BitConverter.ToString(e.Memory.Span.ToArray())}"); //从客户端收到信息 //var mes = Encoding.UTF8.GetString(e.Memory.Span.ToArray(), 0, e.Memory.Span.Length);//注意:数据长度是byteBlock.Len byte[] receivedBuffer = new byte[e.Memory.Span.Length]; Array.Copy(e.Memory.Span.ToArray(), 0, receivedBuffer, 0, e.Memory.Span.Length); //MES客户端消息解析 - if (receivedBuffer[4] == 0x65) - { - byte[] addrby = new byte[2]; - Array.Copy(receivedBuffer, 1, addrby, 0, 2); - var flag = BitConverter.ToUInt16(addrby, 0); - _service.ResetIdAsync($"{client.IP}:{client.Port}", flag.ToString()); - } + //if (receivedBuffer[4] == 0x65) + //{ + // byte[] addrby = new byte[2]; + // Array.Copy(receivedBuffer, 1, addrby, 0, 2); + // var flag = BitConverter.ToUInt16(addrby, 0); + // _service.ResetIdAsync($"{client.IP}:{client.Port}", flag.ToString()); + //} //ReceivedClientBufferEvent?.Invoke(receivedBuffer); @@ -125,7 +125,7 @@ namespace SlnMesnac.TouchSocket //自定义插件 })); _service.StartAsync(); - Log.Information($"TcpServer启动成功,监听端口:{serverPort}"); + Log.Information($"TcpServer激光打标启动成功,监听端口:{serverPort}"); Task.Run(async delegate { //await Task.Delay(1000 * 20); diff --git a/SlnMesnac.WPF/ViewModel/IndexPage/ChangeTypeViewModel.cs b/SlnMesnac.WPF/ViewModel/IndexPage/ChangeTypeViewModel.cs index 3b1ce1f..6da2f48 100644 --- a/SlnMesnac.WPF/ViewModel/IndexPage/ChangeTypeViewModel.cs +++ b/SlnMesnac.WPF/ViewModel/IndexPage/ChangeTypeViewModel.cs @@ -28,6 +28,7 @@ using System.Text.Json; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Forms; +using System.Windows.Threading; using TouchSocket.Sockets; namespace SlnMesnac.WPF.ViewModel.IndexPage @@ -45,6 +46,10 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage private MesOrderInfoImpl databaseService = MesOrderInfoImpl.Instance; + private DispatcherTimer? _autoRefreshTimer; + private string _currentLineName = string.Empty; + private bool _isPaused; + public ChangeTypeViewModel() { _logger = App.ServiceProvider.GetService(); @@ -58,6 +63,10 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage //sqlSugarClient = App.ServiceProvider.GetService(); rfidList = App.ServiceProvider.GetRequiredService>(); + //注册订单刷新暂停/恢复消息 + WeakReferenceMessenger.Default.Register(this, "PauseOrderRefresh", (_, __) => PauseAutoRefreshTimer()); + WeakReferenceMessenger.Default.Register(this, "ResumeOrderRefresh", (_, __) => ResumeAutoRefreshTimer()); + Items = new ObservableCollection(); foreach (var rfid in rfidList) { @@ -130,6 +139,10 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage MessageBox.Show("MES订单切换成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information); Log.Information($"{mesOrderNo}MES订单切换成功{JsonSerializer.Serialize(real_Data)}"); + //记录当前产线并启动自动刷新 + _currentLineName = QueryIsCheck.ToString().Trim(); + StartAutoRefreshTimer(); + MainWindowViewModel.ReturnHomeAction?.Invoke(); } @@ -152,6 +165,9 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage List DeviceInfos = appConfig.deviceInfoConfig.Where(x => x.Collectid == appConfig.StationCode && x.Name == QueryIsCheck.ToString().Trim() && x.Deleteflag == 0).ToList(); WeakReferenceMessenger.Default.Send(DeviceInfos[0].Deviceid, "Cancel"); + //同时停止订单自动刷新 + StopAutoRefreshTimer(); + } @@ -179,6 +195,8 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage //调用MES接口获取生产订单信息 //MessageBox.Show("MES订单获取成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information); //string response = "{\"code\":200,\"msg\":\"success\",\"data\":[{\"OrderNo\":\"SS074\",\"ProductCode\":\"4030502500100006\",\"ProductType\":\"钢丝带-ST-井下阻燃钢丝带\",\"ProductName\":\"输送带-井下阻燃钢丝带-ST\",\"ProductSpec\":\"1400mm;ST/S2500*1;8+8;MT/MT;D7.2;P15;N89\",\"PlanQty\":130.00,\"NextProductNo\":1,\"PlanState\":\"7\",\"PlanStateName\":\"终止\"},{\"OrderNo\":\"SZ091\",\"ProductCode\":\"4030502000100017\",\"ProductType\":\"钢丝带-ST-井下阻燃钢丝带\",\"ProductName\":\"输送带-井下阻燃钢丝带-ST;\",\"ProductSpec\":\"1200mm;ST/S2000*1;8+6;MT/MT;D6;P12;N94\",\"PlanQty\":5.00,\"NextProductNo\":2,\"PlanState\":\"7\",\"PlanStateName\":\"终止\"},{\"OrderNo\":\"SS074\",\"ProductCode\":\"4031502500100003\",\"ProductType\":\"钢丝带-ST-井下阻燃钢网防撕裂钢丝带\",\"ProductName\":\"输送带-井下阻燃钢网防撕裂-ST\",\"ProductSpec\":\"1400mm;ST/S2500*1;8S+8;MT/MT;D7.2;P15;N89\",\"PlanQty\":160.00,\"NextProductNo\":14,\"PlanState\":\"7\",\"PlanStateName\":\"终止\"},{\"OrderNo\":\"SS074\",\"ProductCode\":\"4031502500100003\",\"ProductType\":\"钢丝带-ST-井下阻燃钢网防撕裂钢丝带\",\"ProductName\":\"输送带-井下阻燃钢网防撕裂-ST\",\"ProductSpec\":\"1400mm;ST/S2500*1;8S+8;MT/MT;D7.2;P15;N89\",\"PlanQty\":280.00,\"NextProductNo\":14,\"PlanState\":\"7\",\"PlanStateName\":\"终止\"}]}"; + //调试用:从配置文件MockMesResponse读取模拟数据 + //string response = appConfig.MockMesResponse; string response = await _httpclient.GetMesOrderInfo(lineno, BeginDate.ToString("yyyy-MM-dd")); Console.WriteLine("接收MES接口返回:" + response); // 反序列化 @@ -202,15 +220,17 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage if (response != null) { - //ChangeTypePanel.Clear(); + //先删除所有订单数据 DateTime twoDaysAgo = DateTime.Now.AddDays(-2); - databaseService._helper.Delete(x => x.InsertDate < twoDaysAgo); + databaseService._helper.Delete(x => true); + //直接插入新的订单数据 foreach (var item in responsejson.Data) { item.ID = Guid.NewGuid().ToString(); item.InsertDate = DateTime.Now; databaseService._helper.Insert(item); } + //查询出来所有数据,反向之后刷新界面 var items = databaseService._helper.QueryAll(); items.Reverse(); ChangeTypePanel.Clear(); @@ -321,13 +341,171 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage set => SetProperty(ref _ChangeTypePanel, value); } + #region 订单自动刷新 + + /// + /// 启动订单自动刷新定时器 + /// + private void StartAutoRefreshTimer() + { + if (!appConfig.AutoOrderRefresh) + return; + + if (_autoRefreshTimer != null) + return; + + var intervalSeconds = appConfig.OrderRefreshInterval > 0 ? appConfig.OrderRefreshInterval : 60; + + _autoRefreshTimer = new DispatcherTimer + { + Interval = TimeSpan.FromSeconds(intervalSeconds) + }; + _autoRefreshTimer.Tick += AutoRefreshTimerTick; + _autoRefreshTimer.Start(); + _isPaused = false; + + Log.Information($"订单自动刷新已启动,间隔 {intervalSeconds} 秒"); + } + + /// + /// 暂停订单自动刷新(写入标签时调用) + /// + private void PauseAutoRefreshTimer() + { + if (_autoRefreshTimer == null || _isPaused) + return; + + _autoRefreshTimer.Stop(); + _isPaused = true; + Log.Information("订单自动刷新已暂停(正在写入标签)"); + } + + /// + /// 恢复订单自动刷新(写入完成/失败后调用) + /// + private void ResumeAutoRefreshTimer() + { + if (_autoRefreshTimer == null || !_isPaused) + return; + + _autoRefreshTimer.Start(); + _isPaused = false; + Log.Information("订单自动刷新已恢复"); + } + + /// + /// 停止订单自动刷新定时器 + /// + public void StopAutoRefreshTimer() + { + if (_autoRefreshTimer != null) + { + _autoRefreshTimer.Stop(); + _autoRefreshTimer = null; + _isPaused = false; + Log.Information("订单自动刷新已停止"); + } + } + + /// + /// 自动刷新定时器回调:从MES获取最新订单,发现新订单时自动执行 + /// + private async void AutoRefreshTimerTick(object sender, EventArgs e) + { + try + { + if (string.IsNullOrEmpty(_currentLineName)) + return; + + //获取产线编号 + var deviceInfos = appConfig.deviceInfoConfig + .Where(x => x.Collectid == appConfig.StationCode && x.Name == _currentLineName && x.Deleteflag == 0) + .ToList(); + if (deviceInfos.Count == 0) + return; + + var lineno = deviceInfos[0].Addr; + + //从MES获取订单 + //调试用:从配置文件MockMesResponse读取模拟数据 + //var response = appConfig.MockMesResponse; + var response = await _httpclient.GetMesOrderInfo(lineno, DateTime.Now.ToString("yyyy-MM-dd")); + Log.Information($"自动刷新获取订单,产线:{_currentLineName},返回:{response}"); + + var responsejson = JsonSerializer.Deserialize>( + response, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + if (responsejson?.Code != 200 || responsejson.Data == null || responsejson.Data.Count == 0) + return; + + //查找新订单(数据库中不存在的) + var newOrders = new List(); + foreach (var item in responsejson.Data) + { + var existing = databaseService._helper.Query(x => x.OrderNo == item.OrderNo && x.ProductCode == item.ProductCode); + if (existing == null || existing.Count == 0) + { + newOrders.Add(item); + } + } + + if (newOrders.Count == 0) + return; + + //插入新订单到数据库并刷新界面 + foreach (var item in newOrders) + { + item.ID = Guid.NewGuid().ToString(); + item.InsertDate = DateTime.Now; + databaseService._helper.Insert(item); + Log.Information($"自动刷新发现新订单:{item.OrderNo},物料:{item.ProductCode},自动执行"); + } + + //刷新界面显示 + var items = databaseService._helper.QueryAll(); + items.Reverse(); + ChangeTypePanel.Clear(); + foreach (var item in items) + { + ChangeTypePanel.Add(item); + } + + //自动执行第一个新订单 + var firstNewOrder = newOrders[0]; + var deviceInfo = appConfig.deviceInfoConfig + .Where(x => x.Collectid == appConfig.StationCode && x.Name == _currentLineName && x.Deleteflag == 0) + .ToList(); + + if (deviceInfo.Count > 0) + { + var realData = new Real_DataInfo() + { + OrderNo = firstNewOrder.OrderNo, + Deviceid = deviceInfo[0].Deviceid, + LineName = _currentLineName, + LineNo = deviceInfo[0].Addr, + ProductType = firstNewOrder.ProductType, + RfidCount = firstNewOrder.PlanQty.ToString(), + NextProductNo = firstNewOrder.NextProductNo.ToString("D3") + }; + WeakReferenceMessenger.Default.Send(realData); + } + } + catch (Exception ex) + { + Log.Error($"订单自动刷新异常:{ex.Message}"); + } + } + + #endregion + } } -//0,新建 +//0, 新建 //1, 已审核 //2, 已下发 //3, 已接收 diff --git a/SlnMesnac.WPF/ViewModel/IndexPage/ProductionLineViewModel.cs b/SlnMesnac.WPF/ViewModel/IndexPage/ProductionLineViewModel.cs index 5d92567..8e672df 100644 --- a/SlnMesnac.WPF/ViewModel/IndexPage/ProductionLineViewModel.cs +++ b/SlnMesnac.WPF/ViewModel/IndexPage/ProductionLineViewModel.cs @@ -241,6 +241,7 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage + deviceInfo.NextProductNo + deviceInfo.SerialNo; CurrentState = "写入中"; + //上次读的EPC LastRFIDEPC = tagInfos[0].EPCstring; //写入前暂停心跳和连续盘点 @@ -248,6 +249,9 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage await rfidInfo.Set_HeartBeat(0); Task.Delay(100).Wait(); + //暂停订单自动刷新,防止写入过程中订单切换 + WeakReferenceMessenger.Default.Send(string.Empty, "PauseOrderRefresh"); + //处理写入字符串,并写入 //var originBytes = tagInfos[0].EPC.Where(b => b != 0x00).ToArray(); bool writeflag = rfidInfo.Set_Write(tagInfos[0].EPC, WriteData).GetAwaiter().GetResult(); @@ -415,6 +419,9 @@ namespace SlnMesnac.WPF.ViewModel.IndexPage LastRFIDEPC = ""; LastWrite = ""; + //写入完成,恢复订单自动刷新 + WeakReferenceMessenger.Default.Send(string.Empty, "ResumeOrderRefresh"); + await rfidInfo.Set_BeginIdentify(); await Task.Delay(100); StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value); diff --git a/SlnMesnac.WPF/appsettings.json b/SlnMesnac.WPF/appsettings.json index 55b5c4f..01703cd 100644 --- a/SlnMesnac.WPF/appsettings.json +++ b/SlnMesnac.WPF/appsettings.json @@ -125,7 +125,14 @@ "StationCode": "102", - "MESConfig": "10.20.8.61:8001" + "MESConfig": "10.20.8.61:8001", + + //是否启用订单自动刷新 + "AutoOrderRefresh": true, + //订单自动刷新间隔(秒) + "OrderRefreshInterval": 60, + //模拟MES返回数据(调试用,为空则走真实MES接口) + "MockMesResponse": "" }, "ProductConfig": { "OKCount": "0",