Files
MoviconHub/MoviconHub.App/Services/DBServices.cs
2025-10-30 12:02:12 +08:00

529 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.Message}");
// 发生错误时,等待一段时间后重试
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($"读取RTVar数据时发生错误: {ex.StackTrace}");
throw;
}
}
/// <summary>
/// 使用RTVar数据更新WebSocketData模型
/// </summary>
/// <param name="rtVars">RTVar数据列表</param>
private void UpdateWebSocketData(List<RTVar> rtVars)
{
try
{
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("实时数据已更新");
}
}
catch (Exception ex)
{
Logger.Error($"UpdateWebSocketData: {ex.StackTrace}");
}
}
/// <summary>
/// 更新远程数据库
/// </summary>
/// <param name="webSocketData"></param>
private void UpdateRemoteDb(WebSocketData webSocketData)
{
try
{
// 获取组件信息
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("实时数据已更新到远程数据库");
}
}
catch (Exception ex)
{
Logger.Error($"UpdateRemoteDb: {ex.StackTrace}");
}
}
/// <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();
}
}
}