添加项目文件。
This commit is contained in:
510
MoviconHub.App/Services/DBServices.cs
Normal file
510
MoviconHub.App/Services/DBServices.cs
Normal file
@@ -0,0 +1,510 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MoviconHub.App.Models;
|
||||
using NLog;
|
||||
|
||||
namespace MoviconHub.App.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Db Server
|
||||
/// </summary>
|
||||
public class DBServices : IDisposable
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
private Timer _dataPollingTimer;
|
||||
private readonly object _lockObject = new object();
|
||||
private bool _isRunning = false;
|
||||
private int _pollingInterval = 1000; // 默认轮询间隔1秒
|
||||
private WebSocketData _realtimeData;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// 实时数据对象,用于缓存从RTVar表中读取的数据
|
||||
/// </summary>
|
||||
public WebSocketData RealtimeData
|
||||
{
|
||||
get { return _realtimeData; }
|
||||
}
|
||||
|
||||
public SglModel SglModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 实时数据更新事件
|
||||
/// </summary>
|
||||
public event EventHandler<WebSocketData> DataUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化数据库服务
|
||||
/// </summary>
|
||||
public DBServices(SglModel sglModel)
|
||||
{
|
||||
_realtimeData = new WebSocketData();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
SglModel = sglModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始实时数据轮询
|
||||
/// </summary>
|
||||
/// <param name="interval">轮询间隔,单位毫秒</param>
|
||||
/// <returns>是否成功启动</returns>
|
||||
public bool StartPolling(int interval = 2000)
|
||||
{
|
||||
if (_isRunning)
|
||||
return false;
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_isRunning)
|
||||
return false;
|
||||
|
||||
_pollingInterval = interval;
|
||||
_isRunning = true;
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
// 使用Task来轮询数据
|
||||
Task.Run(async () => await PollDataAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
|
||||
|
||||
Logger.Info($"实时数据轮询已启动,间隔: {_pollingInterval}ms");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止实时数据轮询
|
||||
/// </summary>
|
||||
public void StopPolling()
|
||||
{
|
||||
if (!_isRunning)
|
||||
return;
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (!_isRunning)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource.Cancel();
|
||||
_isRunning = false;
|
||||
Logger.Info("实时数据轮询已停止");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步轮询数据任务
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消标记</param>
|
||||
private async Task PollDataAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取RTVar表数据
|
||||
await ReadRTVarDataAsync();
|
||||
|
||||
// 等待指定的轮询间隔
|
||||
await Task.Delay(_pollingInterval, cancellationToken);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// 任务被取消,正常退出
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "轮询RTVar数据时发生错误");
|
||||
// 发生错误时,等待一段时间后重试
|
||||
await Task.Delay(5000, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取RTVar表数据
|
||||
/// </summary>
|
||||
private async Task ReadRTVarDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 使用FSqlContext封装的FreeSql调用DB数据
|
||||
var rtVars = await FSqlContext.FDb.Select<RTVar>().ToListAsync();
|
||||
|
||||
// 更新实时数据对象
|
||||
UpdateWebSocketData(rtVars);
|
||||
|
||||
// 触发数据更新事件
|
||||
//DataUpdated?.Invoke(this, _realtimeData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex, "读取RTVar数据时发生错误");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用RTVar数据更新WebSocketData模型
|
||||
/// </summary>
|
||||
/// <param name="rtVars">RTVar数据列表</param>
|
||||
private void UpdateWebSocketData(List<RTVar> rtVars)
|
||||
{
|
||||
if (rtVars == null || rtVars.Count == 0)
|
||||
return;
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
|
||||
// 更新设备状态信息
|
||||
var deviceCodeVar = rtVars.FirstOrDefault(v => v.Name == "Device_Code");
|
||||
if (deviceCodeVar != null)
|
||||
_realtimeData.Device_Code = deviceCodeVar.Val;
|
||||
|
||||
var deviceNameVar = rtVars.FirstOrDefault(v => v.Name == "Device_Name");
|
||||
if (deviceNameVar != null)
|
||||
_realtimeData.Device_Name = deviceNameVar.Val;
|
||||
|
||||
var deviceManufacturerVar = rtVars.FirstOrDefault(v => v.Name == "Device_Manufacturer");
|
||||
if (deviceManufacturerVar != null)
|
||||
_realtimeData.Device_Manufacturer = deviceManufacturerVar.Val;
|
||||
|
||||
var statusVar = rtVars.FirstOrDefault(v => v.Name == "Device_Status");
|
||||
if (statusVar != null)
|
||||
_realtimeData.Device_Status = statusVar.Val;
|
||||
|
||||
// 解析故障信息
|
||||
UpdateFaultDetails(rtVars);
|
||||
|
||||
// 解析组件信息
|
||||
UpdateComponentsInfo(rtVars);
|
||||
|
||||
// 解析测试数据
|
||||
UpdateTestData(rtVars);
|
||||
|
||||
//获取条码信息,确定是否需要搜索数据
|
||||
SglModel.CodeReady = rtVars.FirstOrDefault(v => v.Name == "part_qrid").Val;
|
||||
|
||||
UpdateRemoteDb(RealtimeData);
|
||||
|
||||
//把最新的数据赋值给WebSocketClient中
|
||||
WebSocketClientHelper.CurWebSocketData = RealtimeData;
|
||||
|
||||
//更新数据到远程数据库
|
||||
|
||||
// 记录日志
|
||||
Logger.Debug("实时数据已更新");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新远程数据库
|
||||
/// </summary>
|
||||
/// <param name="webSocketData"></param>
|
||||
private void UpdateRemoteDb(WebSocketData webSocketData)
|
||||
{
|
||||
// 获取组件信息
|
||||
var component = webSocketData.ListComponentsInfo?.FirstOrDefault();
|
||||
|
||||
// 创建CurRunClearState对象并映射数据
|
||||
var curRunClearState = new CurRunClearState()
|
||||
{
|
||||
//只有一个,更新数据
|
||||
Id = 1,
|
||||
|
||||
// 基本信息
|
||||
DeviceCode = webSocketData.Device_Code,
|
||||
DeviceName = webSocketData.Device_Name,
|
||||
|
||||
// 组件信息
|
||||
part_qrid = component?.part_qrid,
|
||||
part_num = component?.part_num,
|
||||
part_position = component?.part_position,
|
||||
component_name = component?.part_name,
|
||||
vehicle_model = component?.part_Vehicle_model,
|
||||
locomotive_number = component?.part_locomotive_number,
|
||||
repair_process = component?.part_repair_process,
|
||||
|
||||
program_process = webSocketData.TestData.Test_FrameworkProgramProcess,
|
||||
|
||||
// 程序进程
|
||||
Test_FrameworkProgramProcess = webSocketData.TestData.Test_FrameworkProgramProcess,
|
||||
Test_FrameworkProgramProcessPercentage = webSocketData.TestData.Test_FrameworkProgramProcessPercentage,
|
||||
|
||||
// 设备状态
|
||||
Test_PartsEquipmentStatus = webSocketData.TestData.Test_PartsEquipmentStatus,
|
||||
|
||||
// 清洗时长和用量
|
||||
Test_FrameworkPerModelCleaningDuration = webSocketData.TestData.Test_FrameworkPerModelCleaningDuration,
|
||||
Test_FrameworkPerModelCleaningAgentUsage = webSocketData.TestData.Test_FrameworkPerModelCleaningAgentUsage,
|
||||
Test_FrameworkPerModelWaterUsage = webSocketData.TestData.Test_FrameworkPerModelWaterUsage,
|
||||
|
||||
// 水箱和清洗剂罐信息
|
||||
WaterTank_Temp = webSocketData.TestData.Test_WaterTankTemperature,
|
||||
AgentTank_Temp = webSocketData.TestData.Test_CleaningAgentTankTemperature,
|
||||
WaterTank_Level = webSocketData.TestData.Test_WaterTankLevel,
|
||||
AgentTank_Level = webSocketData.TestData.Test_CleaningAgentTankLevel,
|
||||
|
||||
// 浸泡池温度
|
||||
SoakingTank1_Temp = webSocketData.TestData.Test_SoakingTank1Temperature,
|
||||
SoakingTank2_Temp = webSocketData.TestData.Test_SoakingTank2Temperature,
|
||||
|
||||
// 运行模式
|
||||
Test_WaterTankHeat = webSocketData.TestData.Test_WaterTankHeat,
|
||||
Test_WaterTankAdd = webSocketData.TestData.Test_WaterTankAdd,
|
||||
Test_CleaningAgentTankHeat = webSocketData.TestData.Test_CleaningAgentTankHeat,
|
||||
Test_CleaningAgentTankAdd = webSocketData.TestData.Test_CleaningAgentTankAdd,
|
||||
|
||||
// 监控信息
|
||||
Test_ElectricSurveillance = webSocketData.TestData.Test_ElectricSurveillance,
|
||||
Test_SteamSurveillance = webSocketData.TestData.Test_SteamSurveillance
|
||||
};
|
||||
|
||||
var Data = FRemoteSqlContext.FDb
|
||||
.InsertOrUpdate<CurRunClearState>()
|
||||
.SetSource(curRunClearState)
|
||||
.ExecuteAffrows();
|
||||
|
||||
if (Data > 0)
|
||||
{
|
||||
Logger.Debug("实时数据已更新到远程数据库");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新故障信息
|
||||
/// </summary>
|
||||
/// <param name="rtVars">RTVar数据列表</param>
|
||||
private void UpdateFaultDetails(List<RTVar> rtVars)
|
||||
{
|
||||
var hasFault = rtVars.FirstOrDefault(v => v.Name.Contains("Fault_"));
|
||||
if (hasFault != null && !string.IsNullOrEmpty(hasFault.Val))
|
||||
{
|
||||
if (_realtimeData.FaultDetails == null)
|
||||
_realtimeData.FaultDetails = new FaultDetails();
|
||||
|
||||
var faultDevice = rtVars.FirstOrDefault(v => v.Name == "Fault_Code");
|
||||
if (faultDevice != null)
|
||||
_realtimeData.FaultDetails.Fault_Code = faultDevice.Val;
|
||||
|
||||
var faultTime = rtVars.FirstOrDefault(v => v.Name == "Fault_Time");
|
||||
if (faultTime != null && DateTime.TryParse(faultTime.Val, out DateTime time))
|
||||
_realtimeData.FaultDetails.Fault_Time = time;
|
||||
|
||||
var faultDescription = rtVars.FirstOrDefault(v => v.Name == "Fault_Description");
|
||||
if (faultDescription != null)
|
||||
_realtimeData.FaultDetails.Fault_Description = faultDescription.Val;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有故障时,置空故障信息
|
||||
_realtimeData.FaultDetails = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新组件信息
|
||||
/// </summary>
|
||||
/// <param name="rtVars">RTVar数据列表</param>
|
||||
private void UpdateComponentsInfo(List<RTVar> rtVars)
|
||||
{
|
||||
var componentsCountVar = rtVars.FirstOrDefault(v => v.Name.Contains("part_"));
|
||||
if (componentsCountVar != null)
|
||||
{
|
||||
if (_realtimeData.ListComponentsInfo == null) _realtimeData.ListComponentsInfo = new List<ComponentsInfo>() { new ComponentsInfo() };
|
||||
|
||||
//else
|
||||
// _realtimeData.ListComponentsInfo.Clear();
|
||||
|
||||
var component = _realtimeData.ListComponentsInfo.FirstOrDefault();
|
||||
|
||||
//var partQRCode = rtVars.FirstOrDefault(v => v.Name == $"part_qrid");
|
||||
//if (partQRCode != null)
|
||||
// component.part_qrid = partQRCode.Val;
|
||||
|
||||
var partNum = rtVars.FirstOrDefault(v => v.Name == $"part_num");
|
||||
if (partNum != null)
|
||||
component.part_num = partNum.Val;
|
||||
|
||||
var partPosition = rtVars.FirstOrDefault(v => v.Name == $"part_position");
|
||||
if (partPosition != null)
|
||||
component.part_position = partPosition.Val;
|
||||
|
||||
var componentName = rtVars.FirstOrDefault(v => v.Name == $"part_name");
|
||||
if (componentName != null)
|
||||
component.part_name = componentName.Val;
|
||||
|
||||
// 车型
|
||||
var vehicleModel = rtVars.FirstOrDefault(v => v.Name == $"part_Vehicle_model");
|
||||
if (vehicleModel != null)
|
||||
component.part_Vehicle_model = vehicleModel.Val;
|
||||
|
||||
// 车号
|
||||
var locomotiveNumber = rtVars.FirstOrDefault(v => v.Name == $"part_locomotive_number");
|
||||
if (locomotiveNumber != null)
|
||||
component.part_locomotive_number = locomotiveNumber.Val;
|
||||
|
||||
// 修程
|
||||
var repairProcess = rtVars.FirstOrDefault(v => v.Name == $"part_repair_process");
|
||||
if (repairProcess != null)
|
||||
component.part_repair_process = repairProcess.Val;
|
||||
|
||||
// Id
|
||||
var part_qrid = rtVars.FirstOrDefault(v => v.Name == $"part_qrid");
|
||||
if (part_qrid != null)
|
||||
component.part_qrid = part_qrid.Val;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有组件信息时,初始化空列表
|
||||
if (_realtimeData.ListComponentsInfo == null)
|
||||
_realtimeData.ListComponentsInfo = new List<ComponentsInfo>() { new ComponentsInfo() };
|
||||
//else
|
||||
// _realtimeData.ListComponentsInfo.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 更新组件信息
|
||||
///// </summary>
|
||||
///// <param name="rtVars">RTVar数据列表</param>
|
||||
//private void UpdateComponentsInfoMulit(List<RTVar> rtVars)
|
||||
//{
|
||||
// var componentsCountVar = rtVars.FirstOrDefault(v => v.Name == "ComponentsCount");
|
||||
// if (componentsCountVar != null && int.TryParse(componentsCountVar.Val, out int count) && count > 0)
|
||||
// {
|
||||
// if (_realtimeData.ListComponentsInfo == null)
|
||||
// _realtimeData.ListComponentsInfo = new List<ComponentsInfo>();
|
||||
// else
|
||||
// _realtimeData.ListComponentsInfo.Clear();
|
||||
|
||||
// // 解析多个组件信息
|
||||
// for (int i = 0; i < count; i++)
|
||||
// {
|
||||
// var component = new ComponentsInfo();
|
||||
|
||||
// var partQRCode = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_PartQRCode");
|
||||
// if (partQRCode != null)
|
||||
// component.part_qrid = partQRCode.Val;
|
||||
|
||||
// var partNum = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_PartNum");
|
||||
// if (partNum != null)
|
||||
// component.part_num = partNum.Val;
|
||||
|
||||
// var partPosition = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_PartPosition");
|
||||
// if (partPosition != null && int.TryParse(partPosition.Val, out int position))
|
||||
// component.part_position = position;
|
||||
|
||||
// var componentName = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_ComponentName");
|
||||
// if (componentName != null)
|
||||
// component.component_name = componentName.Val;
|
||||
|
||||
// // 车型
|
||||
// var vehicleModel = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_VehicleModel");
|
||||
// if (vehicleModel != null)
|
||||
// component.Vehicle_model = vehicleModel.Val;
|
||||
|
||||
// // 车号
|
||||
// var locomotiveNumber = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_LocomotiveNumber");
|
||||
// if (locomotiveNumber != null)
|
||||
// component.locomotive_number = locomotiveNumber.Val;
|
||||
|
||||
// // 修程
|
||||
// var repairProcess = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_RepairProcess");
|
||||
// if (repairProcess != null)
|
||||
// component.repair_process = repairProcess.Val;
|
||||
|
||||
// // 添加到列表
|
||||
// _realtimeData.ListComponentsInfo.Add(component);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // 没有组件信息时,初始化空列表
|
||||
// if (_realtimeData.ListComponentsInfo == null)
|
||||
// _realtimeData.ListComponentsInfo = new List<ComponentsInfo>();
|
||||
// else
|
||||
// _realtimeData.ListComponentsInfo.Clear();
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新测试数据
|
||||
/// </summary>
|
||||
/// <param name="rtVars">RTVar数据列表</param>
|
||||
private void UpdateTestData(List<RTVar> rtVars)
|
||||
{
|
||||
var hasTestData = rtVars.FirstOrDefault(v => v.Name.Contains("Test_"));
|
||||
if (hasTestData != null && !string.IsNullOrEmpty(hasTestData.Val))
|
||||
{
|
||||
if (_realtimeData.TestData == null)
|
||||
_realtimeData.TestData = new TestData();
|
||||
|
||||
// 从RTVar中提取测试数据
|
||||
var testItems = rtVars.Where(v => v.Name.StartsWith("Test_")).ToList();
|
||||
foreach (var item in testItems)
|
||||
{
|
||||
// 根据命名规则解析测试数据项
|
||||
string itemName = item.Name;
|
||||
|
||||
// 使用反射设置属性
|
||||
var property = typeof(TestData).GetProperty(itemName);
|
||||
if (property != null && property.CanWrite)
|
||||
{
|
||||
if (property.PropertyType == typeof(string))
|
||||
{
|
||||
property.SetValue(_realtimeData.TestData, item.Val);
|
||||
}
|
||||
else if (property.PropertyType == typeof(int) && int.TryParse(item.Val, out int intValue))
|
||||
{
|
||||
property.SetValue(_realtimeData.TestData, intValue);
|
||||
}
|
||||
else if (property.PropertyType == typeof(double) && double.TryParse(item.Val, out double doubleValue))
|
||||
{
|
||||
property.SetValue(_realtimeData.TestData, doubleValue);
|
||||
}
|
||||
else if (property.PropertyType == typeof(DateTime) && DateTime.TryParse(item.Val, out DateTime dateValue))
|
||||
{
|
||||
property.SetValue(_realtimeData.TestData, dateValue);
|
||||
}
|
||||
else if (property.PropertyType == typeof(bool) && bool.TryParse(item.Val, out bool boolValue))
|
||||
{
|
||||
property.SetValue(_realtimeData.TestData, boolValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有测试数据时,置空测试数据对象
|
||||
_realtimeData.TestData = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新的RTVar数据(可在外部直接调用)
|
||||
/// </summary>
|
||||
/// <returns>WebSocketData对象</returns>
|
||||
public async Task<WebSocketData> GetLatestDataAsync()
|
||||
{
|
||||
await ReadRTVarDataAsync();
|
||||
return _realtimeData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
StopPolling();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_dataPollingTimer?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user