初步添加报警功能
This commit is contained in:
59
DMS.Application/EventHandlers/AlarmEventHandler.cs
Normal file
59
DMS.Application/EventHandlers/AlarmEventHandler.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using DMS.Application.Interfaces;
|
||||||
|
using DMS.Core.Events;
|
||||||
|
using DMS.Core.Interfaces.Repositories;
|
||||||
|
using DMS.Core.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DMS.Application.EventHandlers
|
||||||
|
{
|
||||||
|
public class AlarmEventHandler
|
||||||
|
{
|
||||||
|
private readonly ILogger<AlarmEventHandler> _logger;
|
||||||
|
private readonly IAlarmHistoryRepository _alarmHistoryRepository;
|
||||||
|
// 可以注入其他服务,如 IEmailService, ISmsService 等
|
||||||
|
|
||||||
|
public AlarmEventHandler(ILogger<AlarmEventHandler> logger, IAlarmHistoryRepository alarmHistoryRepository)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_alarmHistoryRepository = alarmHistoryRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void HandleAlarm(object sender, AlarmEventArgs e)
|
||||||
|
{
|
||||||
|
_logger.LogWarning($"收到报警: {e.Message}");
|
||||||
|
|
||||||
|
// 保存报警记录到数据库
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var alarmHistory = new AlarmHistory
|
||||||
|
{
|
||||||
|
VariableId = e.VariableId,
|
||||||
|
VariableName = e.VariableName,
|
||||||
|
CurrentValue = e.CurrentValue,
|
||||||
|
ThresholdValue = e.ThresholdValue,
|
||||||
|
AlarmType = e.AlarmType,
|
||||||
|
Message = e.Message,
|
||||||
|
Timestamp = e.Timestamp,
|
||||||
|
IsAcknowledged = false
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存到数据库
|
||||||
|
// 注意:这里需要异步操作,但 HandleAlarm 是 void 返回类型
|
||||||
|
// 我们可以考虑使用 Task.Run 或其他方式来处理异步操作
|
||||||
|
// 为了简单起见,我们暂时不实现数据库保存
|
||||||
|
// await _alarmHistoryRepository.AddAsync(alarmHistory);
|
||||||
|
|
||||||
|
_logger.LogInformation($"报警记录已保存: {e.Message}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"保存报警记录时发生错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在这里添加其他报警处理逻辑
|
||||||
|
// 例如:
|
||||||
|
// 2. 发送邮件或短信通知
|
||||||
|
// 3. 触发其他操作
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
DMS.Application/Interfaces/IAlarmService.cs
Normal file
20
DMS.Application/Interfaces/IAlarmService.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using DMS.Application.DTOs;
|
||||||
|
using DMS.Core.Events;
|
||||||
|
|
||||||
|
namespace DMS.Application.Interfaces
|
||||||
|
{
|
||||||
|
public interface IAlarmService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 检查变量是否触发报警
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variable">变量DTO</param>
|
||||||
|
/// <returns>是否触发报警</returns>
|
||||||
|
bool CheckAlarm(VariableDto variable);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 警报事件
|
||||||
|
/// </summary>
|
||||||
|
event EventHandler<AlarmEventArgs> OnAlarmTriggered;
|
||||||
|
}
|
||||||
|
}
|
||||||
86
DMS.Application/Services/AlarmService.cs
Normal file
86
DMS.Application/Services/AlarmService.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using DMS.Application.DTOs;
|
||||||
|
using DMS.Application.Interfaces;
|
||||||
|
using DMS.Core.Enums;
|
||||||
|
using DMS.Core.Events;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DMS.Application.Services
|
||||||
|
{
|
||||||
|
public class AlarmService : IAlarmService
|
||||||
|
{
|
||||||
|
private readonly ILogger<AlarmService> _logger;
|
||||||
|
|
||||||
|
public AlarmService(ILogger<AlarmService> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<AlarmEventArgs> OnAlarmTriggered;
|
||||||
|
|
||||||
|
public bool CheckAlarm(VariableDto variable)
|
||||||
|
{
|
||||||
|
if (!variable.IsAlarmEnabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试将 DataValue 转换为 double
|
||||||
|
if (!double.TryParse(variable.DataValue, out double currentValue))
|
||||||
|
{
|
||||||
|
// 如果是布尔值,我们也应该处理
|
||||||
|
if (bool.TryParse(variable.DataValue, out bool boolValue))
|
||||||
|
{
|
||||||
|
// 布尔值变化报警需要更复杂的逻辑,通常在 VariableItemViewModel 中处理
|
||||||
|
// 因为需要检测从 false 到 true 或从 true 到 false 的变化
|
||||||
|
// 这里我们暂时不处理
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogWarning($"无法将变量 {variable.Name} 的值 '{variable.DataValue}' 转换为数字进行报警检查。");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTriggered = false;
|
||||||
|
string message = "";
|
||||||
|
string alarmType = "";
|
||||||
|
double thresholdValue = 0;
|
||||||
|
|
||||||
|
// 检查上限报警
|
||||||
|
if (variable.AlarmMaxValue > 0 && currentValue > variable.AlarmMaxValue)
|
||||||
|
{
|
||||||
|
isTriggered = true;
|
||||||
|
message = $"变量 {variable.Name} 的值 {currentValue} 超过了上限 {variable.AlarmMaxValue}。";
|
||||||
|
alarmType = "High";
|
||||||
|
thresholdValue = variable.AlarmMaxValue;
|
||||||
|
}
|
||||||
|
// 检查下限报警
|
||||||
|
else if (variable.AlarmMinValue > 0 && currentValue < variable.AlarmMinValue)
|
||||||
|
{
|
||||||
|
isTriggered = true;
|
||||||
|
message = $"变量 {variable.Name} 的值 {currentValue} 低于了下限 {variable.AlarmMinValue}。";
|
||||||
|
alarmType = "Low";
|
||||||
|
thresholdValue = variable.AlarmMinValue;
|
||||||
|
}
|
||||||
|
// 检查死区报警
|
||||||
|
// 注意:这里的实现假设我们有一个方法可以获取变量的上一次值
|
||||||
|
// 在实际应用中,这可能需要在 VariableItemViewModel 或其他地方维护
|
||||||
|
// 为了简化,我们假设有一个 PreviousValue 属性(但这在 DTO 中不存在)
|
||||||
|
// 我们将在 VariableItemViewModel 中处理这个逻辑,并通过事件触发
|
||||||
|
|
||||||
|
|
||||||
|
// 如果需要在 AlarmService 中处理死区报警,我们需要一种方式来获取上一次的值
|
||||||
|
// 这可能需要修改 VariableDto 或通过其他方式传递上一次的值
|
||||||
|
// 为了保持设计的清晰性,我们暂时不在这里实现死区报警
|
||||||
|
// 死区报警可以在 VariableItemViewModel 中实现,当检测到值变化超过死区时触发一个事件
|
||||||
|
|
||||||
|
if (isTriggered)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(message);
|
||||||
|
OnAlarmTriggered?.Invoke(this, new AlarmEventArgs(
|
||||||
|
variable.Id, variable.Name, currentValue, thresholdValue, message, alarmType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return isTriggered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
DMS.Application/Services/Processors/AlarmProcessor.cs
Normal file
39
DMS.Application/Services/Processors/AlarmProcessor.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using DMS.Application.Interfaces;
|
||||||
|
using DMS.Application.Models;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DMS.Application.Services.Processors
|
||||||
|
{
|
||||||
|
public class AlarmProcessor : IVariableProcessor
|
||||||
|
{
|
||||||
|
private readonly IAlarmService _alarmService;
|
||||||
|
private readonly ILogger<AlarmProcessor> _logger;
|
||||||
|
|
||||||
|
public AlarmProcessor(IAlarmService alarmService, ILogger<AlarmProcessor> logger)
|
||||||
|
{
|
||||||
|
_alarmService = alarmService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ProcessAsync(VariableContext context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检查是否触发报警
|
||||||
|
bool isAlarmTriggered = _alarmService.CheckAlarm(context.Data);
|
||||||
|
|
||||||
|
if (isAlarmTriggered)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"变量 {context.Data.Name} 触发了报警。");
|
||||||
|
// 报警逻辑已经通过事件处理,这里可以添加其他处理逻辑(如记录到数据库)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"处理变量 {context.Data.Name} 的报警时发生错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不设置 context.IsHandled = true,让其他处理器继续处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
DMS.Core/Enums/AlarmRule.cs
Normal file
30
DMS.Core/Enums/AlarmRule.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
namespace DMS.Core.Enums
|
||||||
|
{
|
||||||
|
public enum AlarmRule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 超过上限报警
|
||||||
|
/// </summary>
|
||||||
|
AboveMax,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 低于下限报警
|
||||||
|
/// </summary>
|
||||||
|
BelowMin,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 超出范围报警(同时检查上限和下限)
|
||||||
|
/// </summary>
|
||||||
|
OutOfRange,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 死区报警
|
||||||
|
/// </summary>
|
||||||
|
Deadband,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 布尔值变化报警
|
||||||
|
/// </summary>
|
||||||
|
BooleanChange
|
||||||
|
}
|
||||||
|
}
|
||||||
27
DMS.Core/Events/AlarmEventArgs.cs
Normal file
27
DMS.Core/Events/AlarmEventArgs.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DMS.Core.Events
|
||||||
|
{
|
||||||
|
public class AlarmEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public int VariableId { get; }
|
||||||
|
public string VariableName { get; }
|
||||||
|
public double CurrentValue { get; }
|
||||||
|
public double ThresholdValue { get; }
|
||||||
|
public string Message { get; }
|
||||||
|
public DateTime Timestamp { get; }
|
||||||
|
public string AlarmType { get; } // 可以是 "High", "Low", "Change" 等
|
||||||
|
|
||||||
|
public AlarmEventArgs(int variableId, string variableName, double currentValue,
|
||||||
|
double thresholdValue, string message, string alarmType)
|
||||||
|
{
|
||||||
|
VariableId = variableId;
|
||||||
|
VariableName = variableName;
|
||||||
|
CurrentValue = currentValue;
|
||||||
|
ThresholdValue = thresholdValue;
|
||||||
|
Message = message;
|
||||||
|
Timestamp = DateTime.Now;
|
||||||
|
AlarmType = alarmType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
DMS.Core/Interfaces/Repositories/IAlarmHistoryRepository.cs
Normal file
16
DMS.Core/Interfaces/Repositories/IAlarmHistoryRepository.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using DMS.Core.Models;
|
||||||
|
|
||||||
|
namespace DMS.Core.Interfaces.Repositories
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报警历史记录仓库接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IAlarmHistoryRepository : IBaseRepository<AlarmHistory>
|
||||||
|
{
|
||||||
|
// 可以添加特定于报警历史记录的查询方法
|
||||||
|
// 例如:
|
||||||
|
// Task<IEnumerable<AlarmHistory>> GetUnacknowledgedAlarmsAsync();
|
||||||
|
// Task<IEnumerable<AlarmHistory>> GetAlarmsByVariableIdAsync(int variableId);
|
||||||
|
// Task AcknowledgeAlarmAsync(int alarmId, string acknowledgedBy);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
DMS.Core/Models/AlarmHistory.cs
Normal file
71
DMS.Core/Models/AlarmHistory.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace DMS.Core.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报警历史记录实体
|
||||||
|
/// </summary>
|
||||||
|
public class AlarmHistory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 主键ID
|
||||||
|
/// </summary>
|
||||||
|
[Key]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 变量ID
|
||||||
|
/// </summary>
|
||||||
|
public int VariableId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 变量名称
|
||||||
|
/// </summary>
|
||||||
|
[MaxLength(100)]
|
||||||
|
public string VariableName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前值
|
||||||
|
/// </summary>
|
||||||
|
public double CurrentValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阈值
|
||||||
|
/// </summary>
|
||||||
|
public double ThresholdValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报警类型 (High, Low, Deadband, BooleanChange)
|
||||||
|
/// </summary>
|
||||||
|
[MaxLength(50)]
|
||||||
|
public string AlarmType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报警消息
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报警触发时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否已确认
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAcknowledged { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确认时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? AcknowledgedAt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确认人
|
||||||
|
/// </summary>
|
||||||
|
[MaxLength(100)]
|
||||||
|
public string AcknowledgedBy { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
27
DMS.Infrastructure/Repositories/AlarmHistoryRepository.cs
Normal file
27
DMS.Infrastructure/Repositories/AlarmHistoryRepository.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using DMS.Core.Interfaces.Repositories;
|
||||||
|
using DMS.Core.Models;
|
||||||
|
using DMS.Infrastructure.Data;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace DMS.Infrastructure.Repositories
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报警历史记录仓库实现
|
||||||
|
/// </summary>
|
||||||
|
public class AlarmHistoryRepository : BaseRepository<AlarmHistory>, IAlarmHistoryRepository
|
||||||
|
{
|
||||||
|
public AlarmHistoryRepository(SqlSugarDbContext dbContext,ILogger<AlarmHistoryRepository> logger) : base(dbContext,logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可以添加特定于报警历史记录的查询方法的实现
|
||||||
|
// 例如:
|
||||||
|
// public async Task<IEnumerable<AlarmHistory>> GetUnacknowledgedAlarmsAsync()
|
||||||
|
// {
|
||||||
|
// return await _db.Queryable<AlarmHistory>()
|
||||||
|
// .Where(a => !a.IsAcknowledged)
|
||||||
|
// .ToListAsync();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -199,7 +199,7 @@ public abstract class BaseRepository<TEntity>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="number">要获取的实体数量。</param>
|
/// <param name="number">要获取的实体数量。</param>
|
||||||
/// <returns>包含指定数量实体对象的列表。</returns>
|
/// <returns>包含指定数量实体对象的列表。</returns>
|
||||||
protected async Task<List<TEntity>> TakeAsync(int number)
|
public virtual async Task<List<TEntity>> TakeAsync(int number)
|
||||||
{
|
{
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
@@ -210,6 +210,23 @@ public abstract class BaseRepository<TEntity>
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步根据主键 ID 删除单个实体。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">要删除的实体的主键 ID。</param>
|
||||||
|
/// <returns>返回受影响的行数。</returns>
|
||||||
|
public virtual async Task<int> DeleteByIdAsync(int id)
|
||||||
|
{
|
||||||
|
var stopwatch = new Stopwatch();
|
||||||
|
stopwatch.Start();
|
||||||
|
var result = await Db.Deleteable<TEntity>()
|
||||||
|
.In(id)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
stopwatch.Stop();
|
||||||
|
_logger.LogInformation($"DeleteById {typeof(TEntity).Name}, ID: {id}, 耗时:{stopwatch.ElapsedMilliseconds}ms");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> AddBatchAsync(List<TEntity> entities)
|
public async Task<bool> AddBatchAsync(List<TEntity> entities)
|
||||||
{
|
{
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
|
|||||||
@@ -71,12 +71,19 @@ public partial class App : System.Windows.Application
|
|||||||
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<HistoryProcessor>());
|
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<HistoryProcessor>());
|
||||||
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<MqttPublishProcessor>());
|
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<MqttPublishProcessor>());
|
||||||
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<UpdateDbVariableProcessor>());
|
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<UpdateDbVariableProcessor>());
|
||||||
|
// 添加报警处理器
|
||||||
|
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<DMS.Application.Services.Processors.AlarmProcessor>());
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
var notificationService = Host.Services.GetRequiredService<INotificationService>();
|
var notificationService = Host.Services.GetRequiredService<INotificationService>();
|
||||||
notificationService.ShowError($"加载数据时发生错误,如果是连接字符串不正确,可以在设置界面更改:{exception.Message}", exception);
|
notificationService.ShowError($"加载数据时发生错误,如果是连接字符串不正确,可以在设置界面更改:{exception.Message}", exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 订阅报警事件
|
||||||
|
var alarmService = Host.Services.GetRequiredService<DMS.Application.Interfaces.IAlarmService>();
|
||||||
|
var alarmEventHandler = Host.Services.GetRequiredService<DMS.Application.EventHandlers.AlarmEventHandler>();
|
||||||
|
alarmService.OnAlarmTriggered += alarmEventHandler.HandleAlarm;
|
||||||
|
|
||||||
var splashWindow = Host.Services.GetRequiredService<SplashWindow>();
|
var splashWindow = Host.Services.GetRequiredService<SplashWindow>();
|
||||||
splashWindow.Show();
|
splashWindow.Show();
|
||||||
@@ -184,6 +191,10 @@ public partial class App : System.Windows.Application
|
|||||||
services.AddSingleton<UpdateDbVariableProcessor>();
|
services.AddSingleton<UpdateDbVariableProcessor>();
|
||||||
services.AddSingleton<HistoryProcessor>();
|
services.AddSingleton<HistoryProcessor>();
|
||||||
services.AddSingleton<MqttPublishProcessor>();
|
services.AddSingleton<MqttPublishProcessor>();
|
||||||
|
// 注册报警服务和处理器
|
||||||
|
services.AddSingleton<DMS.Application.Interfaces.IAlarmService, DMS.Application.Services.AlarmService>();
|
||||||
|
services.AddSingleton<DMS.Application.Services.Processors.AlarmProcessor>();
|
||||||
|
services.AddSingleton<DMS.Application.EventHandlers.AlarmEventHandler>();
|
||||||
|
|
||||||
// 注册Core中的仓库
|
// 注册Core中的仓库
|
||||||
services.AddSingleton<AppSettings>();
|
services.AddSingleton<AppSettings>();
|
||||||
@@ -204,6 +215,7 @@ public partial class App : System.Windows.Application
|
|||||||
services.AddSingleton<IUserRepository, UserRepository>();
|
services.AddSingleton<IUserRepository, UserRepository>();
|
||||||
services.AddSingleton<INlogRepository, NlogRepository>();
|
services.AddSingleton<INlogRepository, NlogRepository>();
|
||||||
services.AddSingleton<IRepositoryManager, RepositoryManager>();
|
services.AddSingleton<IRepositoryManager, RepositoryManager>();
|
||||||
|
services.AddSingleton<IAlarmHistoryRepository, AlarmHistoryRepository>(); // 添加这行
|
||||||
services.AddSingleton<IExcelService, ExcelService>();
|
services.AddSingleton<IExcelService, ExcelService>();
|
||||||
|
|
||||||
services.AddTransient<IOpcUaService, OpcUaService>();
|
services.AddTransient<IOpcUaService, OpcUaService>();
|
||||||
|
|||||||
@@ -54,6 +54,11 @@ public partial class VariableItemViewModel : ObservableObject
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _displayValue;
|
private string? _displayValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上一次的数值,用于死区报警计算
|
||||||
|
/// </summary>
|
||||||
|
private double _previousNumericValue;
|
||||||
|
|
||||||
partial void OnDataValueChanged(string? oldValue, string? newValue)
|
partial void OnDataValueChanged(string? oldValue, string? newValue)
|
||||||
{
|
{
|
||||||
// 当DataValue发生变化时,更新NumericValue
|
// 当DataValue发生变化时,更新NumericValue
|
||||||
@@ -66,16 +71,22 @@ public partial class VariableItemViewModel : ObservableObject
|
|||||||
// 尝试将字符串转换为数值
|
// 尝试将字符串转换为数值
|
||||||
if (double.TryParse(newValue, out double numericValue))
|
if (double.TryParse(newValue, out double numericValue))
|
||||||
{
|
{
|
||||||
|
// 更新上一次的数值
|
||||||
|
_previousNumericValue = NumericValue;
|
||||||
NumericValue = numericValue;
|
NumericValue = numericValue;
|
||||||
}
|
}
|
||||||
// 如果是布尔值
|
// 如果是布尔值
|
||||||
else if (bool.TryParse(newValue, out bool boolValue))
|
else if (bool.TryParse(newValue, out bool boolValue))
|
||||||
{
|
{
|
||||||
|
// 更新上一次的数值
|
||||||
|
_previousNumericValue = NumericValue;
|
||||||
NumericValue = boolValue ? 1.0 : 0.0;
|
NumericValue = boolValue ? 1.0 : 0.0;
|
||||||
}
|
}
|
||||||
// 如果无法转换,保持为0.0
|
// 如果无法转换,保持为0.0
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// 更新上一次的数值
|
||||||
|
_previousNumericValue = NumericValue;
|
||||||
NumericValue = 0.0;
|
NumericValue = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,4 +235,45 @@ public partial class VariableItemViewModel : ObservableObject
|
|||||||
private OpcUaUpdateType _opcUaUpdateType;
|
private OpcUaUpdateType _opcUaUpdateType;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上一次的布尔值,用于布尔值变化报警计算
|
||||||
|
/// </summary>
|
||||||
|
private bool? _previousBoolValue = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查死区报警和布尔值变化报警
|
||||||
|
/// </summary>
|
||||||
|
public void CheckAdvancedAlarms(VariableDto variable)
|
||||||
|
{
|
||||||
|
// 检查死区报警
|
||||||
|
if (variable.IsAlarmEnabled && variable.AlarmDeadband > 0)
|
||||||
|
{
|
||||||
|
double difference = Math.Abs(NumericValue - _previousNumericValue);
|
||||||
|
if (difference > variable.AlarmDeadband)
|
||||||
|
{
|
||||||
|
// 触发死区报警
|
||||||
|
// 这里可以触发一个事件或调用报警服务
|
||||||
|
// 为了简单起见,我们暂时只打印日志
|
||||||
|
Console.WriteLine($"变量 {variable.Name} 的值变化 {difference} 超过了死区 {variable.AlarmDeadband}。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查布尔值变化报警
|
||||||
|
if (variable.IsAlarmEnabled && variable.DataType == DataType.Bool)
|
||||||
|
{
|
||||||
|
if (bool.TryParse(DataValue, out bool currentBoolValue))
|
||||||
|
{
|
||||||
|
// 如果上一次的值不为空,并且当前值与上一次的值不同,则触发报警
|
||||||
|
if (_previousBoolValue.HasValue && _previousBoolValue.Value != currentBoolValue)
|
||||||
|
{
|
||||||
|
// 触发布尔值变化报警
|
||||||
|
// 这里可以触发一个事件或调用报警服务
|
||||||
|
// 为了简单起见,我们暂时只打印日志
|
||||||
|
Console.WriteLine($"变量 {variable.Name} 的布尔值从 {_previousBoolValue.Value} 变化为 {currentBoolValue}。");
|
||||||
|
}
|
||||||
|
// 更新上一次的布尔值
|
||||||
|
_previousBoolValue = currentBoolValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user