|
|
using CommunityToolkit.Mvvm.Input;
|
|
|
using CommunityToolkit.Mvvm.Messaging;
|
|
|
using GalaSoft.MvvmLight;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using NVelocity.Runtime.Directive;
|
|
|
using Serilog;
|
|
|
using SlnMesnac.Common;
|
|
|
using SlnMesnac.Config;
|
|
|
using SlnMesnac.Model.domain;
|
|
|
using SlnMesnac.Model.dto;
|
|
|
using SlnMesnac.Model.Enum;
|
|
|
using SlnMesnac.Repository;
|
|
|
using SlnMesnac.Repository.service;
|
|
|
using SlnMesnac.Repository.service.Impl;
|
|
|
using SlnMesnac.Rfid;
|
|
|
using SlnMesnac.Rfid.Enum;
|
|
|
using SlnMesnac.Serilog;
|
|
|
using SlnMesnac.TouchSocket;
|
|
|
using SlnMesnac.WPF.Attribute;
|
|
|
using SlnMesnac.WPF.Model;
|
|
|
using SqlSugar;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.ObjectModel;
|
|
|
using System.Data;
|
|
|
using System.Drawing;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Text.Json.Serialization;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
using System.Windows.Markup;
|
|
|
using System.Windows.Threading;
|
|
|
using System.Xml.Serialization;
|
|
|
using TouchSocket.Core;
|
|
|
using static Microsoft.WindowsAPICodePack.Shell.PropertySystem.SystemProperties.System;
|
|
|
using Task = System.Threading.Tasks.Task;
|
|
|
|
|
|
|
|
|
namespace SlnMesnac.WPF.ViewModel.IndexPage
|
|
|
{
|
|
|
[RegisterAsSingletonAttribute]
|
|
|
public class ProductionLineViewModel : ViewModelBase
|
|
|
{
|
|
|
#region 参数定义
|
|
|
|
|
|
private static StringChange _StringChange;
|
|
|
private String SerialNo = "";
|
|
|
private SerilogHelper _logger;
|
|
|
//private ISqlSugarClient? sqlSugarClient;
|
|
|
//容器里面的读写器集合
|
|
|
public List<RfidAbsractFactory> rfidList;
|
|
|
private AppConfig appConfig;
|
|
|
private MeshttpClient meshttpClient;
|
|
|
public TcpServer _TcpServer;
|
|
|
private DispatcherTimer _timer;
|
|
|
private Dictionary<string, DispatcherTimer> _inventoryTimers = new Dictionary<string, DispatcherTimer>();
|
|
|
private ObservableCollection<RFIDRecord> _rfidHistoryRecords = new ObservableCollection<RFIDRecord>();
|
|
|
private RealReadDataImpl databaseService = RealReadDataImpl.Instance;
|
|
|
private System.Threading.Timer ReReadTimer;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 每个设备的写入状态(支持多线并行)
|
|
|
/// </summary>
|
|
|
private class DeviceWriteState
|
|
|
{
|
|
|
public bool IsVerify;
|
|
|
public int WriteTime;
|
|
|
public string LastWrite = "";
|
|
|
public string Real_LastRFIDEPC = "";
|
|
|
public CancellationTokenSource? VerifyCts;
|
|
|
public CancellationTokenSource? WriteCts;
|
|
|
}
|
|
|
private Dictionary<string, DeviceWriteState> _deviceStates = new();
|
|
|
|
|
|
private DeviceWriteState GetDeviceState(string deviceId)
|
|
|
{
|
|
|
if (!_deviceStates.TryGetValue(deviceId, out var state))
|
|
|
{
|
|
|
state = new DeviceWriteState();
|
|
|
_deviceStates[deviceId] = state;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 关联属性
|
|
|
|
|
|
public ObservableCollection<RFIDRecord> RFIDHistoryRecords
|
|
|
{
|
|
|
get { return _rfidHistoryRecords; }
|
|
|
set
|
|
|
{
|
|
|
_rfidHistoryRecords = value;
|
|
|
RaisePropertyChanged(() => RFIDHistoryRecords);
|
|
|
}
|
|
|
}
|
|
|
ChangeTypeViewModel ChangeTypeView;
|
|
|
|
|
|
|
|
|
|
|
|
private ObservableCollection<Real_DataInfo> _Deviceinfo = new ObservableCollection<Real_DataInfo>();
|
|
|
public ObservableCollection<Real_DataInfo> Deviceinfo
|
|
|
{
|
|
|
get { return _Deviceinfo; }
|
|
|
set
|
|
|
{
|
|
|
_Deviceinfo = value;
|
|
|
RaisePropertyChanged(() => Deviceinfo);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 日期时间
|
|
|
/// </summary>
|
|
|
private DateTime _currentDateTime;
|
|
|
public DateTime CurrentDateTime
|
|
|
{
|
|
|
get => _currentDateTime;
|
|
|
set
|
|
|
{
|
|
|
if (_currentDateTime != value)
|
|
|
{
|
|
|
_currentDateTime = value;
|
|
|
RaisePropertyChanged(() => CurrentDateTime);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 上一次写入状态
|
|
|
/// </summary>
|
|
|
private string _lastWriteState;
|
|
|
public string LastWriteState
|
|
|
{
|
|
|
get => _lastWriteState;
|
|
|
set
|
|
|
{
|
|
|
if (_lastWriteState != value)
|
|
|
{
|
|
|
_lastWriteState = value;
|
|
|
RaisePropertyChanged(() => LastWriteState);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 当前状态 空闲 盘点中 写入中
|
|
|
/// </summary>
|
|
|
private string _CurrentState = "空闲";
|
|
|
public string CurrentState
|
|
|
{
|
|
|
get => _CurrentState;
|
|
|
set
|
|
|
{
|
|
|
if (_CurrentState != value)
|
|
|
{
|
|
|
_CurrentState = value;
|
|
|
RaisePropertyChanged(() => CurrentState);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 构造函数
|
|
|
|
|
|
public ProductionLineViewModel()
|
|
|
{
|
|
|
ChangeTypeView = App.ServiceProvider.GetService<ChangeTypeViewModel>();
|
|
|
// 构造函数里注册
|
|
|
WeakReferenceMessenger.Default.Register<Real_DataInfo>(this, RefreshOrderNo);
|
|
|
WeakReferenceMessenger.Default.Register<string, string>(this, "Cancel", StopMessage);
|
|
|
_StringChange = App.ServiceProvider.GetService<StringChange>();
|
|
|
_logger = App.ServiceProvider.GetService<SerilogHelper>();
|
|
|
appConfig = App.ServiceProvider.GetService<AppConfig>();
|
|
|
//sqlSugarClient = App.ServiceProvider.GetService<ISqlSugarClient>();
|
|
|
_TcpServer = App.ServiceProvider.GetRequiredService<TcpServer>();
|
|
|
rfidList = App.ServiceProvider.GetRequiredService<List<RfidAbsractFactory>>();
|
|
|
|
|
|
rfidList.ForEach(rfid =>
|
|
|
{
|
|
|
rfid._Action += RecvIdentifyData_Instance;
|
|
|
//rfid._RefreshLogMessageAction += RefreshLogMessage;
|
|
|
});
|
|
|
LoadDeviceInfo();
|
|
|
StartCheckStatus();
|
|
|
//GetRFIDHistoryRecords();
|
|
|
_currentDateTime = DateTime.Now;
|
|
|
_timer = new DispatcherTimer
|
|
|
{
|
|
|
Interval = TimeSpan.FromSeconds(1) // 每秒更新一次
|
|
|
};
|
|
|
_timer.Tick += (s, e) =>
|
|
|
{
|
|
|
CurrentDateTime = DateTime.Now;
|
|
|
};
|
|
|
_timer.Start();
|
|
|
|
|
|
Log.Information("RFID输送带系统启动");
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 核心写入算法
|
|
|
|
|
|
/// <summary>
|
|
|
/// 接收到连续盘点标签返回
|
|
|
/// </summary>
|
|
|
/// <param name="iCombineId"></param>
|
|
|
/// <param name="tagInfos"></param>
|
|
|
private async void RecvIdentifyData_Instance(string iCombineId, List<TagInfo> tagInfos)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
var state = GetDeviceState(iCombineId);
|
|
|
state.WriteCts?.Cancel();
|
|
|
var rfidInfo = rfidList.FirstOrDefault(x => x.deviceid == iCombineId);
|
|
|
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId);
|
|
|
var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == iCombineId);
|
|
|
//初次写入
|
|
|
if (!state.IsVerify)
|
|
|
{
|
|
|
//写入前等待标签稳定
|
|
|
if (!state.IsVerify)
|
|
|
{
|
|
|
await Task.Delay(deviceInfo.WriteDelaySet ?? 2000);
|
|
|
}
|
|
|
|
|
|
//验证是否已获取订单信息
|
|
|
if (string.IsNullOrEmpty(deviceInfo.OrderNo))
|
|
|
{
|
|
|
MessageBox.Show("请先获取MES订单号!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
//查询数据库是否已存在记录
|
|
|
string epcascii = Encoding.ASCII.GetString(tagInfos[0].EPC);
|
|
|
epcascii = epcascii.Replace("\0", "");
|
|
|
List<real_readdata> real_Readdatas = databaseService._helper.Query(x => x.rfidascii == epcascii);
|
|
|
|
|
|
//如果不存在则写入
|
|
|
if (real_Readdatas.Count <= 0)
|
|
|
//if (true)
|
|
|
{
|
|
|
//验证是否已获取序列号
|
|
|
if (string.IsNullOrEmpty(deviceInfo.SerialNo))
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
deviceInfo.ReadTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
//拼接订单号写入标签:OrderNo + 处理后的ProductOrder + 序号
|
|
|
string processedProductOrder = ProcessProductOrder(deviceInfo.ProductOrder);
|
|
|
string WriteData = deviceInfo.OrderNo + processedProductOrder + deviceInfo.SerialNo;
|
|
|
deviceInfo.CurrentState = "写入中";
|
|
|
//上次读的EPC
|
|
|
//LastRFIDEPC = tagInfos[0].EPCstring;
|
|
|
//保存最原始的EPC(仅第一次读取时保存,后续重试不覆盖)
|
|
|
if (string.IsNullOrEmpty(state.Real_LastRFIDEPC))
|
|
|
{
|
|
|
state.Real_LastRFIDEPC = tagInfos[0].EPCstring;
|
|
|
}
|
|
|
|
|
|
//写入前暂停心跳和连续盘点
|
|
|
StopInventoryTimer(iCombineId);
|
|
|
await rfidInfo.Set_HeartBeat(0);
|
|
|
await Task.Delay(100);
|
|
|
|
|
|
//暂停订单自动刷新,防止写入过程中订单切换
|
|
|
WeakReferenceMessenger.Default.Send(string.Empty, "PauseOrderRefresh");
|
|
|
|
|
|
//处理写入字符串,并写入
|
|
|
//var originBytes = tagInfos[0].EPC.Where(b => b != 0x00).ToArray();
|
|
|
bool writeflag = await rfidInfo.Set_Write(tagInfos[0].EPC, WriteData);
|
|
|
state.WriteTime++;
|
|
|
|
|
|
if (writeflag) //写入成功
|
|
|
{
|
|
|
state.LastWrite = WriteData;
|
|
|
state.IsVerify = true;
|
|
|
state.WriteTime = 0;
|
|
|
|
|
|
//开始二次验证
|
|
|
await rfidInfo.Set_BeginIdentify();
|
|
|
|
|
|
// 启动验证超时检测
|
|
|
state.VerifyCts?.Cancel();
|
|
|
state.VerifyCts = new CancellationTokenSource();
|
|
|
var token = state.VerifyCts.Token;
|
|
|
var capturedTagInfos = tagInfos;
|
|
|
var timeoutMs = deviceConfig.VerifyTimeoutMilliseconds ?? 20000;
|
|
|
_ = Task.Run(async () =>
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
await Task.Delay(timeoutMs, token);
|
|
|
Log.Error($"二次验证超时未读到标签,标签已离开,记为写入失败");
|
|
|
await DataAdd(iCombineId, capturedTagInfos, false);
|
|
|
}
|
|
|
catch (TaskCanceledException) { }
|
|
|
}, token);
|
|
|
|
|
|
//开启定时盘点和心跳
|
|
|
StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
|
|
|
await rfidInfo.Set_HeartBeat(5);
|
|
|
return;
|
|
|
}
|
|
|
else //写入失败
|
|
|
{
|
|
|
Log.Error($"第{state.WriteTime + 1}次写入失败,重试中...");
|
|
|
//重试前再读取一次标签
|
|
|
await rfidInfo.Set_BeginIdentify();
|
|
|
|
|
|
//设置下次读取超时
|
|
|
state.WriteCts?.Cancel();
|
|
|
state.WriteCts = new CancellationTokenSource();
|
|
|
var token = state.WriteCts.Token;
|
|
|
var capturedTagInfos = tagInfos;
|
|
|
var timeoutMs = deviceConfig.WriteTimeoutMilliseconds ?? 10000;
|
|
|
_ = Task.Run(async () =>
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
await Task.Delay(timeoutMs, token);
|
|
|
Log.Error($"写入前读取超时,[{tagInfos[0].EPCstring}] 记为写入失败");
|
|
|
await DataAdd(iCombineId, capturedTagInfos, false);
|
|
|
state.WriteTime = 0;
|
|
|
}
|
|
|
catch (TaskCanceledException) { }
|
|
|
}, token);
|
|
|
|
|
|
StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
|
|
|
await rfidInfo.Set_HeartBeat(5);
|
|
|
await Task.Delay(100);
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
await Task.Run(async () =>
|
|
|
{
|
|
|
await Task.Delay(1000);
|
|
|
await rfidInfo!.Set_BeginIdentify();
|
|
|
deviceInfo.CurrentState = "盘点中";
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
else //二次验证流程
|
|
|
{
|
|
|
var judgeString = Encoding.ASCII.GetString(tagInfos[0].EPC);
|
|
|
judgeString = judgeString.Replace("\0", "");
|
|
|
//二次验证如果不通过 重新开始盘点
|
|
|
if (judgeString != state.LastWrite)
|
|
|
{
|
|
|
// 读到标签但数据不匹配,重置超时(标签仍在天线范围内)
|
|
|
state.VerifyCts?.Cancel();
|
|
|
state.VerifyCts = new CancellationTokenSource();
|
|
|
var token = state.VerifyCts.Token;
|
|
|
var capturedTagInfos = tagInfos;
|
|
|
var timeoutMs = deviceConfig?.VerifyTimeoutMilliseconds ?? 20000;
|
|
|
_ = Task.Run(async () =>
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
await Task.Delay(timeoutMs, token);
|
|
|
Log.Error($"二次验证超时写入标签超时,标签已离开,记为写入失败");
|
|
|
await DataAdd(iCombineId, capturedTagInfos, false);
|
|
|
}
|
|
|
catch (TaskCanceledException) { }
|
|
|
}, token);
|
|
|
|
|
|
state.IsVerify = false;
|
|
|
//state.Real_LastRFIDEPC = LastRFIDEPC;
|
|
|
rfidInfo.Set_BeginIdentify().GetAwaiter().GetResult();
|
|
|
deviceInfo.CurrentState = "盘点中";
|
|
|
return;
|
|
|
}
|
|
|
else //二次验证通过
|
|
|
{
|
|
|
state.VerifyCts?.Cancel();
|
|
|
Log.Information($"验证成功");
|
|
|
//插入成功记录
|
|
|
await DataAdd(iCombineId, tagInfos, true);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
Log.Error($"读结果准备写入时异常:{e.Message}");
|
|
|
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId);
|
|
|
if (deviceInfo != null)
|
|
|
deviceInfo.CurrentState = "空闲";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 插入记录
|
|
|
/// </summary>
|
|
|
/// <param name="iCombineId"></param>
|
|
|
/// <param name="tagInfos"></param>
|
|
|
/// <param name="isSuccess"></param>
|
|
|
private async Task DataAdd(string iCombineId, List<TagInfo> tagInfos, bool isSuccess)
|
|
|
{
|
|
|
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId);
|
|
|
var rfidInfo = rfidList.FirstOrDefault(x => x.deviceid == iCombineId);
|
|
|
var state = GetDeviceState(iCombineId);
|
|
|
|
|
|
var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == iCombineId);
|
|
|
state.IsVerify = false;
|
|
|
deviceInfo.WriteTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
deviceInfo.WriteStatus = isSuccess ? "成功" : "失败";
|
|
|
deviceInfo.LastWriteState = isSuccess ? "成功" : "失败";
|
|
|
deviceInfo.RfidASCII = state.LastWrite;
|
|
|
deviceInfo.RfidEPC = state.Real_LastRFIDEPC;
|
|
|
deviceInfo.SerialNo = (Convert.ToInt32(deviceInfo.SerialNo) + 1).ToString("D2");
|
|
|
//更新下一个要写入的EPC预览
|
|
|
deviceInfo.NextWriteEPC = deviceInfo.OrderNo + ProcessProductOrder(deviceInfo.ProductOrder) + deviceInfo.SerialNo;
|
|
|
//保存写入记录
|
|
|
real_readdata real_Readdata = new real_readdata()
|
|
|
{
|
|
|
objid = Guid.NewGuid().ToString(),
|
|
|
serialno = (Convert.ToInt32(deviceInfo.SerialNo) - 1).ToString("D2"),
|
|
|
orderno = deviceInfo.OrderNo,
|
|
|
lineno = deviceInfo.LineNo,
|
|
|
producttype = deviceInfo.ProductType,
|
|
|
productorder = ProcessProductOrder(deviceInfo.ProductOrder),
|
|
|
rfidepc = deviceInfo.RfidEPC,
|
|
|
rfidascii = state.LastWrite,
|
|
|
readtime = Convert.ToDateTime(deviceInfo.ReadTime),
|
|
|
writetime = Convert.ToDateTime(deviceInfo.WriteTime),
|
|
|
writestatus = deviceInfo.WriteStatus
|
|
|
};
|
|
|
|
|
|
//插入到数据库历史记录中
|
|
|
var a = databaseService._helper.Insert(real_Readdata);
|
|
|
|
|
|
//插入记录到首页临时数据显示
|
|
|
AddRFIDData(iCombineId, tagInfos);
|
|
|
|
|
|
//LastRFIDEPC = "";
|
|
|
state.Real_LastRFIDEPC = "";
|
|
|
state.LastWrite = "";
|
|
|
|
|
|
//写入完成,恢复订单自动刷新
|
|
|
WeakReferenceMessenger.Default.Send(string.Empty, "ResumeOrderRefresh");
|
|
|
|
|
|
await rfidInfo.Set_BeginIdentify();
|
|
|
await Task.Delay(100);
|
|
|
StartInventoryTimer(iCombineId, deviceConfig.InventoryIntervalSeconds.Value);
|
|
|
await rfidInfo.Set_HeartBeat(5);
|
|
|
deviceInfo.CurrentState = "盘点中";
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 处理ProductOrder:去掉前导字母和中间的"-"
|
|
|
/// 例:"GS426-0250" → "4260250","GSW426-0250" → "4260250"
|
|
|
/// </summary>
|
|
|
private static string ProcessProductOrder(string productOrder)
|
|
|
{
|
|
|
if (string.IsNullOrEmpty(productOrder))
|
|
|
return "";
|
|
|
return System.Text.RegularExpressions.Regex.Replace(productOrder, @"^[A-Za-z]+|-", "");
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 数据流相关
|
|
|
|
|
|
/// <summary>
|
|
|
/// 开始订单初次流程
|
|
|
/// </summary>
|
|
|
/// <param name="recipient"></param>
|
|
|
/// <param name="real_Data"></param>
|
|
|
private void RefreshOrderNo(object recipient, Real_DataInfo real_Data)
|
|
|
{
|
|
|
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid);
|
|
|
var deviceConfig = appConfig.deviceInfoConfig.FirstOrDefault(x => x.Deviceid == real_Data.Deviceid);
|
|
|
|
|
|
//检测OrderNo或ProductOrder是否发生变化,变化则重置计数器
|
|
|
bool orderChanged = deviceInfo.OrderNo != real_Data.OrderNo
|
|
|
|| deviceInfo.ProductOrder != real_Data.ProductOrder;
|
|
|
|
|
|
if (orderChanged)
|
|
|
{
|
|
|
//查询当前订单+产品订单下的最大序列号
|
|
|
string processedPo = ProcessProductOrder(real_Data.ProductOrder);
|
|
|
List<real_readdata> real_Readdatas = databaseService._helper.Query(x =>
|
|
|
x.orderno == real_Data.OrderNo && x.productorder == processedPo);
|
|
|
string SNo = "";
|
|
|
if (real_Readdatas.Count > 0)
|
|
|
{
|
|
|
SNo = real_Readdatas.Max(x => x.serialno);
|
|
|
SNo = (Convert.ToInt32(SNo) + 1).ToString("D2");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
SNo = "01";
|
|
|
}
|
|
|
deviceInfo.SerialNo = SNo;
|
|
|
}
|
|
|
|
|
|
deviceInfo.OrderNo = real_Data.OrderNo;
|
|
|
deviceInfo.ProductType = real_Data.ProductType;
|
|
|
deviceInfo.LineNo = real_Data.LineNo;
|
|
|
deviceInfo.RfidCount = real_Data.RfidCount;
|
|
|
deviceInfo.NextProductNo = real_Data.NextProductNo;
|
|
|
deviceInfo.ProductOrder = real_Data.ProductOrder;
|
|
|
|
|
|
//更新下一个要写入的EPC预览
|
|
|
deviceInfo.NextWriteEPC = deviceInfo.OrderNo + ProcessProductOrder(deviceInfo.ProductOrder) + deviceInfo.SerialNo;
|
|
|
|
|
|
rfidList.FirstOrDefault(x => x.deviceid == real_Data.Deviceid).Set_BeginIdentify().GetAwaiter().GetResult();
|
|
|
var state = GetDeviceState(real_Data.Deviceid);
|
|
|
state.IsVerify = false;
|
|
|
state.Real_LastRFIDEPC = "";
|
|
|
deviceInfo.CurrentState = "盘点中";
|
|
|
|
|
|
// 启动定时盘点
|
|
|
if (deviceConfig?.InventoryIntervalSeconds > 0)
|
|
|
{
|
|
|
StartInventoryTimer(real_Data.Deviceid, deviceConfig.InventoryIntervalSeconds.Value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 停止盘点消息
|
|
|
/// </summary>
|
|
|
private void StopMessage(object o, string e)
|
|
|
{
|
|
|
var rfid = rfidList.FirstOrDefault(x => x.deviceid == e);
|
|
|
StopInventoryTimer(e);
|
|
|
|
|
|
var res = rfid.Set_StopIdentify().GetAwaiter().GetResult();
|
|
|
if (res)
|
|
|
{
|
|
|
MessageBox.Show("停止盘点成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
MessageBox.Show("停止盘点失败!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
}
|
|
|
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == e);
|
|
|
if (deviceInfo != null)
|
|
|
deviceInfo.CurrentState = "空闲";
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 初次加载设备信息
|
|
|
/// </summary>
|
|
|
private void LoadDeviceInfo()
|
|
|
{
|
|
|
List<DeviceInfoConfig> DeviceInfos = appConfig.deviceInfoConfig.Where(x => x.Collectid == appConfig.StationCode && x.Deleteflag == 0).ToList();
|
|
|
List<Real_DataInfo> real_DataInfos = new List<Real_DataInfo>();
|
|
|
|
|
|
foreach (var item in DeviceInfos)
|
|
|
{
|
|
|
Real_DataInfo real_DataInfo = new Real_DataInfo()
|
|
|
{
|
|
|
Name = item.Name,
|
|
|
Deviceid = item.Deviceid,
|
|
|
Connectstr = item.Connectstr,
|
|
|
LineName = item.Name,
|
|
|
LineNo = item.Addr,
|
|
|
OrderNo = "",
|
|
|
ProductType = "",
|
|
|
WriteCount = "",
|
|
|
RfidCount = "",
|
|
|
IsOnline = "未连接",
|
|
|
RfidASCII = "",
|
|
|
RfidEPC = "",
|
|
|
ReadTime = "",
|
|
|
WriteTime = "",
|
|
|
ProductStatus = "",
|
|
|
WriteStatus = "",
|
|
|
WriteDelaySet = item.WriteDelaySet
|
|
|
};
|
|
|
real_DataInfos.Add(real_DataInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
App.Current.Dispatcher.Invoke(() =>
|
|
|
{
|
|
|
Deviceinfo.Clear();
|
|
|
|
|
|
foreach (var item in real_DataInfos)
|
|
|
{
|
|
|
Real_DataInfo real_DataInfo = new Real_DataInfo()
|
|
|
{
|
|
|
Name = item.Name,
|
|
|
Deviceid = item.Deviceid,
|
|
|
Connectstr = item.Connectstr,
|
|
|
LineName = item.Name,
|
|
|
LineNo = item.LineNo,
|
|
|
OrderNo = item.OrderNo,
|
|
|
ProductType = item.ProductType,
|
|
|
WriteCount = item.WriteCount,
|
|
|
RfidCount = item.RfidCount,
|
|
|
IsOnline = item.IsOnline,
|
|
|
RfidASCII = item.RfidASCII,
|
|
|
ReadTime = item.ReadTime,
|
|
|
WriteTime = item.WriteTime,
|
|
|
ProductStatus = item.ProductStatus,
|
|
|
WriteStatus = item.WriteStatus,
|
|
|
RfidEPC = item.RfidEPC,
|
|
|
WriteDelaySet = item.WriteDelaySet
|
|
|
};
|
|
|
Deviceinfo.Add(real_DataInfo);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 添加数据的方法
|
|
|
/// </summary>
|
|
|
/// <param name="iCombineId"></param>
|
|
|
/// <param name="tagInfos"></param>
|
|
|
public void AddRFIDData(string iCombineId, List<TagInfo> tagInfos)
|
|
|
{
|
|
|
Task.Run(() =>
|
|
|
{
|
|
|
App.Current.Dispatcher.Invoke(() =>
|
|
|
{
|
|
|
var deviceInfo = Deviceinfo.FirstOrDefault(x => x.Deviceid == iCombineId);
|
|
|
if (deviceInfo == null) return;
|
|
|
RFIDHistoryRecords.Insert(0, new RFIDRecord
|
|
|
{
|
|
|
OrderNumber = deviceInfo.OrderNo,
|
|
|
LineNumber = deviceInfo.LineNo,
|
|
|
ProductType = deviceInfo.ProductType,
|
|
|
OriginalEPC = deviceInfo.RfidEPC,
|
|
|
RFIDCode = deviceInfo.RfidASCII,
|
|
|
ReadTime = deviceInfo.ReadTime,
|
|
|
WriteTime = deviceInfo.ReadTime,
|
|
|
WriteStatus = deviceInfo.WriteStatus,
|
|
|
DeviceId = iCombineId
|
|
|
});
|
|
|
//更新过滤后的历史记录
|
|
|
RefreshFilteredRecords();
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 当前选中的设备ID(Tab切换时更新)
|
|
|
/// </summary>
|
|
|
private string? _selectedDeviceId;
|
|
|
public string? SelectedDeviceId
|
|
|
{
|
|
|
get => _selectedDeviceId;
|
|
|
set
|
|
|
{
|
|
|
if (_selectedDeviceId != value)
|
|
|
{
|
|
|
_selectedDeviceId = value;
|
|
|
RaisePropertyChanged(() => SelectedDeviceId);
|
|
|
RefreshFilteredRecords();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private ObservableCollection<RFIDRecord> _filteredRFIDHistoryRecords = new();
|
|
|
/// <summary>
|
|
|
/// 按选中设备过滤后的RFID历史记录
|
|
|
/// </summary>
|
|
|
public ObservableCollection<RFIDRecord> FilteredRFIDHistoryRecords
|
|
|
{
|
|
|
get => _filteredRFIDHistoryRecords;
|
|
|
set
|
|
|
{
|
|
|
_filteredRFIDHistoryRecords = value;
|
|
|
RaisePropertyChanged(() => FilteredRFIDHistoryRecords);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void RefreshFilteredRecords()
|
|
|
{
|
|
|
var filtered = string.IsNullOrEmpty(_selectedDeviceId)
|
|
|
? RFIDHistoryRecords.ToList()
|
|
|
: RFIDHistoryRecords.Where(x => x.DeviceId == _selectedDeviceId).ToList();
|
|
|
FilteredRFIDHistoryRecords.Clear();
|
|
|
foreach (var item in filtered)
|
|
|
{
|
|
|
FilteredRFIDHistoryRecords.Add(item);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 设备状态检测
|
|
|
|
|
|
private void StartCheckStatus()
|
|
|
{
|
|
|
Task.Run(async () =>
|
|
|
{
|
|
|
while (true)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
#region RFID状态
|
|
|
//RefreshLogMessage("检测设备状态");
|
|
|
var batches = SplitListIntoBatches(rfidList, 10);
|
|
|
for (int i = 0; i < batches.Count; i++)
|
|
|
{
|
|
|
var currentBatch = batches[i];
|
|
|
// 显示当前批次信息(UI线程)
|
|
|
Console.WriteLine($"{DateTime.Now}开始检测第{i + 1}批(共{currentBatch.Count}个设备)\r\n");
|
|
|
|
|
|
// 异步检测当前批次的设备状态(不阻塞UI)
|
|
|
await DetectDeviceBatchAsync(currentBatch);
|
|
|
|
|
|
// 批次之间的间隔(最后一批无需等待)
|
|
|
if (i < batches.Count - 1)
|
|
|
{
|
|
|
Console.WriteLine($"{DateTime.Now}第{i + 1}批检测完成,共{batches.Count}批,等待{1000 / 1000}秒后检测下一批\r\n");
|
|
|
await Task.Delay(10);
|
|
|
}
|
|
|
}
|
|
|
#endregion RFID状态
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Log.Information($"监听设备状态异常:{ex.Message}");
|
|
|
}
|
|
|
await Task.Delay(1000 * 20);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
private List<List<RfidAbsractFactory>> SplitListIntoBatches(List<RfidAbsractFactory> sourceList, int batchSize)
|
|
|
{
|
|
|
var batches = new List<List<RfidAbsractFactory>>();
|
|
|
for (int i = 0; i < sourceList.Count; i += batchSize)
|
|
|
{
|
|
|
// 截取每批的设备(最后一批可能不足10个)
|
|
|
var batch = sourceList.Skip(i).Take(batchSize).ToList();
|
|
|
batches.Add(batch);
|
|
|
}
|
|
|
return batches;
|
|
|
}
|
|
|
|
|
|
private async Task DetectDeviceBatchAsync(List<RfidAbsractFactory> batch)
|
|
|
{
|
|
|
// 并行检测当前批次的设备(可选,根据接口性能调整)
|
|
|
var detectionTasks = batch.Select(device => DetectSingleDeviceAsync(device));
|
|
|
// 等待当前批次所有设备检测完成
|
|
|
await Task.WhenAll(detectionTasks);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 重连核心算法
|
|
|
/// </summary>
|
|
|
/// <param name="device"></param>
|
|
|
/// <returns></returns>
|
|
|
private async Task DetectSingleDeviceAsync(RfidAbsractFactory device)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
//基于心跳检测的断线重连机制
|
|
|
if (GloalVar.HeartBeatRecoard.TryGetValue(device.deviceid, out var value))
|
|
|
{
|
|
|
if (value.AddSeconds(15) < DateTime.Now)
|
|
|
{
|
|
|
await Reconnect(device);
|
|
|
Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "已连接";
|
|
|
}
|
|
|
}
|
|
|
else //第一次的逻辑
|
|
|
{
|
|
|
await Reconnect(device);
|
|
|
Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "已连接";
|
|
|
var res = false;
|
|
|
//无限获取心跳返回报文
|
|
|
Log.Information($"准备第一次获取心跳");
|
|
|
res = await device.Set_HeartBeat(5);
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Log.Information($"更新RFID状态异常:{ex.Message}", ex);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 无限重连
|
|
|
/// </summary>
|
|
|
/// <param name="device"></param>
|
|
|
/// <returns></returns>
|
|
|
private async Task Reconnect(RfidAbsractFactory device)
|
|
|
{
|
|
|
var res = false;
|
|
|
do
|
|
|
{
|
|
|
await Task.Delay(1000);
|
|
|
Deviceinfo.FirstOrDefault(x => x.Deviceid == device.deviceid).IsOnline = "未连接";
|
|
|
Log.Information($"[{device.deviceid}]:[{device.ip}:{device.port}]连接中...");
|
|
|
res = await device.ConnectAsync(device.ip, device.port, device.deviceid);
|
|
|
}
|
|
|
while (!res);
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 定时盘点
|
|
|
|
|
|
/// <summary>
|
|
|
/// 启动定时盘点
|
|
|
/// </summary>
|
|
|
private void StartInventoryTimer(string deviceId, int intervalSeconds)
|
|
|
{
|
|
|
StopInventoryTimer(deviceId);
|
|
|
var timer = new DispatcherTimer
|
|
|
{
|
|
|
Interval = TimeSpan.FromMilliseconds(intervalSeconds)
|
|
|
};
|
|
|
timer.Tick += (s, e) => OnInventoryTimerTick(deviceId);
|
|
|
timer.Start();
|
|
|
//OnInventoryTimerTick(deviceId);
|
|
|
_inventoryTimers[deviceId] = timer;
|
|
|
Log.Information($"设备 {deviceId} 启动定时盘点,间隔 {intervalSeconds} ms");
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 停止定时盘点
|
|
|
/// </summary>
|
|
|
private void StopInventoryTimer(string deviceId)
|
|
|
{
|
|
|
if (_inventoryTimers.TryGetValue(deviceId, out var timer))
|
|
|
{
|
|
|
timer.Stop();
|
|
|
_inventoryTimers.Remove(deviceId);
|
|
|
Log.Information($"设备 {deviceId} 停止定时盘点");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 定时盘点回调
|
|
|
/// </summary>
|
|
|
private async void OnInventoryTimerTick(string deviceId)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
var rfid = rfidList.FirstOrDefault(x => x.deviceid == deviceId);
|
|
|
if (rfid != null)
|
|
|
{
|
|
|
//Log.Information($"设备 {deviceId} 执行定时盘点");
|
|
|
//await rfid.Set_StopIdentify();
|
|
|
//await Task.Delay(100);
|
|
|
await rfid.Set_BeginIdentify();
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Log.Error($"设备 {deviceId} 定时盘点异常: {ex.Message}");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
}
|
|
|
}
|