mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-20 10:50:48 +08:00
修改报警事件时间字段,增加变量表报警类
This commit is contained in:
@@ -306,8 +306,19 @@ public class TimerScheduler : ILogFeature
|
||||
return;
|
||||
}
|
||||
|
||||
var func = timer.Method.As<Func<Object?, Task>>(target);
|
||||
await func!(timer.State).ConfigureAwait(false);
|
||||
#if NET6_0_OR_GREATER
|
||||
if (timer.IsValueTask)
|
||||
{
|
||||
var func = timer.Method.As<Func<Object?, ValueTask>>(target);
|
||||
await func!(timer.State).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
var func = timer.Method.As<Func<Object?, Task>>(target);
|
||||
await func!(timer.State).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
catch (ThreadAbortException) { throw; }
|
||||
catch (ThreadInterruptedException) { throw; }
|
||||
|
@@ -87,6 +87,8 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
||||
|
||||
private DateTime _AbsolutelyNext;
|
||||
private readonly Cron[]? _crons;
|
||||
|
||||
internal bool IsValueTask { get; }
|
||||
#endregion
|
||||
|
||||
// #region 静态
|
||||
@@ -158,6 +160,29 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
||||
Init(dueTime);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
|
||||
/// <summary>实例化一个不可重入的定时器</summary>
|
||||
/// <param name="callback">委托</param>
|
||||
/// <param name="state">用户数据</param>
|
||||
/// <param name="dueTime">多久之后开始。毫秒</param>
|
||||
/// <param name="period">间隔周期。毫秒</param>
|
||||
/// <param name="scheduler">调度器</param>
|
||||
public TimerX(Func<Object, ValueTask> callback, Object? state, Int32 dueTime, Int32 period, String? scheduler = null) : this(callback.Target, callback.Method, state, scheduler)
|
||||
{
|
||||
IsValueTask = true;
|
||||
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||
if (dueTime < 0) throw new ArgumentOutOfRangeException(nameof(dueTime));
|
||||
|
||||
IsAsyncTask = true;
|
||||
Async = true;
|
||||
Period = period;
|
||||
|
||||
Init(dueTime);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>实例化一个绝对定时器,指定时刻执行,跟当前时间和SetNext无关</summary>
|
||||
/// <param name="callback">委托</param>
|
||||
/// <param name="state">用户数据</param>
|
||||
@@ -210,6 +235,37 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
||||
Init(ms);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
|
||||
/// <summary>实例化一个绝对定时器,指定时刻执行,跟当前时间和SetNext无关</summary>
|
||||
/// <param name="callback">委托</param>
|
||||
/// <param name="state">用户数据</param>
|
||||
/// <param name="startTime">绝对开始时间</param>
|
||||
/// <param name="period">间隔周期。毫秒</param>
|
||||
/// <param name="scheduler">调度器</param>
|
||||
public TimerX(Func<Object, ValueTask> callback, Object? state, DateTime startTime, Int32 period, String? scheduler = null) : this(callback.Target, callback.Method, state, scheduler)
|
||||
{
|
||||
IsValueTask = true;
|
||||
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||
if (startTime <= DateTime.MinValue) throw new ArgumentOutOfRangeException(nameof(startTime));
|
||||
if (period <= 0) throw new ArgumentOutOfRangeException(nameof(period));
|
||||
|
||||
IsAsyncTask = true;
|
||||
Async = true;
|
||||
Period = period;
|
||||
Absolutely = true;
|
||||
|
||||
//var now = DateTime.Now;
|
||||
var now = Scheduler.GetNow();
|
||||
var next = startTime;
|
||||
while (next < now) next = next.AddMilliseconds(period);
|
||||
|
||||
var ms = (Int64)(next - now).TotalMilliseconds;
|
||||
_AbsolutelyNext = next;
|
||||
Init(ms);
|
||||
}
|
||||
|
||||
#endif
|
||||
/// <summary>实例化一个Cron定时器</summary>
|
||||
/// <param name="callback">委托</param>
|
||||
/// <param name="state">用户数据</param>
|
||||
@@ -274,6 +330,42 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
||||
//Init(_AbsolutelyNext = _cron.GetNext(DateTime.Now));
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <summary>实例化一个Cron定时器</summary>
|
||||
/// <param name="callback">委托</param>
|
||||
/// <param name="state">用户数据</param>
|
||||
/// <param name="cronExpression">Cron表达式。支持多个表达式,分号分隔</param>
|
||||
/// <param name="scheduler">调度器</param>
|
||||
public TimerX(Func<Object, ValueTask> callback, Object? state, String cronExpression, String? scheduler = null) : this(callback.Target, callback.Method, state, scheduler)
|
||||
{
|
||||
IsValueTask = true;
|
||||
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||
if (cronExpression.IsNullOrEmpty()) throw new ArgumentNullException(nameof(cronExpression));
|
||||
|
||||
var list = new List<Cron>();
|
||||
foreach (var item in cronExpression.Split(";"))
|
||||
{
|
||||
var cron = new Cron();
|
||||
if (!cron.Parse(item)) throw new ArgumentException($"Invalid Cron expression[{item}]", nameof(cronExpression));
|
||||
|
||||
list.Add(cron);
|
||||
}
|
||||
_crons = list.ToArray();
|
||||
|
||||
IsAsyncTask = true;
|
||||
Async = true;
|
||||
Absolutely = true;
|
||||
|
||||
//var now = DateTime.Now;
|
||||
var now = Scheduler.GetNow();
|
||||
var next = _crons.Min(e => e.GetNext(now));
|
||||
var ms = (Int64)(next - now).TotalMilliseconds;
|
||||
_AbsolutelyNext = next;
|
||||
Init(ms);
|
||||
//Init(_AbsolutelyNext = _cron.GetNext(DateTime.Now));
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool Disposed { get; private set; }
|
||||
/// <summary>销毁定时器</summary>
|
||||
public void Dispose()
|
||||
|
@@ -48,7 +48,7 @@ namespace ThingsGateway.SqlSugar
|
||||
private static readonly object _instanceLock = new object();
|
||||
private ReflectionInoCore()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public V this[string key]
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.10.9</PluginVersion>
|
||||
<ProPluginVersion>10.10.9</ProPluginVersion>
|
||||
<DefaultVersion>10.10.12</DefaultVersion>
|
||||
<PluginVersion>10.10.11</PluginVersion>
|
||||
<ProPluginVersion>10.10.11</ProPluginVersion>
|
||||
<DefaultVersion>10.10.14</DefaultVersion>
|
||||
<AuthenticationVersion>10.10.1</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.10.1</SourceGeneratorVersion>
|
||||
<NET8Version>8.0.19</NET8Version>
|
||||
|
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
public class LinkedCancellationTokenSourceCache : IDisposable
|
||||
{
|
||||
private CancellationTokenSource? _cachedCts;
|
||||
private CancellationToken _token1;
|
||||
private CancellationToken _token2;
|
||||
private readonly object _lock = new();
|
||||
~LinkedCancellationTokenSourceCache()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取一个 CancellationTokenSource,它是由两个 token 链接而成的。
|
||||
/// 会尝试复用之前缓存的 CTS,前提是两个 token 仍然相同且未取消。
|
||||
/// </summary>
|
||||
public CancellationTokenSource GetLinkedTokenSource(CancellationToken token1, CancellationToken token2)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// 如果缓存的 CTS 已经取消或 Dispose,或者 token 不同,重新创建
|
||||
if (_cachedCts?.IsCancellationRequested != false ||
|
||||
!_token1.Equals(token1) || !_token2.Equals(token2))
|
||||
{
|
||||
_cachedCts?.Dispose();
|
||||
|
||||
_cachedCts = CancellationTokenSource.CreateLinkedTokenSource(token1, token2);
|
||||
_token1 = token1;
|
||||
_token2 = token2;
|
||||
}
|
||||
|
||||
return _cachedCts;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_cachedCts?.Dispose();
|
||||
_cachedCts = null!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -10,6 +10,7 @@ public class CronScheduledTask : DisposeBase, IScheduledTask
|
||||
private int _interval10MS = 10;
|
||||
private string _interval;
|
||||
private readonly Func<object?, CancellationToken, Task> _taskFunc;
|
||||
private readonly Func<object?, CancellationToken, ValueTask> _valueTaskFunc;
|
||||
private readonly Action<object?, CancellationToken> _taskAction;
|
||||
private readonly CancellationToken _token;
|
||||
private TimerX? _timer;
|
||||
@@ -28,6 +29,17 @@ public class CronScheduledTask : DisposeBase, IScheduledTask
|
||||
_taskFunc = taskFunc;
|
||||
_token = token;
|
||||
}
|
||||
public CronScheduledTask(string interval, Func<object?, CancellationToken, ValueTask> taskFunc, object? state, ILog log, CancellationToken token)
|
||||
{
|
||||
_interval = interval;
|
||||
LogMessage = log;
|
||||
_state = state;
|
||||
_valueTaskFunc = taskFunc;
|
||||
_token = token;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public CronScheduledTask(string interval, Action<object?, CancellationToken> taskAction, object? state, ILog log, CancellationToken token)
|
||||
{
|
||||
_interval = interval;
|
||||
@@ -51,14 +63,14 @@ public class CronScheduledTask : DisposeBase, IScheduledTask
|
||||
if (Check()) return;
|
||||
if (_taskAction != null)
|
||||
_timer = new TimerX(TimerCallback, _state, _interval, nameof(IScheduledTask)) { Async = true };
|
||||
else if (_taskFunc != null)
|
||||
else if (_taskFunc != null || _valueTaskFunc != null)
|
||||
_timer = new TimerX(TimerCallbackAsync, _state, _interval, nameof(IScheduledTask)) { Async = true };
|
||||
}
|
||||
|
||||
private async Task TimerCallbackAsync(object? state)
|
||||
private async ValueTask TimerCallbackAsync(object? state)
|
||||
{
|
||||
if (Check()) return;
|
||||
if (_taskFunc == null)
|
||||
if (_taskFunc == null && _valueTaskFunc == null)
|
||||
{
|
||||
Dispose();
|
||||
return;
|
||||
@@ -74,7 +86,10 @@ public class CronScheduledTask : DisposeBase, IScheduledTask
|
||||
|
||||
try
|
||||
{
|
||||
await _taskFunc(state, _token).ConfigureAwait(false);
|
||||
if (_taskFunc != null)
|
||||
await _taskFunc(state, _token).ConfigureAwait(false);
|
||||
else if (_valueTaskFunc != null)
|
||||
await _valueTaskFunc(state, _token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
@@ -10,6 +10,7 @@ public class ScheduledAsyncTask : DisposeBase, IScheduledTask, IScheduledIntInte
|
||||
private int _interval10MS = 10;
|
||||
public int IntervalMS { get; }
|
||||
private readonly Func<object?, CancellationToken, Task> _taskFunc;
|
||||
private readonly Func<object?, CancellationToken, ValueTask> _valueTaskFunc;
|
||||
private readonly CancellationToken _token;
|
||||
private TimerX? _timer;
|
||||
private object? _state;
|
||||
@@ -26,6 +27,14 @@ public class ScheduledAsyncTask : DisposeBase, IScheduledTask, IScheduledIntInte
|
||||
_taskFunc = taskFunc;
|
||||
_token = token;
|
||||
}
|
||||
public ScheduledAsyncTask(int interval, Func<object?, CancellationToken, ValueTask> taskFunc, object? state, ILog log, CancellationToken token)
|
||||
{
|
||||
IntervalMS = interval;
|
||||
LogMessage = log;
|
||||
_state = state;
|
||||
_valueTaskFunc = taskFunc;
|
||||
_token = token;
|
||||
}
|
||||
private bool Check()
|
||||
{
|
||||
if (_token.IsCancellationRequested)
|
||||
@@ -42,11 +51,17 @@ public class ScheduledAsyncTask : DisposeBase, IScheduledTask, IScheduledIntInte
|
||||
_timer = new TimerX(DoAsync, _state, IntervalMS, IntervalMS, nameof(IScheduledTask)) { Async = true };
|
||||
}
|
||||
|
||||
private async Task DoAsync(object? state)
|
||||
private async ValueTask DoAsync(object? state)
|
||||
{
|
||||
if (Check())
|
||||
return;
|
||||
|
||||
if (_taskFunc == null && _valueTaskFunc == null)
|
||||
{
|
||||
Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref _pendingTriggers);
|
||||
|
||||
if (Interlocked.Exchange(ref _isRunning, 1) == 1)
|
||||
@@ -55,9 +70,13 @@ public class ScheduledAsyncTask : DisposeBase, IScheduledTask, IScheduledIntInte
|
||||
// 减少一个触发次数
|
||||
Interlocked.Decrement(ref _pendingTriggers);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
await _taskFunc(state, _token).ConfigureAwait(false);
|
||||
if (_taskFunc != null)
|
||||
await _taskFunc(state, _token).ConfigureAwait(false);
|
||||
else if (_valueTaskFunc != null)
|
||||
await _valueTaskFunc(state, _token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
@@ -14,6 +14,18 @@ public static class ScheduledTaskHelper
|
||||
return new CronScheduledTask(interval, func, state, log, cancellationToken);
|
||||
}
|
||||
}
|
||||
public static IScheduledTask GetTask(string interval, Func<object?, CancellationToken, ValueTask> func, object? state, TouchSocket.Core.ILog log, CancellationToken cancellationToken)
|
||||
{
|
||||
if (int.TryParse(interval, out int intervalV))
|
||||
{
|
||||
var intervalMilliseconds = intervalV < 10 ? 10 : intervalV;
|
||||
return new ScheduledAsyncTask(intervalMilliseconds, func, state, log, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new CronScheduledTask(interval, func, state, log, cancellationToken);
|
||||
}
|
||||
}
|
||||
public static IScheduledTask GetTask(string interval, Action<object?, CancellationToken> action, object? state, TouchSocket.Core.ILog log, CancellationToken cancellationToken)
|
||||
{
|
||||
if (int.TryParse(interval, out int intervalV))
|
||||
|
@@ -35,6 +35,12 @@ public static class ExportString
|
||||
/// </summary>
|
||||
public static string VariableName => Localizer["VariableName"];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 变量报警表名称
|
||||
/// </summary>
|
||||
public static string AlarmName => Localizer["AlarmName"];
|
||||
|
||||
public static IStringLocalizer localizer;
|
||||
public static IStringLocalizer Localizer
|
||||
{
|
||||
|
@@ -15,14 +15,10 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO.Ports;
|
||||
|
||||
using ThingsGateway.FriendlyException;
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
@@ -156,9 +152,9 @@ public class ControlController : ControllerBase, IRpcServer
|
||||
[HttpPost("batchSaveChannel")]
|
||||
[DisplayName("保存通道")]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchSaveChannelAsync([FromBody][TouchSocket.WebApi.FromBody] List<ChannelInput> channels, ItemChangedType type, bool restart = true)
|
||||
public Task<bool> BatchSaveChannelAsync([FromBody][TouchSocket.WebApi.FromBody] List<Channel> channels, ItemChangedType type, bool restart = true)
|
||||
{
|
||||
return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.AdaptListChannel(), type, restart);
|
||||
return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels, type, restart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,9 +163,9 @@ public class ControlController : ControllerBase, IRpcServer
|
||||
[HttpPost("batchSaveDevice")]
|
||||
[DisplayName("保存设备")]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchSaveDeviceAsync([FromBody][TouchSocket.WebApi.FromBody] List<DeviceInput> devices, ItemChangedType type, bool restart = true)
|
||||
public Task<bool> BatchSaveDeviceAsync([FromBody][TouchSocket.WebApi.FromBody] List<Device> devices, ItemChangedType type, bool restart = true)
|
||||
{
|
||||
return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.AdaptListDevice(), type, restart);
|
||||
return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices, type, restart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,9 +174,9 @@ public class ControlController : ControllerBase, IRpcServer
|
||||
[HttpPost("batchSaveVariable")]
|
||||
[DisplayName("保存变量")]
|
||||
[TouchSocket.WebApi.WebApi(Method = TouchSocket.WebApi.HttpMethodType.Post)]
|
||||
public Task<bool> BatchSaveVariableAsync([FromBody][TouchSocket.WebApi.FromBody] List<VariableInput> variables, ItemChangedType type, bool restart = true)
|
||||
public Task<bool> BatchSaveVariableAsync([FromBody][TouchSocket.WebApi.FromBody] List<Variable> variables, ItemChangedType type, bool restart = true)
|
||||
{
|
||||
return GlobalData.VariableRuntimeService.BatchSaveVariableAsync(variables.AdaptListVariable(), type, restart, default);
|
||||
return GlobalData.VariableRuntimeService.BatchSaveVariableAsync(variables, type, restart, default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -247,552 +243,3 @@ public class ControlController : ControllerBase, IRpcServer
|
||||
}
|
||||
}
|
||||
}
|
||||
public class ChannelInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键Id
|
||||
/// </summary>
|
||||
public virtual long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通道名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual ChannelTypeEnum ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 插件名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
public virtual string PluginName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使能
|
||||
/// </summary>
|
||||
public virtual bool Enable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// LogLevel
|
||||
/// </summary>
|
||||
public LogLevel LogLevel { get; set; } = LogLevel.Info;
|
||||
|
||||
/// <summary>
|
||||
/// 远程地址,可由<see cref="IPHost"/> 与 <see cref="string"/> 相互转化
|
||||
/// </summary>
|
||||
[UriValidation]
|
||||
public virtual string RemoteUrl { get; set; } = "127.0.0.1:502";
|
||||
|
||||
/// <summary>
|
||||
/// 本地地址,可由<see cref="IPHost.IPHost(string)"/>与<see href="IPHost.ToString()"/>相互转化
|
||||
/// </summary>
|
||||
[UriValidation]
|
||||
public virtual string BindUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// COM
|
||||
/// </summary>
|
||||
public virtual string PortName { get; set; } = "COM1";
|
||||
|
||||
/// <summary>
|
||||
/// 波特率
|
||||
/// </summary>
|
||||
public virtual int BaudRate { get; set; } = 9600;
|
||||
|
||||
/// <summary>
|
||||
/// 数据位
|
||||
/// </summary>
|
||||
public virtual int DataBits { get; set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 校验位
|
||||
/// </summary>
|
||||
public virtual Parity Parity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 停止位
|
||||
/// </summary>
|
||||
public virtual StopBits StopBits { get; set; } = StopBits.One;
|
||||
|
||||
/// <summary>
|
||||
/// DtrEnable
|
||||
/// </summary>
|
||||
public virtual bool DtrEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RtsEnable
|
||||
/// </summary>
|
||||
public virtual bool RtsEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// StreamAsync
|
||||
/// </summary>
|
||||
public virtual bool StreamAsync { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存超时
|
||||
/// </summary>
|
||||
[MinValue(100)]
|
||||
public virtual int CacheTimeout { get; set; } = 500;
|
||||
|
||||
/// <summary>
|
||||
/// 连接超时
|
||||
/// </summary>
|
||||
[MinValue(100)]
|
||||
public virtual ushort ConnectTimeout { get; set; } = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// 最大并发数
|
||||
/// </summary>
|
||||
[MinValue(1)]
|
||||
public virtual int MaxConcurrentCount { get; set; } = 1;
|
||||
|
||||
public virtual int MaxClientCount { get; set; } = 10000;
|
||||
public virtual int CheckClearTime { get; set; } = 120000;
|
||||
public virtual string Heartbeat { get; set; } = "Heartbeat";
|
||||
|
||||
#region dtu终端
|
||||
|
||||
public virtual int HeartbeatTime { get; set; } = 60000;
|
||||
public virtual string DtuId { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual DtuSeviceType DtuSeviceType { get; set; }
|
||||
}
|
||||
|
||||
public class DeviceInput : IValidatableObject
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
[RegularExpression(@"^[^.]*$", ErrorMessage = "The field {0} cannot contain a dot ('.')")]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 通道
|
||||
/// </summary>
|
||||
[MinValue(1)]
|
||||
[Required]
|
||||
public virtual long ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认执行间隔,支持corn表达式
|
||||
/// </summary>
|
||||
public virtual string IntervalTime { get; set; } = "1000";
|
||||
|
||||
/// <summary>
|
||||
/// 设备使能
|
||||
/// </summary>
|
||||
public virtual bool Enable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// LogLevel
|
||||
/// </summary>
|
||||
public virtual TouchSocket.Core.LogLevel LogLevel { get; set; } = TouchSocket.Core.LogLevel.Info;
|
||||
|
||||
/// <summary>
|
||||
/// 设备属性Json
|
||||
/// </summary>
|
||||
public Dictionary<string, string>? DevicePropertys { get; set; } = new();
|
||||
|
||||
#region 冗余配置
|
||||
|
||||
/// <summary>
|
||||
/// 启用冗余
|
||||
/// </summary>
|
||||
public bool RedundantEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 冗余设备Id,只能选择相同驱动
|
||||
/// </summary>
|
||||
public long? RedundantDeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 冗余模式
|
||||
/// </summary>
|
||||
public virtual RedundantSwitchTypeEnum RedundantSwitchType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 冗余扫描间隔
|
||||
/// </summary>
|
||||
[MinValue(30000)]
|
||||
public virtual int RedundantScanIntervalTime { get; set; } = 30000;
|
||||
|
||||
/// <summary>
|
||||
/// 冗余切换判断脚本,返回true则切换冗余设备
|
||||
/// </summary>
|
||||
public virtual string RedundantScript { get; set; }
|
||||
|
||||
#endregion 冗余配置
|
||||
|
||||
#region 备用字段
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark5 { get; set; }
|
||||
|
||||
#endregion 备用字段
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (RedundantEnable && RedundantDeviceId == null)
|
||||
{
|
||||
yield return new ValidationResult("When enable redundancy, you must select a redundant device.", new[] { nameof(RedundantEnable), nameof(RedundantDeviceId) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class VariableInput : IValidatableObject
|
||||
{
|
||||
public virtual long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备
|
||||
/// </summary>
|
||||
[Required]
|
||||
public virtual long DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 单位
|
||||
/// </summary>
|
||||
public virtual string? Unit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 间隔时间
|
||||
/// </summary>
|
||||
public virtual string? IntervalTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量地址,可能带有额外的信息,比如<see cref="DataFormatEnum"/> ,以;分割
|
||||
/// </summary>
|
||||
public string? RegisterAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数组长度
|
||||
/// </summary>
|
||||
public int? ArrayLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 其他方法,若不为空,此时RegisterAddress为方法参数
|
||||
/// </summary>
|
||||
public string? OtherMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使能
|
||||
/// </summary>
|
||||
public virtual bool Enable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 读写权限
|
||||
/// </summary>
|
||||
public virtual ProtectTypeEnum ProtectType { get; set; } = ProtectTypeEnum.ReadWrite;
|
||||
|
||||
/// <summary>
|
||||
/// 数据类型
|
||||
/// </summary>
|
||||
public virtual DataTypeEnum DataType { get; set; } = DataTypeEnum.Int16;
|
||||
|
||||
/// <summary>
|
||||
/// 读取表达式
|
||||
/// </summary>
|
||||
public virtual string? ReadExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 写入表达式
|
||||
/// </summary>
|
||||
public virtual string? WriteExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许远程Rpc写入
|
||||
/// </summary>
|
||||
public virtual bool RpcWriteEnable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 初始值
|
||||
/// </summary>
|
||||
public object? InitValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
_value = value?.ToString()?.GetJTokenFromString();
|
||||
else
|
||||
_value = null;
|
||||
}
|
||||
}
|
||||
private object? _value;
|
||||
|
||||
/// <summary>
|
||||
/// 保存初始值
|
||||
/// </summary>
|
||||
public virtual bool SaveValue { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 变量额外属性Json
|
||||
/// </summary>
|
||||
public Dictionary<long, Dictionary<string, string>>? VariablePropertys { get; set; }
|
||||
|
||||
#region 报警
|
||||
/// <summary>
|
||||
/// 报警延时
|
||||
/// </summary>
|
||||
public int AlarmDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警使能
|
||||
/// </summary>
|
||||
public bool BoolOpenAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警约束
|
||||
/// </summary>
|
||||
public string? BoolOpenRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警文本
|
||||
/// </summary>
|
||||
public string? BoolOpenAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警使能
|
||||
/// </summary>
|
||||
public bool BoolCloseAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警约束
|
||||
/// </summary>
|
||||
public string? BoolCloseRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警文本
|
||||
/// </summary>
|
||||
public string? BoolCloseAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报使能
|
||||
/// </summary>
|
||||
public bool HAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报约束
|
||||
/// </summary>
|
||||
public string? HRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报文本
|
||||
/// </summary>
|
||||
public string? HAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高限值
|
||||
/// </summary>
|
||||
public double? HAlarmCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报使能
|
||||
/// </summary>
|
||||
public bool HHAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报约束
|
||||
/// </summary>
|
||||
public string? HHRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报文本
|
||||
/// </summary>
|
||||
public string? HHAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高限值
|
||||
/// </summary>
|
||||
public double? HHAlarmCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报使能
|
||||
/// </summary>
|
||||
public bool LAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报约束
|
||||
/// </summary>
|
||||
public string? LRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报文本
|
||||
/// </summary>
|
||||
public string? LAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低限值
|
||||
/// </summary>
|
||||
public double? LAlarmCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报使能
|
||||
/// </summary>
|
||||
public bool LLAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报约束
|
||||
/// </summary>
|
||||
public string? LLRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报文本
|
||||
/// </summary>
|
||||
public string? LLAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低限值
|
||||
/// </summary>
|
||||
public double? LLAlarmCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警使能
|
||||
/// </summary>
|
||||
public bool CustomAlarmEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警条件约束
|
||||
/// </summary>
|
||||
public string? CustomRestrainExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义文本
|
||||
/// </summary>
|
||||
public string? CustomAlarmText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警条件
|
||||
/// </summary>
|
||||
public string? CustomAlarmCode { get; set; }
|
||||
|
||||
#endregion 报警
|
||||
|
||||
#region 备用字段
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义
|
||||
/// </summary>
|
||||
public string? Remark5 { get; set; }
|
||||
|
||||
#endregion 备用字段
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(RegisterAddress) && string.IsNullOrEmpty(OtherMethod))
|
||||
{
|
||||
yield return new ValidationResult("Both RegisterAddress and OtherMethod cannot be empty or null.", new[] { nameof(RegisterAddress), nameof(OtherMethod) });
|
||||
}
|
||||
if (HHAlarmEnable && HHAlarmCode == null)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode cannot be null when HHAlarmEnable is true", new[] { nameof(HHAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && HAlarmCode == null)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode cannot be null when HAlarmEnable is true", new[] { nameof(HAlarmCode) });
|
||||
}
|
||||
if (LAlarmEnable && LAlarmCode == null)
|
||||
{
|
||||
yield return new ValidationResult("LAlarmCode cannot be null when LAlarmEnable is true", new[] { nameof(LAlarmCode) });
|
||||
}
|
||||
if (LLAlarmEnable && LLAlarmCode == null)
|
||||
{
|
||||
yield return new ValidationResult("LLAlarmCode cannot be null when LLAlarmEnable is true", new[] { nameof(LLAlarmCode) });
|
||||
}
|
||||
|
||||
if (HHAlarmEnable && HAlarmEnable && HHAlarmCode <= HAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode must be greater than HAlarmCode", new[] { nameof(HHAlarmCode), nameof(HAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && LAlarmEnable && HAlarmCode <= LAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode must be greater than LAlarmCode", new[] { nameof(HAlarmCode), nameof(LAlarmCode) });
|
||||
}
|
||||
if (LAlarmEnable && LLAlarmEnable && LAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("LAlarmCode must be greater than LLAlarmCode", new[] { nameof(LAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
|
||||
if (HHAlarmEnable && LAlarmEnable && HHAlarmCode <= LAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode should be greater than or less than LAlarmCode", new[] { nameof(HHAlarmCode), nameof(LAlarmCode) });
|
||||
}
|
||||
if (HHAlarmEnable && LLAlarmEnable && HHAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode should be greater than or less than LLAlarmCode", new[] { nameof(HHAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && LLAlarmEnable && HAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode should be greater than or less than LLAlarmCode", new[] { nameof(HAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
}
|
||||
}
|
@@ -21,6 +21,8 @@ public interface IDBHistoryAlarm
|
||||
string? Description { get; set; }
|
||||
string DeviceName { get; set; }
|
||||
DateTime EventTime { get; set; }
|
||||
DateTime FinishTime { get; set; }
|
||||
DateTime ConfirmTime { get; set; }
|
||||
EventTypeEnum EventType { get; set; }
|
||||
string Name { get; set; }
|
||||
string RegisterAddress { get; set; }
|
||||
|
@@ -29,7 +29,7 @@ namespace ThingsGateway.Gateway.Application;
|
||||
/// 采集插件,继承实现不同PLC通讯
|
||||
/// <para></para>
|
||||
/// </summary>
|
||||
public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
public abstract partial class CollectBase : DriverBase, IRpcDriver
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件配置项
|
||||
@@ -278,11 +278,9 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
}
|
||||
}
|
||||
|
||||
#region private
|
||||
|
||||
#region 执行方法
|
||||
|
||||
async Task ReadVariableMed(object? state, CancellationToken cancellationToken)
|
||||
async ValueTask ReadVariableMed(object? state, CancellationToken cancellationToken)
|
||||
{
|
||||
if (state is not VariableMethod readVariableMethods) return;
|
||||
if (Pause)
|
||||
@@ -348,25 +346,25 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
}
|
||||
|
||||
#endregion
|
||||
private readonly LinkedCancellationTokenSourceCache _linkedCtsCache = new();
|
||||
|
||||
#region 执行默认读取
|
||||
|
||||
async Task ReadVariableSource(object? state, CancellationToken cancellationToken)
|
||||
async ValueTask ReadVariableSource(object? state, CancellationToken cancellationToken)
|
||||
{
|
||||
var readToken = await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (state is not VariableSourceRead variableSourceRead) return;
|
||||
|
||||
if (Pause) return;
|
||||
if (cancellationToken.IsCancellationRequested) return;
|
||||
|
||||
var readToken = await ReadWriteLock.ReaderLockAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (readToken.IsCancellationRequested)
|
||||
{
|
||||
await ReadVariableSource(state, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
using var allTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, readToken);
|
||||
var allTokenSource = _linkedCtsCache.GetLinkedTokenSource(cancellationToken, readToken);
|
||||
var allToken = allTokenSource.Token;
|
||||
|
||||
//if (LogMessage?.LogLevel <= TouchSocket.Core.LogLevel.Trace)
|
||||
@@ -434,13 +432,15 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
variableSourceRead.LastErrorMessage = readResult.ErrorMessage;
|
||||
CurrentDevice.SetDeviceStatus(TimerX.Now, null, readResult.ErrorMessage);
|
||||
var time = DateTime.Now;
|
||||
variableSourceRead.VariableRuntimes.ForEach(a => a.SetValue(null, time, isOnline: false));
|
||||
foreach (var item in variableSourceRead.VariableRuntimes)
|
||||
{
|
||||
item.SetValue(null, time, isOnline: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
protected virtual Task TestOnline(object? state, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -722,4 +722,10 @@ public abstract class CollectBase : DriverBase, IRpcDriver
|
||||
|
||||
|
||||
#endregion 写入方法
|
||||
|
||||
protected override Task DisposeAsync(bool disposing)
|
||||
{
|
||||
_linkedCtsCache?.SafeDispose();
|
||||
return base.DisposeAsync(disposing);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,284 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
public class AlarmPropertys : IValidatableObject
|
||||
{
|
||||
private int alarmDelay;
|
||||
private int alarmLevel;
|
||||
|
||||
private decimal hAlarmCode = 50;
|
||||
private decimal lAlarmCode = 10;
|
||||
private decimal hHAlarmCode = 90;
|
||||
private decimal lLAlarmCode = 0;
|
||||
|
||||
private bool boolOpenAlarmEnable;
|
||||
private bool boolCloseAlarmEnable;
|
||||
private bool hAlarmEnable;
|
||||
private bool hHAlarmEnable;
|
||||
private bool lLAlarmEnable;
|
||||
private bool lAlarmEnable;
|
||||
private bool customAlarmEnable;
|
||||
|
||||
private string boolOpenRestrainExpressions;
|
||||
private string boolOpenAlarmText;
|
||||
private string boolCloseRestrainExpressions;
|
||||
private string boolCloseAlarmText;
|
||||
private string hRestrainExpressions;
|
||||
private string hAlarmText;
|
||||
private string hHRestrainExpressions;
|
||||
private string hHAlarmText;
|
||||
private string lRestrainExpressions;
|
||||
private string lAlarmText;
|
||||
|
||||
private string lLRestrainExpressions;
|
||||
private string lLAlarmText;
|
||||
private string customRestrainExpressions;
|
||||
private string customAlarmText;
|
||||
private string customAlarmCode;
|
||||
|
||||
#region 报警
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 报警等级
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "报警等级")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public int AlarmLevel { get => alarmLevel; set => alarmLevel = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警延时
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "报警延时")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public int AlarmDelay { get => alarmDelay; set => alarmDelay = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔开报警使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool BoolOpenAlarmEnable { get => boolOpenAlarmEnable; set => boolOpenAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔开报警约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolOpenRestrainExpressions { get => boolOpenRestrainExpressions; set => boolOpenRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔开报警文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolOpenAlarmText { get => boolOpenAlarmText; set => boolOpenAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔关报警使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool BoolCloseAlarmEnable { get => boolCloseAlarmEnable; set => boolCloseAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔关报警约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolCloseRestrainExpressions { get => boolCloseRestrainExpressions; set => boolCloseRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔关报警文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolCloseAlarmText { get => boolCloseAlarmText; set => boolCloseAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool HAlarmEnable { get => hAlarmEnable; set => hAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HRestrainExpressions { get => hRestrainExpressions; set => hRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HAlarmText { get => hAlarmText; set => hAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public decimal HAlarmCode { get => hAlarmCode; set => hAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool HHAlarmEnable { get => hHAlarmEnable; set => hHAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HHRestrainExpressions { get => hHRestrainExpressions; set => hHRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HHAlarmText { get => hHAlarmText; set => hHAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public decimal HHAlarmCode { get => hHAlarmCode; set => hHAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool LAlarmEnable { get => lAlarmEnable; set => lAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LRestrainExpressions { get => lRestrainExpressions; set => lRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LAlarmText { get => lAlarmText; set => lAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public decimal LAlarmCode { get => lAlarmCode; set => lAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool LLAlarmEnable { get => lLAlarmEnable; set => lLAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LLRestrainExpressions { get => lLRestrainExpressions; set => lLRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LLAlarmText { get => lLAlarmText; set => lLAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public decimal LLAlarmCode { get => lLAlarmCode; set => lLAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义报警使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool CustomAlarmEnable { get => customAlarmEnable; set => customAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警条件约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义报警条件约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string CustomRestrainExpressions { get => customRestrainExpressions; set => customRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string CustomAlarmText { get => customAlarmText; set => customAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警条件
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义报警条件", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string CustomAlarmCode { get => customAlarmCode; set => customAlarmCode = value; }
|
||||
|
||||
#endregion 报警
|
||||
|
||||
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
|
||||
if (HHAlarmEnable && HAlarmEnable && HHAlarmCode <= HAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode must be greater than HAlarmCode", new[] { nameof(HHAlarmCode), nameof(HAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && LAlarmEnable && HAlarmCode <= LAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode must be greater than LAlarmCode", new[] { nameof(HAlarmCode), nameof(LAlarmCode) });
|
||||
}
|
||||
if (LAlarmEnable && LLAlarmEnable && LAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("LAlarmCode must be greater than LLAlarmCode", new[] { nameof(LAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
|
||||
if (HHAlarmEnable && LAlarmEnable && HHAlarmCode <= LAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode should be greater than or less than LAlarmCode", new[] { nameof(HHAlarmCode), nameof(LAlarmCode) });
|
||||
}
|
||||
if (HHAlarmEnable && LLAlarmEnable && HHAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode should be greater than or less than LLAlarmCode", new[] { nameof(HHAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && LLAlarmEnable && HAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode should be greater than or less than LLAlarmCode", new[] { nameof(HAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
}
|
||||
}
|
@@ -43,14 +43,9 @@ public class Variable : BaseDataEntity, IValidatableObject
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
internal long Row;
|
||||
private double hAlarmCode = 50;
|
||||
private double lAlarmCode = 10;
|
||||
private double hHAlarmCode = 90;
|
||||
private double lLAlarmCode = 0;
|
||||
private long deviceId;
|
||||
private int? arrayLength;
|
||||
private int alarmDelay;
|
||||
private int alarmLevel;
|
||||
|
||||
private ProtectTypeEnum protectType = ProtectTypeEnum.ReadWrite;
|
||||
private DataTypeEnum dataType = DataTypeEnum.Int16;
|
||||
|
||||
@@ -64,13 +59,6 @@ public class Variable : BaseDataEntity, IValidatableObject
|
||||
public bool DynamicVariable;
|
||||
private bool rpcWriteEnable = true;
|
||||
private bool saveValue = false;
|
||||
private bool boolOpenAlarmEnable;
|
||||
private bool boolCloseAlarmEnable;
|
||||
private bool hAlarmEnable;
|
||||
private bool hHAlarmEnable;
|
||||
private bool lLAlarmEnable;
|
||||
private bool lAlarmEnable;
|
||||
private bool customAlarmEnable;
|
||||
private bool businessGroupUpdateTrigger = true;
|
||||
private bool rpcWriteCheck;
|
||||
|
||||
@@ -85,29 +73,17 @@ public class Variable : BaseDataEntity, IValidatableObject
|
||||
private string otherMethod;
|
||||
private string readExpressions;
|
||||
private string writeExpressions;
|
||||
private string boolOpenRestrainExpressions;
|
||||
private string boolOpenAlarmText;
|
||||
private string boolCloseRestrainExpressions;
|
||||
private string boolCloseAlarmText;
|
||||
private string hRestrainExpressions;
|
||||
private string hAlarmText;
|
||||
private Dictionary<long, Dictionary<string, string>>? variablePropertys;
|
||||
private string hHRestrainExpressions;
|
||||
private string hHAlarmText;
|
||||
private string lRestrainExpressions;
|
||||
private string lAlarmText;
|
||||
|
||||
private string lLRestrainExpressions;
|
||||
private string lLAlarmText;
|
||||
private string customRestrainExpressions;
|
||||
private string customAlarmText;
|
||||
private string customAlarmCode;
|
||||
private Dictionary<long, Dictionary<string, string>>? variablePropertys;
|
||||
private string remark1;
|
||||
private string remark2;
|
||||
private string remark3;
|
||||
private string remark4;
|
||||
private string remark5;
|
||||
|
||||
[MapperIgnore]
|
||||
public ValidateForm AlarmPropertysValidateForm;
|
||||
|
||||
/// <summary>
|
||||
/// 变量额外属性Json
|
||||
/// </summary>
|
||||
@@ -276,206 +252,15 @@ public class Variable : BaseDataEntity, IValidatableObject
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
public Dictionary<long, Dictionary<string, string>>? VariablePropertys { get => variablePropertys; set => variablePropertys = value; }
|
||||
|
||||
#region 报警
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 报警等级
|
||||
/// 变量报警属性Json
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "报警等级")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public int AlarmLevel { get => alarmLevel; set => alarmLevel = value; }
|
||||
[SugarColumn(IsJson = true, ColumnDataType = StaticConfig.CodeFirst_BigString, ColumnDescription = "报警属性Json", IsNullable = true)]
|
||||
[IgnoreExcel]
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
public AlarmPropertys? AlarmPropertys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警延时
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "报警延时")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public int AlarmDelay { get => alarmDelay; set => alarmDelay = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔开报警使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool BoolOpenAlarmEnable { get => boolOpenAlarmEnable; set => boolOpenAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔开报警约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolOpenRestrainExpressions { get => boolOpenRestrainExpressions; set => boolOpenRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔开报警文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolOpenAlarmText { get => boolOpenAlarmText; set => boolOpenAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔关报警使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool BoolCloseAlarmEnable { get => boolCloseAlarmEnable; set => boolCloseAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔关报警约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolCloseRestrainExpressions { get => boolCloseRestrainExpressions; set => boolCloseRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔关报警文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "布尔关报警文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string BoolCloseAlarmText { get => boolCloseAlarmText; set => boolCloseAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool HAlarmEnable { get => hAlarmEnable; set => hAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HRestrainExpressions { get => hRestrainExpressions; set => hRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HAlarmText { get => hAlarmText; set => hAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public double HAlarmCode { get => hAlarmCode; set => hAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool HHAlarmEnable { get => hHAlarmEnable; set => hHAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HHRestrainExpressions { get => hHRestrainExpressions; set => hHRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string HHAlarmText { get => hHAlarmText; set => hHAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 高高限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "高高限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public double HHAlarmCode { get => hHAlarmCode; set => hHAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool LAlarmEnable { get => lAlarmEnable; set => lAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LRestrainExpressions { get => lRestrainExpressions; set => lRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LAlarmText { get => lAlarmText; set => lAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public double LAlarmCode { get => lAlarmCode; set => lAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低报使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool LLAlarmEnable { get => lLAlarmEnable; set => lLAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低报约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LLRestrainExpressions { get => lLRestrainExpressions; set => lLRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低报文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低报文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string LLAlarmText { get => lLAlarmText; set => lLAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 低低限值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "低低限值", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public double LLAlarmCode { get => lLAlarmCode; set => lLAlarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警使能
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义报警使能")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public bool CustomAlarmEnable { get => customAlarmEnable; set => customAlarmEnable = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警条件约束
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义报警条件约束", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string CustomRestrainExpressions { get => customRestrainExpressions; set => customRestrainExpressions = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义文本
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string CustomAlarmText { get => customAlarmText; set => customAlarmText = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义报警条件
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "自定义报警条件", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public string CustomAlarmCode { get => customAlarmCode; set => customAlarmCode = value; }
|
||||
|
||||
#endregion 报警
|
||||
|
||||
#region 备用字段
|
||||
|
||||
@@ -523,30 +308,6 @@ public class Variable : BaseDataEntity, IValidatableObject
|
||||
yield return new ValidationResult("Both RegisterAddress and OtherMethod cannot be empty or null.", new[] { nameof(OtherMethod), nameof(RegisterAddress) });
|
||||
}
|
||||
|
||||
if (HHAlarmEnable && HAlarmEnable && HHAlarmCode <= HAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode must be greater than HAlarmCode", new[] { nameof(HHAlarmCode), nameof(HAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && LAlarmEnable && HAlarmCode <= LAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode must be greater than LAlarmCode", new[] { nameof(HAlarmCode), nameof(LAlarmCode) });
|
||||
}
|
||||
if (LAlarmEnable && LLAlarmEnable && LAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("LAlarmCode must be greater than LLAlarmCode", new[] { nameof(LAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
|
||||
if (HHAlarmEnable && LAlarmEnable && HHAlarmCode <= LAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode should be greater than or less than LAlarmCode", new[] { nameof(HHAlarmCode), nameof(LAlarmCode) });
|
||||
}
|
||||
if (HHAlarmEnable && LLAlarmEnable && HHAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HHAlarmCode should be greater than or less than LLAlarmCode", new[] { nameof(HHAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
if (HAlarmEnable && LLAlarmEnable && HAlarmCode <= LLAlarmCode)
|
||||
{
|
||||
yield return new ValidationResult("HAlarmCode should be greater than or less than LLAlarmCode", new[] { nameof(HAlarmCode), nameof(LLAlarmCode) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -44,4 +44,11 @@ public enum EventTypeEnum
|
||||
/// 报警确认并恢复
|
||||
/// </summary>
|
||||
ConfirmAndFinish,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 重启默认
|
||||
/// </summary>
|
||||
Restart,
|
||||
|
||||
}
|
||||
|
@@ -147,6 +147,8 @@
|
||||
"DeviceName": "DeviceName",
|
||||
"Enable": "Enable",
|
||||
"EventTime": "EventTime",
|
||||
"ConfirmTime": "ConfirmTime",
|
||||
"FinishTime": "FinishTime",
|
||||
"EventType": "EventType",
|
||||
"HAlarmCode": "HAlarmCode",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
@@ -390,6 +392,7 @@
|
||||
"BusinessDeviceName": "BusinessDevice",
|
||||
"ChannelName": "Channel",
|
||||
"DeviceName": "Device",
|
||||
"AlarmName": "Alarm",
|
||||
"RedundantDeviceName": "Redundant Device",
|
||||
"VariableName": "Variable"
|
||||
},
|
||||
@@ -451,25 +454,16 @@
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.Variable": {
|
||||
"AddressOrOtherMethodNotNull": "Variable address or special method cannot be empty at the same time",
|
||||
"AlarmDelay": "AlarmDelay",
|
||||
"AlarmLevel": "AlarmLevel",
|
||||
|
||||
"ArrayLength": "ArrayLength",
|
||||
"BoolCloseAlarmEnable": "BoolCloseAlarmEnable",
|
||||
"BoolCloseAlarmText": "BoolCloseAlarmText",
|
||||
"BoolCloseRestrainExpressions": "BoolCloseRestrainExpressions",
|
||||
"BoolOpenAlarmEnable": "BoolOpenAlarmEnable",
|
||||
"BoolOpenAlarmText": "BoolOpenAlarmText",
|
||||
"BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions",
|
||||
|
||||
"BusinessGroup": "BusinessGroup",
|
||||
"BusinessGroupUpdateTrigger": "BusinessGroupUpdateTrigger",
|
||||
"RpcWriteCheck": "RpcWriteCheck",
|
||||
"ClearVariable": "Clear Variable",
|
||||
"CollectGroup": "CollectGroup",
|
||||
"CopyVariable": "Copy Variable",
|
||||
"CustomAlarmCode": "CustomAlarmCode",
|
||||
"CustomAlarmEnable": "CustomAlarmEnable",
|
||||
"CustomAlarmText": "CustomAlarmText",
|
||||
"CustomRestrainExpressions": "CustomRestrainExpressions",
|
||||
|
||||
"DataType": "DataType",
|
||||
"DeleteVariable": "Delete Variable",
|
||||
"Description": "Description",
|
||||
@@ -480,26 +474,14 @@
|
||||
"DynamicVariable": "DynamicVariable",
|
||||
"Enable": "Enable",
|
||||
"ExportVariable": "Export Variable",
|
||||
"HAlarmCode": "HAlarmCode",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
"HAlarmText": "HAlarmText",
|
||||
"HHAlarmCode": "HHAlarmCode",
|
||||
"HHAlarmEnable": "HHAlarmEnable",
|
||||
"HHAlarmText": "HHAlarmText",
|
||||
"HHRestrainExpressions": "HHRestrainExpressions",
|
||||
"HRestrainExpressions": "HRestrainExpressions",
|
||||
|
||||
|
||||
"ImportVariable": "Import Variable",
|
||||
"InitValue": "InitValue",
|
||||
"IntervalTime": "IntervalTime",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"LAlarmCode": "LAlarmCode",
|
||||
"LAlarmEnable": "LAlarmEnable",
|
||||
"LAlarmText": "LAlarmText",
|
||||
"LLAlarmCode": "LLAlarmCode",
|
||||
"LLAlarmEnable": "LLAlarmEnable",
|
||||
"LLAlarmText": "LLAlarmText",
|
||||
"LLRestrainExpressions": "LLRestrainExpressions",
|
||||
"LRestrainExpressions": "LRestrainExpressions",
|
||||
|
||||
|
||||
"Name": "Name",
|
||||
"Name.Required": "{0} cannot be empty",
|
||||
"NameDump": "Duplicate variable name {0}",
|
||||
@@ -521,6 +503,38 @@
|
||||
"VariableNotNull": "Variable name does not exist",
|
||||
"WriteExpressions": "WriteExpressions"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.AlarmPropertys": {
|
||||
|
||||
"AlarmDelay": "AlarmDelay",
|
||||
"AlarmLevel": "AlarmLevel",
|
||||
"BoolCloseAlarmEnable": "BoolCloseAlarmEnable",
|
||||
"BoolCloseAlarmText": "BoolCloseAlarmText",
|
||||
"BoolCloseRestrainExpressions": "BoolCloseRestrainExpressions",
|
||||
"BoolOpenAlarmEnable": "BoolOpenAlarmEnable",
|
||||
"BoolOpenAlarmText": "BoolOpenAlarmText",
|
||||
"BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions",
|
||||
"CustomAlarmCode": "CustomAlarmCode",
|
||||
"CustomAlarmEnable": "CustomAlarmEnable",
|
||||
"CustomAlarmText": "CustomAlarmText",
|
||||
"CustomRestrainExpressions": "CustomRestrainExpressions",
|
||||
"HAlarmCode": "HAlarmCode",
|
||||
"HAlarmEnable": "HAlarmEnable",
|
||||
"HAlarmText": "HAlarmText",
|
||||
"HHAlarmCode": "HHAlarmCode",
|
||||
"HHAlarmEnable": "HHAlarmEnable",
|
||||
"HHAlarmText": "HHAlarmText",
|
||||
"HHRestrainExpressions": "HHRestrainExpressions",
|
||||
"HRestrainExpressions": "HRestrainExpressions",
|
||||
"LAlarmCode": "LAlarmCode",
|
||||
"LAlarmEnable": "LAlarmEnable",
|
||||
"LAlarmText": "LAlarmText",
|
||||
"LLAlarmCode": "LLAlarmCode",
|
||||
"LLAlarmEnable": "LLAlarmEnable",
|
||||
"LLAlarmText": "LLAlarmText",
|
||||
"LLRestrainExpressions": "LLRestrainExpressions",
|
||||
"LRestrainExpressions": "LRestrainExpressions"
|
||||
},
|
||||
"ThingsGateway.Gateway.Application.VariableRuntime": {
|
||||
"AlarmCode": "AlarmCode",
|
||||
"AlarmEnable": "AlarmEnable",
|
||||
@@ -535,6 +549,8 @@
|
||||
"DeviceName": "DeviceName",
|
||||
"DynamicVariable": "DynamicVariable",
|
||||
"EventTime": "EventTime",
|
||||
"ConfirmTime": "ConfirmTime",
|
||||
"FinishTime": "FinishTime",
|
||||
"EventType": "EventType",
|
||||
"IntervalTime.MinValue": "{0} value is too small",
|
||||
"IsOnline": "IsOnline",
|
||||
|
@@ -147,6 +147,8 @@
|
||||
"DeviceName": "设备名称",
|
||||
"Enable": "变量使能",
|
||||
"EventTime": "事件时间",
|
||||
"ConfirmTime": "确认时间",
|
||||
"FinishTime": "恢复时间",
|
||||
"EventType": "事件类型",
|
||||
"HAlarmCode": "高限值",
|
||||
"HAlarmEnable": "高报使能",
|
||||
@@ -392,6 +394,7 @@
|
||||
"BusinessDeviceName": "业务设备",
|
||||
"ChannelName": "通道",
|
||||
"DeviceName": "设备",
|
||||
"AlarmName": "报警",
|
||||
"RedundantDeviceName": "冗余设备",
|
||||
"VariableName": "变量"
|
||||
},
|
||||
@@ -523,6 +526,40 @@
|
||||
"VariableNotNull": "变量名称不存在",
|
||||
"WriteExpressions": "写入表达式"
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.AlarmPropertys": {
|
||||
|
||||
"AlarmDelay": "报警延时",
|
||||
"AlarmLevel": "报警等级",
|
||||
"BoolCloseAlarmEnable": "布尔关报警使能",
|
||||
"BoolCloseAlarmText": "布尔关报警文本",
|
||||
"BoolCloseRestrainExpressions": "布尔关报警约束",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"CustomAlarmCode": "自定义报警限值",
|
||||
"CustomAlarmEnable": "自定义报警使能",
|
||||
"CustomAlarmText": "自定义报警文本",
|
||||
"CustomRestrainExpressions": "自定义报警约束",
|
||||
"HAlarmCode": "高限值",
|
||||
"HAlarmEnable": "高报使能",
|
||||
"HAlarmText": "高报文本",
|
||||
"HHAlarmCode": "高高限值",
|
||||
"HHAlarmEnable": "高高报使能",
|
||||
"HHAlarmText": "高高报文本",
|
||||
"HHRestrainExpressions": "高高报约束",
|
||||
"HRestrainExpressions": "高报约束",
|
||||
"LAlarmCode": "低限值",
|
||||
"LAlarmEnable": "低报使能",
|
||||
"LAlarmText": "低报文本",
|
||||
"LLAlarmCode": "低低限值",
|
||||
"LLAlarmEnable": "低低报使能",
|
||||
"LLAlarmText": "低低报文本",
|
||||
"LLRestrainExpressions": "低低报约束",
|
||||
"LRestrainExpressions": "低报约束"
|
||||
|
||||
},
|
||||
|
||||
"ThingsGateway.Gateway.Application.VariableRuntime": {
|
||||
"AlarmCode": "报警值",
|
||||
"AlarmEnable": "报警使能",
|
||||
@@ -537,6 +574,8 @@
|
||||
"DeviceName": "设备名称",
|
||||
"DynamicVariable": "动态变量",
|
||||
"EventTime": "事件时间",
|
||||
"ConfirmTime": "确认时间",
|
||||
"FinishTime": "恢复时间",
|
||||
"EventType": "事件类型",
|
||||
"IntervalTime.MinValue": " {0} 值太小",
|
||||
"IsOnline": "在线",
|
||||
|
@@ -14,9 +14,21 @@ namespace ThingsGateway.Gateway.Application;
|
||||
[Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)]
|
||||
public static partial class GatewayMapper
|
||||
{
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmPropertys)}.{nameof(AlarmPropertys.AlarmLevel)}", nameof(AlarmVariable.AlarmLevel))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.AlarmCode)}", nameof(AlarmVariable.AlarmCode))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.AlarmLimit)}", nameof(AlarmVariable.AlarmLimit))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.AlarmText)}", nameof(AlarmVariable.AlarmText))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.RecoveryCode)}", nameof(AlarmVariable.RecoveryCode))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.AlarmTime)}", nameof(AlarmVariable.AlarmTime))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.FinishTime)}", nameof(AlarmVariable.FinishTime))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.ConfirmTime)}", nameof(AlarmVariable.ConfirmTime))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.EventTime)}", nameof(AlarmVariable.EventTime))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.AlarmType)}", nameof(AlarmVariable.AlarmType))]
|
||||
[MapProperty($"{nameof(VariableRuntime.AlarmRuntimePropertys)}.{nameof(AlarmRuntimePropertys.EventType)}", nameof(AlarmVariable.EventType))]
|
||||
public static partial AlarmVariable AdaptAlarmVariable(this VariableRuntime src);
|
||||
|
||||
public static partial VariableDataWithValue AdaptVariableDataWithValue(this VariableBasicData src);
|
||||
public static partial VariableDataWithValue AdaptVariableDataWithValue(this VariableRuntime src);
|
||||
public static partial AlarmVariable AdaptAlarmVariable(this VariableRuntime src);
|
||||
public static partial DeviceBasicData AdaptDeviceBasicData(this DeviceRuntime src);
|
||||
public static partial IEnumerable<DeviceBasicData> AdaptIEnumerableDeviceBasicData(this IEnumerable<DeviceRuntime> src);
|
||||
public static partial List<DeviceBasicData> AdaptListDeviceBasicData(this IEnumerable<DeviceRuntime> src);
|
||||
@@ -28,6 +40,7 @@ public static partial class GatewayMapper
|
||||
|
||||
[MapProperty(nameof(Variable.InitValue), nameof(VariableRuntime.Value))]
|
||||
public static partial VariableRuntime AdaptVariableRuntime(this Variable src);
|
||||
|
||||
public static partial List<Variable> AdaptListVariable(this IEnumerable<Variable> src);
|
||||
|
||||
public static partial DeviceRuntime AdaptDeviceRuntime(this Device src);
|
||||
@@ -49,9 +62,7 @@ public static partial class GatewayMapper
|
||||
public static partial RedundancyOptions AdaptRedundancyOptions(this RedundancyOptions src);
|
||||
|
||||
public static partial List<DeviceDataWithValue> AdaptListDeviceDataWithValue(this IEnumerable<DeviceRuntime> src);
|
||||
public static partial List<Channel> AdaptListChannel(this List<ChannelInput> src);
|
||||
public static partial List<Device> AdaptListDevice(this List<DeviceInput> src);
|
||||
public static partial List<Variable> AdaptListVariable(this List<VariableInput> src);
|
||||
|
||||
public static partial Channel AdaptChannel(this Channel src);
|
||||
public static partial Device AdaptDevice(this Device src);
|
||||
public static partial Variable AdaptVariable(this Variable src);
|
||||
|
@@ -0,0 +1,87 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using BootstrapBlazor.Components;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
|
||||
public partial class AlarmRuntimePropertys
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public EventTypeEnum? EventType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警类型
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public AlarmTypeEnum? AlarmType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警值
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string AlarmCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 恢复值
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string RecoveryCode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
internal DateTime? PrepareAlarmEventTime { get; set; }
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
internal DateTime? PrepareFinishEventTime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 报警时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime AlarmTime { get; set; } = DateTime.UnixEpoch.ToLocalTime();
|
||||
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime FinishTime { get; set; } = DateTime.UnixEpoch.ToLocalTime();
|
||||
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime ConfirmTime { get; set; } = DateTime.UnixEpoch.ToLocalTime();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 报警限值
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string AlarmLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警文本
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string AlarmText { get; set; }
|
||||
|
||||
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime EventTime { get; set; } = DateTime.UnixEpoch.ToLocalTime();
|
||||
|
||||
internal object AlarmLockObject = new();
|
||||
internal bool AlarmConfirm;
|
||||
}
|
@@ -63,77 +63,86 @@ public class AlarmVariable : PrimaryIdEntity, IDBHistoryAlarm
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public DataTypeEnum DataType { get; set; }
|
||||
|
||||
/// <inheritdoc cref="Variable.AlarmLevel"/>
|
||||
/// <inheritdoc cref="AlarmPropertys.AlarmLevel"/>
|
||||
[SugarColumn(ColumnDescription = "报警等级", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public int AlarmLevel { get; set; }
|
||||
|
||||
/// <inheritdoc cref="VariableRuntime.AlarmCode"/>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.AlarmCode"/>
|
||||
[SugarColumn(ColumnDescription = "报警值", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public string AlarmCode { get; set; }
|
||||
|
||||
/// <inheritdoc cref="VariableRuntime.AlarmLimit"/>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.AlarmLimit"/>
|
||||
[SugarColumn(ColumnDescription = "报警限值", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public string AlarmLimit { get; set; }
|
||||
|
||||
/// <inheritdoc cref="VariableRuntime.AlarmText"/>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.AlarmText"/>
|
||||
[SugarColumn(ColumnDescription = "报警文本", IsNullable = true)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public string? AlarmText { get; set; }
|
||||
|
||||
/// <inheritdoc cref="VariableRuntime.RecoveryCode"/>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.RecoveryCode"/>
|
||||
[SugarColumn(ColumnDescription = "恢复值", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public string RecoveryCode { get; set; }
|
||||
|
||||
/// <inheritdoc cref="VariableRuntime.AlarmTime"/>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.AlarmTime"/>
|
||||
[SugarColumn(ColumnDescription = "报警时间", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public DateTime AlarmTime { get; set; }
|
||||
|
||||
/// <inheritdoc cref="VariableRuntime.EventTime"/>
|
||||
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.EventTime"/>
|
||||
[SugarColumn(ColumnDescription = "事件时间", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
[TimeDbSplitField(DateType.Month)]
|
||||
public DateTime EventTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警类型
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.FinishTime"/>
|
||||
[SugarColumn(ColumnDescription = "恢复时间", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
[TimeDbSplitField(DateType.Month)]
|
||||
public DateTime FinishTime { get; set; }
|
||||
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.ConfirmTime"/>
|
||||
[SugarColumn(ColumnDescription = "确认时间", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
[TimeDbSplitField(DateType.Month)]
|
||||
public DateTime ConfirmTime { get; set; }
|
||||
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.AlarmType"/>
|
||||
[SugarColumn(ColumnDescription = "报警类型", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public AlarmTypeEnum? AlarmType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="AlarmRuntimePropertys.EventType"/>
|
||||
[SugarColumn(ColumnDescription = "事件类型", IsNullable = false)]
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true)]
|
||||
public EventTypeEnum EventType { get; set; }
|
||||
|
||||
/// <inheritdoc cref="Device.Remark1"/>
|
||||
/// <inheritdoc cref="Variable.Remark1"/>
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Remark1 { get; set; }
|
||||
|
||||
/// <inheritdoc cref="Device.Remark2"/>
|
||||
/// <inheritdoc cref="Variable.Remark2"/>
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Remark2 { get; set; }
|
||||
|
||||
/// <inheritdoc cref="Device.Remark3"/>
|
||||
/// <inheritdoc cref="Variable.Remark3"/>
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Remark3 { get; set; }
|
||||
|
||||
/// <inheritdoc cref="Device.Remark4"/>
|
||||
/// <inheritdoc cref="Variable.Remark4"/>
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Remark4 { get; set; }
|
||||
|
||||
/// <inheritdoc cref="Device.Remark5"/>
|
||||
/// <inheritdoc cref="Variable.Remark5"/>
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string Remark5 { get; set; }
|
||||
|
@@ -21,33 +21,22 @@ namespace ThingsGateway.Gateway.Application;
|
||||
/// </summary>
|
||||
public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
{
|
||||
private DateTime? prepareAlarmEventTime;
|
||||
private DateTime? prepareFinishEventTime;
|
||||
private EventTypeEnum? eventType;
|
||||
|
||||
private AlarmTypeEnum? alarmType { get; set; }
|
||||
|
||||
private int index;
|
||||
private int sortCode;
|
||||
private DateTime changeTime = DateTime.UnixEpoch.ToLocalTime();
|
||||
private DateTime alarmTime;
|
||||
private DateTime eventTime;
|
||||
|
||||
private DateTime collectTime = DateTime.UnixEpoch.ToLocalTime();
|
||||
|
||||
private bool _isOnline;
|
||||
private bool _isOnlineChanged;
|
||||
private bool _valueInited;
|
||||
|
||||
private string alarmLimit;
|
||||
private string alarmText;
|
||||
private string alarmCode;
|
||||
private string _lastErrorMessage;
|
||||
private string recoveryCode;
|
||||
private object _value;
|
||||
private object lastSetValue;
|
||||
private object rawValue;
|
||||
internal object AlarmLockObject = new();
|
||||
internal bool AlarmConfirm;
|
||||
private DeviceRuntime? deviceRuntime;
|
||||
private IVariableSource? variableSource;
|
||||
private VariableMethod? variableMethod;
|
||||
@@ -183,9 +172,9 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
public void Init(DeviceRuntime deviceRuntime)
|
||||
{
|
||||
GlobalData.AlarmEnableIdVariables.Remove(Id);
|
||||
if (GlobalData.RealAlarmIdVariables.TryRemove(Id, out var oldAlarm))
|
||||
if (!AlarmEnable && GlobalData.RealAlarmIdVariables.TryRemove(Id, out var oldAlarm))
|
||||
{
|
||||
oldAlarm.EventType = EventTypeEnum.Finish;
|
||||
oldAlarm.EventType = EventTypeEnum.Restart;
|
||||
oldAlarm.EventTime = DateTime.Now;
|
||||
GlobalData.AlarmChange(this.AdaptAlarmVariable());
|
||||
}
|
||||
@@ -199,6 +188,7 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
GlobalData.IdVariables.TryAdd(Id, this);
|
||||
if (AlarmEnable)
|
||||
{
|
||||
this.AlarmRuntimePropertys = new();
|
||||
GlobalData.AlarmEnableIdVariables.TryAdd(Id, this);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +202,7 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
GlobalData.AlarmEnableIdVariables.Remove(Id);
|
||||
if (GlobalData.RealAlarmIdVariables.TryRemove(Id, out var oldAlarm))
|
||||
{
|
||||
oldAlarm.EventType = EventTypeEnum.Finish;
|
||||
oldAlarm.EventType = EventTypeEnum.Restart;
|
||||
oldAlarm.EventTime = DateTime.Now;
|
||||
GlobalData.AlarmChange(this.AdaptAlarmVariable());
|
||||
}
|
||||
|
@@ -24,45 +24,12 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
public bool ValueInited { get => _valueInited; set => _valueInited = value; }
|
||||
|
||||
#region 属性
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public EventTypeEnum? EventType { get => eventType; set => eventType = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警类型
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public AlarmTypeEnum? AlarmType { get => alarmType; set => alarmType = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警值
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string AlarmCode { get => alarmCode; set => alarmCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 恢复值
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string RecoveryCode { get => recoveryCode; set => recoveryCode = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 这个参数值由自动打包方法写入<see cref="IDevice.LoadSourceRead{T}(IEnumerable{IVariable}, int, string)"/>
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public int Index { get => index; set => index = value; }
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
internal DateTime? PrepareAlarmEventTime { get => prepareAlarmEventTime; set => prepareAlarmEventTime = value; }
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
internal DateTime? PrepareFinishEventTime { get => prepareFinishEventTime; set => prepareFinishEventTime = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 变化时间
|
||||
@@ -70,17 +37,6 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
[AutoGenerateColumn(Visible = true, Filterable = true, Sortable = true, Order = 5)]
|
||||
public DateTime ChangeTime { get => changeTime; set => changeTime = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime AlarmTime { get => alarmTime; set => alarmTime = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime EventTime { get => eventTime; set => eventTime = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 采集时间
|
||||
@@ -204,21 +160,13 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
|
||||
{
|
||||
get
|
||||
{
|
||||
return LAlarmEnable || LLAlarmEnable || HAlarmEnable || HHAlarmEnable || BoolOpenAlarmEnable || BoolCloseAlarmEnable || CustomAlarmEnable;
|
||||
return AlarmPropertys != null && (AlarmPropertys.LAlarmEnable || AlarmPropertys.LLAlarmEnable || AlarmPropertys.HAlarmEnable || AlarmPropertys.HHAlarmEnable || AlarmPropertys.BoolOpenAlarmEnable || AlarmPropertys.BoolCloseAlarmEnable || AlarmPropertys.CustomAlarmEnable);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报警限值
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string AlarmLimit { get => alarmLimit; set => alarmLimit = value; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警文本
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public string AlarmText { get => alarmText; set => alarmText = value; }
|
||||
[IgnoreExcel]
|
||||
[AutoGenerateColumn(Ignore = true)]
|
||||
public AlarmRuntimePropertys? AlarmRuntimePropertys { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
@@ -69,19 +69,19 @@ internal sealed class AlarmTask : IDisposable
|
||||
return null; // 如果是,则返回null
|
||||
}
|
||||
|
||||
if (tag.BoolCloseAlarmEnable && !tag.Value.ToBoolean(true)) // 检查是否启用了关闭报警功能,并且变量的布尔值为false
|
||||
if (tag.AlarmPropertys.BoolCloseAlarmEnable && !tag.Value.ToBoolean(true)) // 检查是否启用了关闭报警功能,并且变量的布尔值为false
|
||||
{
|
||||
limit = false.ToString(); // 将报警限制值设置为"false"
|
||||
expressions = tag.BoolCloseRestrainExpressions!; // 获取关闭报警的约束表达式
|
||||
text = tag.BoolCloseAlarmText!; // 获取关闭报警时的报警文本
|
||||
expressions = tag.AlarmPropertys.BoolCloseRestrainExpressions!; // 获取关闭报警的约束表达式
|
||||
text = tag.AlarmPropertys.BoolCloseAlarmText!; // 获取关闭报警时的报警文本
|
||||
return AlarmTypeEnum.Close; // 返回关闭报警类型枚举
|
||||
}
|
||||
|
||||
if (tag.BoolOpenAlarmEnable && tag.Value.ToBoolean(false)) // 检查是否启用了开启报警功能,并且变量的布尔值为true
|
||||
if (tag.AlarmPropertys.BoolOpenAlarmEnable && tag.Value.ToBoolean(false)) // 检查是否启用了开启报警功能,并且变量的布尔值为true
|
||||
{
|
||||
limit = true.ToString(); // 将报警限制值设置为"true"
|
||||
expressions = tag.BoolOpenRestrainExpressions!; // 获取开启报警的约束表达式
|
||||
text = tag.BoolOpenAlarmText!; // 获取开启报警时的报警文本
|
||||
expressions = tag.AlarmPropertys.BoolOpenRestrainExpressions!; // 获取开启报警的约束表达式
|
||||
text = tag.AlarmPropertys.BoolOpenAlarmText!; // 获取开启报警时的报警文本
|
||||
return AlarmTypeEnum.Open; // 返回开启报警类型枚举
|
||||
}
|
||||
|
||||
@@ -107,18 +107,18 @@ internal sealed class AlarmTask : IDisposable
|
||||
return null; // 如果是,则返回null
|
||||
}
|
||||
|
||||
if (tag.CustomAlarmEnable) // 检查是否启用了自定义报警功能
|
||||
if (tag.AlarmPropertys.CustomAlarmEnable) // 检查是否启用了自定义报警功能
|
||||
{
|
||||
// 调用变量的CustomAlarmCode属性的GetExpressionsResult方法,传入变量的值,获取报警表达式的计算结果
|
||||
var result = tag.CustomAlarmCode.GetExpressionsResult(tag.Value, tag.DeviceRuntime?.Driver?.LogMessage);
|
||||
var result = tag.AlarmPropertys.CustomAlarmCode.GetExpressionsResult(tag.Value, tag.DeviceRuntime?.Driver?.LogMessage);
|
||||
|
||||
if (result is bool boolResult) // 检查计算结果是否为布尔类型
|
||||
{
|
||||
if (boolResult) // 如果计算结果为true
|
||||
{
|
||||
limit = tag.CustomAlarmCode; // 将报警限制值设置为自定义报警代码
|
||||
expressions = tag.CustomRestrainExpressions!; // 获取自定义报警时的报警约束表达式
|
||||
text = tag.CustomAlarmText!; // 获取自定义报警时的报警文本
|
||||
limit = tag.AlarmPropertys.CustomAlarmCode; // 将报警限制值设置为自定义报警代码
|
||||
expressions = tag.AlarmPropertys.CustomRestrainExpressions!; // 获取自定义报警时的报警约束表达式
|
||||
text = tag.AlarmPropertys.CustomAlarmText!; // 获取自定义报警时的报警文本
|
||||
return AlarmTypeEnum.Custom; // 返回自定义报警类型枚举
|
||||
}
|
||||
}
|
||||
@@ -147,38 +147,38 @@ internal sealed class AlarmTask : IDisposable
|
||||
}
|
||||
|
||||
// 检查是否启用了高高报警功能,并且变量的值大于高高报警的限制值
|
||||
if (tag.HHAlarmEnable && tag.Value.ToDecimal() > tag.HHAlarmCode.ToDecimal())
|
||||
if (tag.AlarmPropertys.HHAlarmEnable && tag.Value.ToDecimal() > tag.AlarmPropertys.HHAlarmCode)
|
||||
{
|
||||
limit = tag.HHAlarmCode.ToString()!; // 将报警限制值设置为高高报警的限制值
|
||||
expressions = tag.HHRestrainExpressions!; // 获取高高报警的约束表达式
|
||||
text = tag.HHAlarmText!; // 获取高高报警时的报警文本
|
||||
limit = tag.AlarmPropertys.HHAlarmCode.ToString()!; // 将报警限制值设置为高高报警的限制值
|
||||
expressions = tag.AlarmPropertys.HHRestrainExpressions!; // 获取高高报警的约束表达式
|
||||
text = tag.AlarmPropertys.HHAlarmText!; // 获取高高报警时的报警文本
|
||||
return AlarmTypeEnum.HH; // 返回高高报警类型枚举
|
||||
}
|
||||
|
||||
// 检查是否启用了高报警功能,并且变量的值大于高报警的限制值
|
||||
if (tag.HAlarmEnable && tag.Value.ToDecimal() > tag.HAlarmCode.ToDecimal())
|
||||
if (tag.AlarmPropertys.HAlarmEnable && tag.Value.ToDecimal() > tag.AlarmPropertys.HAlarmCode)
|
||||
{
|
||||
limit = tag.HAlarmCode.ToString()!; // 将报警限制值设置为高报警的限制值
|
||||
expressions = tag.HRestrainExpressions!; // 获取高报警的约束表达式
|
||||
text = tag.HAlarmText!; // 获取高报警时的报警文本
|
||||
limit = tag.AlarmPropertys.HAlarmCode.ToString()!; // 将报警限制值设置为高报警的限制值
|
||||
expressions = tag.AlarmPropertys.HRestrainExpressions!; // 获取高报警的约束表达式
|
||||
text = tag.AlarmPropertys.HAlarmText!; // 获取高报警时的报警文本
|
||||
return AlarmTypeEnum.H; // 返回高报警类型枚举
|
||||
}
|
||||
|
||||
// 检查是否启用了低低报警功能,并且变量的值小于低低报警的限制值
|
||||
if (tag.LLAlarmEnable && tag.Value.ToDecimal() < tag.LLAlarmCode.ToDecimal())
|
||||
if (tag.AlarmPropertys.LLAlarmEnable && tag.Value.ToDecimal() < tag.AlarmPropertys.LLAlarmCode)
|
||||
{
|
||||
limit = tag.LLAlarmCode.ToString()!; // 将报警限制值设置为低低报警的限制值
|
||||
expressions = tag.LLRestrainExpressions!; // 获取低低报警的约束表达式
|
||||
text = tag.LLAlarmText!; // 获取低低报警时的报警文本
|
||||
limit = tag.AlarmPropertys.LLAlarmCode.ToString()!; // 将报警限制值设置为低低报警的限制值
|
||||
expressions = tag.AlarmPropertys.LLRestrainExpressions!; // 获取低低报警的约束表达式
|
||||
text = tag.AlarmPropertys.LLAlarmText!; // 获取低低报警时的报警文本
|
||||
return AlarmTypeEnum.LL; // 返回低低报警类型枚举
|
||||
}
|
||||
|
||||
// 检查是否启用了低报警功能,并且变量的值小于低报警的限制值
|
||||
if (tag.LAlarmEnable && tag.Value.ToDecimal() < tag.LAlarmCode.ToDecimal())
|
||||
if (tag.AlarmPropertys.LAlarmEnable && tag.Value.ToDecimal() < tag.AlarmPropertys.LAlarmCode)
|
||||
{
|
||||
limit = tag.LAlarmCode.ToString()!; // 将报警限制值设置为低报警的限制值
|
||||
expressions = tag.LRestrainExpressions!; // 获取低报警的约束表达式
|
||||
text = tag.LAlarmText!; // 获取低报警时的报警文本
|
||||
limit = tag.AlarmPropertys.LAlarmCode.ToString()!; // 将报警限制值设置为低报警的限制值
|
||||
expressions = tag.AlarmPropertys.LRestrainExpressions!; // 获取低报警的约束表达式
|
||||
text = tag.AlarmPropertys.LAlarmText!; // 获取低报警时的报警文本
|
||||
return AlarmTypeEnum.L; // 返回低报警类型枚举
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ internal sealed class AlarmTask : IDisposable
|
||||
string ex; // 报警约束表达式
|
||||
string text; // 报警文本
|
||||
AlarmTypeEnum? alarmEnum; // 报警类型枚举
|
||||
int delay = item.AlarmDelay; // 获取报警延迟时间
|
||||
int delay = item.AlarmPropertys.AlarmDelay; // 获取报警延迟时间
|
||||
|
||||
// 检查变量的数据类型
|
||||
if (item.Value?.GetType() == typeof(bool))
|
||||
@@ -235,6 +235,10 @@ internal sealed class AlarmTask : IDisposable
|
||||
// 如果表达式结果为true,则触发报警事件
|
||||
AlarmChange(item, limit, text, false, alarmEnum, delay);
|
||||
}
|
||||
else
|
||||
{
|
||||
AlarmChange(item, limit, text, true, alarmEnum, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -256,7 +260,7 @@ internal sealed class AlarmTask : IDisposable
|
||||
/// <param name="delay">报警延时</param>
|
||||
private static void AlarmChange(VariableRuntime item, object limit, string text, bool finish, AlarmTypeEnum? alarmEnum, int delay)
|
||||
{
|
||||
lock (item.AlarmLockObject)
|
||||
lock (item.AlarmRuntimePropertys.AlarmLockObject)
|
||||
{
|
||||
bool changed = false;
|
||||
if (finish)
|
||||
@@ -270,14 +274,14 @@ internal sealed class AlarmTask : IDisposable
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.EventType != EventTypeEnum.Confirm)
|
||||
item.AlarmConfirm = false;
|
||||
if (item.AlarmRuntimePropertys.EventType != EventTypeEnum.Confirm)
|
||||
item.AlarmRuntimePropertys.AlarmConfirm = false;
|
||||
// 如果是触发报警事件
|
||||
// 在实时报警列表中查找该变量
|
||||
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var variable))
|
||||
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var variable) && (variable.EventType == EventTypeEnum.Alarm || variable.EventType == EventTypeEnum.Confirm))
|
||||
{
|
||||
// 如果变量已经处于相同的报警类型,则直接返回
|
||||
if (item.AlarmType == alarmEnum)
|
||||
if (item.AlarmRuntimePropertys.AlarmType == alarmEnum)
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -289,48 +293,48 @@ internal sealed class AlarmTask : IDisposable
|
||||
//添加报警延时策略
|
||||
if (delay > 0)
|
||||
{
|
||||
if (item.EventType != EventTypeEnum.Alarm && item.EventType != EventTypeEnum.PrepareAlarm)
|
||||
if (item.AlarmRuntimePropertys.EventType != EventTypeEnum.Alarm && item.AlarmRuntimePropertys.EventType != EventTypeEnum.PrepareAlarm)
|
||||
{
|
||||
item.EventType = EventTypeEnum.PrepareAlarm;//准备报警
|
||||
item.PrepareAlarmEventTime = now;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.PrepareAlarm;//准备报警
|
||||
item.AlarmRuntimePropertys.PrepareAlarmEventTime = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.EventType == EventTypeEnum.PrepareAlarm)
|
||||
if (item.AlarmRuntimePropertys.EventType == EventTypeEnum.PrepareAlarm)
|
||||
{
|
||||
if ((now - item.PrepareAlarmEventTime!.Value).TotalMilliseconds > delay)
|
||||
if ((now - item.AlarmRuntimePropertys.PrepareAlarmEventTime!.Value).TotalMilliseconds > delay)
|
||||
{
|
||||
//超过延时时间,触发报警
|
||||
item.EventType = EventTypeEnum.Alarm;
|
||||
item.AlarmTime = now;
|
||||
item.EventTime = now;
|
||||
item.AlarmType = alarmEnum;
|
||||
item.AlarmLimit = limit.ToString();
|
||||
item.AlarmCode = item.Value.ToString();
|
||||
item.RecoveryCode = string.Empty;
|
||||
item.AlarmText = text;
|
||||
item.PrepareAlarmEventTime = null;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.Alarm;
|
||||
item.AlarmRuntimePropertys.AlarmTime = now;
|
||||
item.AlarmRuntimePropertys.EventTime = now;
|
||||
item.AlarmRuntimePropertys.AlarmType = alarmEnum;
|
||||
item.AlarmRuntimePropertys.AlarmLimit = limit.ToString();
|
||||
item.AlarmRuntimePropertys.AlarmCode = item.Value.ToString();
|
||||
item.AlarmRuntimePropertys.RecoveryCode = string.Empty;
|
||||
item.AlarmRuntimePropertys.AlarmText = text;
|
||||
item.AlarmRuntimePropertys.PrepareAlarmEventTime = null;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (item.EventType == EventTypeEnum.Alarm && item.AlarmType != alarmEnum)
|
||||
else if (item.AlarmRuntimePropertys.EventType == EventTypeEnum.Alarm && item.AlarmRuntimePropertys.AlarmType != alarmEnum)
|
||||
{
|
||||
//报警类型改变,重新计时
|
||||
if (item.PrepareAlarmEventTime == null)
|
||||
item.PrepareAlarmEventTime = now;
|
||||
if ((now - item.PrepareAlarmEventTime!.Value).TotalMilliseconds > delay)
|
||||
if (item.AlarmRuntimePropertys.PrepareAlarmEventTime == null)
|
||||
item.AlarmRuntimePropertys.PrepareAlarmEventTime = now;
|
||||
if ((now - item.AlarmRuntimePropertys.PrepareAlarmEventTime!.Value).TotalMilliseconds > delay)
|
||||
{
|
||||
//超过延时时间,触发报警
|
||||
item.EventType = EventTypeEnum.Alarm;
|
||||
item.AlarmTime = now;
|
||||
item.EventTime = now;
|
||||
item.AlarmType = alarmEnum;
|
||||
item.AlarmLimit = limit.ToString();
|
||||
item.AlarmCode = item.Value.ToString();
|
||||
item.RecoveryCode = string.Empty;
|
||||
item.AlarmText = text;
|
||||
item.PrepareAlarmEventTime = null;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.Alarm;
|
||||
item.AlarmRuntimePropertys.AlarmTime = now;
|
||||
item.AlarmRuntimePropertys.EventTime = now;
|
||||
item.AlarmRuntimePropertys.AlarmType = alarmEnum;
|
||||
item.AlarmRuntimePropertys.AlarmLimit = limit.ToString();
|
||||
item.AlarmRuntimePropertys.AlarmCode = item.Value.ToString();
|
||||
item.AlarmRuntimePropertys.RecoveryCode = string.Empty;
|
||||
item.AlarmRuntimePropertys.AlarmText = text;
|
||||
item.AlarmRuntimePropertys.PrepareAlarmEventTime = null;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -343,15 +347,15 @@ internal sealed class AlarmTask : IDisposable
|
||||
else
|
||||
{
|
||||
// 如果是触发报警事件
|
||||
item.EventType = EventTypeEnum.Alarm;
|
||||
item.AlarmTime = now;
|
||||
item.EventTime = now;
|
||||
item.AlarmType = alarmEnum;
|
||||
item.AlarmLimit = limit.ToString();
|
||||
item.AlarmCode = item.Value.ToString();
|
||||
item.RecoveryCode = string.Empty;
|
||||
item.AlarmText = text;
|
||||
item.PrepareAlarmEventTime = null;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.Alarm;
|
||||
item.AlarmRuntimePropertys.AlarmTime = now;
|
||||
item.AlarmRuntimePropertys.EventTime = now;
|
||||
item.AlarmRuntimePropertys.AlarmType = alarmEnum;
|
||||
item.AlarmRuntimePropertys.AlarmLimit = limit.ToString();
|
||||
item.AlarmRuntimePropertys.AlarmCode = item.Value.ToString();
|
||||
item.AlarmRuntimePropertys.RecoveryCode = string.Empty;
|
||||
item.AlarmRuntimePropertys.AlarmText = text;
|
||||
item.AlarmRuntimePropertys.PrepareAlarmEventTime = null;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -361,30 +365,31 @@ internal sealed class AlarmTask : IDisposable
|
||||
//添加报警延时策略
|
||||
if (delay > 0)
|
||||
{
|
||||
if (item.EventType != EventTypeEnum.Finish && item.EventType != EventTypeEnum.PrepareFinish)
|
||||
if (item.AlarmRuntimePropertys.EventType != EventTypeEnum.Finish && item.AlarmRuntimePropertys.EventType != EventTypeEnum.PrepareFinish)
|
||||
{
|
||||
item.EventType = EventTypeEnum.PrepareFinish;
|
||||
item.PrepareFinishEventTime = now;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.PrepareFinish;
|
||||
item.AlarmRuntimePropertys.PrepareFinishEventTime = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.EventType == EventTypeEnum.PrepareFinish)
|
||||
if (item.AlarmRuntimePropertys.EventType == EventTypeEnum.PrepareFinish)
|
||||
{
|
||||
if ((now - item.PrepareFinishEventTime!.Value).TotalMilliseconds > delay)
|
||||
if ((now - item.AlarmRuntimePropertys.PrepareFinishEventTime!.Value).TotalMilliseconds > delay)
|
||||
{
|
||||
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var oldAlarm))
|
||||
{
|
||||
item.AlarmType = oldAlarm.AlarmType;
|
||||
item.AlarmLimit = oldAlarm.AlarmLimit;
|
||||
item.AlarmCode = oldAlarm.AlarmCode;
|
||||
item.RecoveryCode = item.Value.ToString();
|
||||
item.AlarmText = oldAlarm.AlarmText;
|
||||
if (item.EventType != EventTypeEnum.Finish)
|
||||
item.AlarmRuntimePropertys.AlarmType = oldAlarm.AlarmType;
|
||||
item.AlarmRuntimePropertys.AlarmLimit = oldAlarm.AlarmLimit;
|
||||
item.AlarmRuntimePropertys.AlarmCode = oldAlarm.AlarmCode;
|
||||
item.AlarmRuntimePropertys.RecoveryCode = item.Value.ToString();
|
||||
item.AlarmRuntimePropertys.AlarmText = oldAlarm.AlarmText;
|
||||
if (item.AlarmRuntimePropertys.EventType != EventTypeEnum.Finish)
|
||||
{
|
||||
item.EventTime = now;
|
||||
item.AlarmRuntimePropertys.FinishTime = now;
|
||||
item.AlarmRuntimePropertys.EventTime = now;
|
||||
}
|
||||
item.EventType = EventTypeEnum.Finish;
|
||||
item.PrepareFinishEventTime = null;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.Finish;
|
||||
item.AlarmRuntimePropertys.PrepareFinishEventTime = null;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -399,20 +404,24 @@ internal sealed class AlarmTask : IDisposable
|
||||
{
|
||||
// 如果是需恢复报警事件
|
||||
// 获取旧的报警信息
|
||||
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var oldAlarm))
|
||||
if (item.AlarmRuntimePropertys.EventType != EventTypeEnum.Finish && item.AlarmRuntimePropertys.EventType != EventTypeEnum.PrepareFinish)
|
||||
{
|
||||
item.AlarmType = oldAlarm.AlarmType;
|
||||
item.AlarmLimit = oldAlarm.AlarmLimit;
|
||||
item.AlarmCode = oldAlarm.AlarmCode;
|
||||
item.RecoveryCode = item.Value.ToString();
|
||||
item.AlarmText = oldAlarm.AlarmText;
|
||||
if (item.EventType != EventTypeEnum.Finish)
|
||||
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var oldAlarm))
|
||||
{
|
||||
item.EventTime = now;
|
||||
item.AlarmRuntimePropertys.AlarmType = oldAlarm.AlarmType;
|
||||
item.AlarmRuntimePropertys.AlarmLimit = oldAlarm.AlarmLimit;
|
||||
item.AlarmRuntimePropertys.AlarmCode = oldAlarm.AlarmCode;
|
||||
item.AlarmRuntimePropertys.RecoveryCode = item.Value.ToString();
|
||||
item.AlarmRuntimePropertys.AlarmText = oldAlarm.AlarmText;
|
||||
if (item.AlarmRuntimePropertys.EventType != EventTypeEnum.Finish)
|
||||
{
|
||||
item.AlarmRuntimePropertys.FinishTime = now;
|
||||
item.AlarmRuntimePropertys.EventTime = now;
|
||||
}
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.Finish;
|
||||
item.AlarmRuntimePropertys.PrepareFinishEventTime = null;
|
||||
changed = true;
|
||||
}
|
||||
item.EventType = EventTypeEnum.Finish;
|
||||
item.PrepareFinishEventTime = null;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,7 +429,7 @@ internal sealed class AlarmTask : IDisposable
|
||||
// 触发报警变化事件
|
||||
if (changed)
|
||||
{
|
||||
if (item.EventType == EventTypeEnum.Alarm)
|
||||
if (item.AlarmRuntimePropertys.EventType == EventTypeEnum.Alarm)
|
||||
{
|
||||
// 如果是触发报警事件
|
||||
//lock (GlobalData. RealAlarmVariables)
|
||||
@@ -429,14 +438,14 @@ internal sealed class AlarmTask : IDisposable
|
||||
GlobalData.RealAlarmIdVariables.AddOrUpdate(item.Id, a => item.AdaptAlarmVariable(), (a, b) => item.AdaptAlarmVariable());
|
||||
}
|
||||
}
|
||||
else if (item.EventType == EventTypeEnum.Finish)
|
||||
else if (item.AlarmRuntimePropertys.EventType == EventTypeEnum.Finish)
|
||||
{
|
||||
|
||||
// 如果是需恢复报警事件,则从实时报警列表中移除该变量
|
||||
if (item.AlarmConfirm)
|
||||
if (item.AlarmRuntimePropertys.AlarmConfirm)
|
||||
{
|
||||
GlobalData.RealAlarmIdVariables.TryRemove(item.Id, out _);
|
||||
item.EventType = EventTypeEnum.ConfirmAndFinish;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.ConfirmAndFinish;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -454,19 +463,20 @@ internal sealed class AlarmTask : IDisposable
|
||||
// 如果是确认报警事件
|
||||
if (GlobalData.AlarmEnableIdVariables.TryGetValue(variableId, out var item))
|
||||
{
|
||||
lock (item.AlarmLockObject)
|
||||
lock (item.AlarmRuntimePropertys.AlarmLockObject)
|
||||
{
|
||||
item.AlarmConfirm = true;
|
||||
item.EventTime = DateTime.Now;
|
||||
item.AlarmRuntimePropertys.AlarmConfirm = true;
|
||||
item.AlarmRuntimePropertys.ConfirmTime = DateTime.Now;
|
||||
item.AlarmRuntimePropertys.EventTime = item.AlarmRuntimePropertys.ConfirmTime;
|
||||
|
||||
if (item.EventType == EventTypeEnum.Finish)
|
||||
if (item.AlarmRuntimePropertys.EventType == EventTypeEnum.Finish)
|
||||
{
|
||||
item.EventType = EventTypeEnum.ConfirmAndFinish;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.ConfirmAndFinish;
|
||||
GlobalData.RealAlarmIdVariables.TryRemove(variableId, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.EventType = EventTypeEnum.Confirm;
|
||||
item.AlarmRuntimePropertys.EventType = EventTypeEnum.Confirm;
|
||||
GlobalData.RealAlarmIdVariables.AddOrUpdate(variableId, a => item.AdaptAlarmVariable(), (a, b) => item.AdaptAlarmVariable());
|
||||
}
|
||||
|
||||
|
@@ -622,7 +622,7 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
// 变量页处理
|
||||
if (sheetName == ExportString.VariableName)
|
||||
{
|
||||
int row = 0;
|
||||
int row = 1;
|
||||
ImportPreviewOutput<Dictionary<string, Variable>> importPreviewOutput = new();
|
||||
ImportPreviews.Add(sheetName, importPreviewOutput);
|
||||
deviceImportPreview = importPreviewOutput;
|
||||
@@ -721,7 +721,97 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
|
||||
// 将变量列表转换为字典,并赋值给导入预览输出对象的 Data 属性
|
||||
importPreviewOutput.Data = variables.OrderBy(a => a.Row).GroupBy(a => a.DeviceId.ToString()).ToDictionary(a => a.Key, b => b.ToDictionary(a => a.Name));
|
||||
}
|
||||
else if (sheetName == ExportString.AlarmName)
|
||||
{
|
||||
int row = 1;
|
||||
ImportPreviewOutput<string> importPreviewOutput = new();
|
||||
ImportPreviews.Add(sheetName, importPreviewOutput);
|
||||
var type = typeof(AlarmPropertys);
|
||||
// 获取目标类型的所有属性,并根据是否需要过滤 IgnoreExcelAttribute 进行筛选
|
||||
var variableProperties = type.GetRuntimeProperties().Where(a => (a.GetCustomAttribute<IgnoreExcelAttribute>() == null) && a.CanWrite)
|
||||
.ToDictionary(a => type.GetPropertyDisplayName(a.Name), a => (a, a.IsNullableType()));
|
||||
|
||||
// 并行处理每一行数据
|
||||
rows.ParallelForEachStreamed((item, state, index) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var alarm = item.ConvertToEntity<AlarmPropertys>(variableProperties);
|
||||
|
||||
// 如果转换失败,则添加错误信息到导入预览结果并返回
|
||||
if (alarm == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["ImportNullError"]));
|
||||
return;
|
||||
}
|
||||
|
||||
// 转化插件名称和变量名称
|
||||
item.TryGetValue(ExportString.VariableName, out var variableNameObj);
|
||||
item.TryGetValue(ExportString.DeviceName, out var collectDevName);
|
||||
deviceDicts.TryGetValue(collectDevName?.ToString(), out var collectDevice);
|
||||
// 如果设备名称或变量名称为空,或者找不到对应的设备,则添加错误信息到导入预览结果并返回
|
||||
if (collectDevName == null || collectDevice == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["DeviceNotNull"]));
|
||||
return;
|
||||
}
|
||||
if (variableNameObj == null)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["VariableNotNull"]));
|
||||
return;
|
||||
}
|
||||
|
||||
// 对对象进行验证
|
||||
var validationContext = new ValidationContext(alarm);
|
||||
var validationResults = new List<ValidationResult>();
|
||||
validationContext.ValidateProperty(validationResults);
|
||||
|
||||
// 构建验证结果的错误信息
|
||||
StringBuilder stringBuilder = new();
|
||||
foreach (var validationResult in validationResults.Where(v => !string.IsNullOrEmpty(v.ErrorMessage)))
|
||||
{
|
||||
foreach (var memberName in validationResult.MemberNames)
|
||||
{
|
||||
stringBuilder.Append(validationResult.ErrorMessage!);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有验证错误,则添加错误信息到导入预览结果并返回
|
||||
if (stringBuilder.Length > 0)
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, stringBuilder.ToString()));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取变量名称并检查是否存在于设备导入预览数据中
|
||||
var variableName = variableNameObj?.ToString();
|
||||
// 如果存在,则更新变量属性字典,并添加成功信息到导入预览结果;否则,添加错误信息到导入预览结果并返回
|
||||
if (deviceImportPreview.Data.TryGetValue(collectDevice.Id.ToString(), out var deviceVariables) && deviceVariables.TryGetValue(variableName, out var deviceVariable))
|
||||
{
|
||||
deviceVariable.AlarmPropertys = alarm;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), true, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, Localizer["VariableNotNull"]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获异常并添加错误信息到导入预览结果
|
||||
importPreviewOutput.HasError = true;
|
||||
importPreviewOutput.Results.Add((Interlocked.Increment(ref row), false, ex.Message));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
// 其他工作表处理
|
||||
else
|
||||
{
|
||||
|
@@ -98,6 +98,7 @@ IReadOnlyDictionary<long, ChannelRuntime> channelDicts)
|
||||
|
||||
// 主变量页
|
||||
sheets.Add(ExportString.VariableName, GetVariableSheets(data, deviceDicts, deviceName));
|
||||
sheets.Add(ExportString.AlarmName, GetAlarmSheets(data, deviceDicts, deviceName));
|
||||
|
||||
// 插件页(动态推导)
|
||||
foreach (var plugin in pluginDrivers.Keys.Distinct())
|
||||
@@ -151,6 +152,46 @@ IReadOnlyDictionary<long, ChannelRuntime> channelDicts)
|
||||
return row;
|
||||
}
|
||||
|
||||
static IEnumerable<Dictionary<string, object>> GetAlarmSheets(
|
||||
IEnumerable<Variable> data,
|
||||
IReadOnlyDictionary<long, DeviceRuntime> deviceDicts,
|
||||
string? deviceName)
|
||||
{
|
||||
var type = typeof(AlarmPropertys);
|
||||
var propertyInfos = type.GetRuntimeProperties()
|
||||
.Where(a => a.GetCustomAttribute<IgnoreExcelAttribute>(false) == null)
|
||||
.OrderBy(a =>
|
||||
{
|
||||
var order = a.GetCustomAttribute<AutoGenerateColumnAttribute>()?.Order ?? int.MaxValue;
|
||||
if (order < 0) order += 10000000;
|
||||
else if (order == 0) order = 10000000;
|
||||
return order;
|
||||
});
|
||||
|
||||
foreach (var variable in data)
|
||||
{
|
||||
if (variable.AlarmPropertys != null)
|
||||
yield return GetAlarm(deviceDicts, deviceName, type, propertyInfos, variable);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> GetAlarm(IReadOnlyDictionary<long, DeviceRuntime> deviceDicts, string? deviceName, Type type, IOrderedEnumerable<PropertyInfo> propertyInfos, Variable variable)
|
||||
{
|
||||
var row = new Dictionary<string, object>();
|
||||
deviceDicts.TryGetValue(variable.DeviceId, out var device);
|
||||
row.TryAdd(ExportString.DeviceName, device?.Name ?? deviceName);
|
||||
row.TryAdd(ExportString.VariableName, variable.Name);
|
||||
|
||||
foreach (var item in propertyInfos)
|
||||
{
|
||||
var desc = type.GetPropertyDisplayName(item.Name);
|
||||
row.TryAdd(desc ?? item.Name, item.GetValue(variable.AlarmPropertys)?.ToString());
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
static IEnumerable<Dictionary<string, object>> GetPluginSheets(
|
||||
IEnumerable<Variable> data,
|
||||
IReadOnlyDictionary<long, DeviceRuntime> deviceDicts,
|
||||
@@ -327,6 +368,7 @@ IReadOnlyDictionary<long, ChannelRuntime> channelDicts)
|
||||
Dictionary<string, object> sheets = new();
|
||||
//变量页
|
||||
ConcurrentList<Dictionary<string, object>> variableExports = new();
|
||||
ConcurrentList<Dictionary<string, object>> alarmExports = new();
|
||||
//变量附加属性,转成Dict<表名,List<Dict<列名,列数据>>>的形式
|
||||
ConcurrentDictionary<string, ConcurrentList<Dictionary<string, object>>> devicePropertys = new();
|
||||
ConcurrentDictionary<string, (VariablePropertyBase, Dictionary<string, PropertyInfo>)> propertysDict = new();
|
||||
@@ -352,29 +394,68 @@ IReadOnlyDictionary<long, ChannelRuntime> channelDicts)
|
||||
)
|
||||
;
|
||||
|
||||
var alarmPropertysType = typeof(AlarmPropertys);
|
||||
var alarmPropertysInfos = alarmPropertysType.GetRuntimeProperties().Where(a => a.GetCustomAttribute<IgnoreExcelAttribute>(false) == null)
|
||||
.OrderBy(
|
||||
a =>
|
||||
{
|
||||
var order = a.GetCustomAttribute<AutoGenerateColumnAttribute>()?.Order ?? int.MaxValue;
|
||||
if (order < 0)
|
||||
{
|
||||
order = order + 10000000;
|
||||
}
|
||||
else if (order == 0)
|
||||
{
|
||||
order = 10000000;
|
||||
}
|
||||
return order;
|
||||
}
|
||||
)
|
||||
;
|
||||
|
||||
#endregion 列名称
|
||||
data.ParallelForEachStreamed((variable, state, index) =>
|
||||
{
|
||||
Dictionary<string, object> varExport = new();
|
||||
deviceDicts.TryGetValue(variable.DeviceId, out var device);
|
||||
//设备实体没有包含设备名称,手动插入
|
||||
varExport.TryAdd(ExportString.DeviceName, device?.Name ?? deviceName);
|
||||
foreach (var item in propertyInfos)
|
||||
{
|
||||
if (item.Name == nameof(Variable.Id))
|
||||
Dictionary<string, object> varExport = new();
|
||||
deviceDicts.TryGetValue(variable.DeviceId, out var device);
|
||||
//设备实体没有包含设备名称,手动插入
|
||||
varExport.TryAdd(ExportString.DeviceName, device?.Name ?? deviceName);
|
||||
foreach (var item in propertyInfos)
|
||||
{
|
||||
if (sortName != nameof(Variable.Id))
|
||||
continue;
|
||||
if (item.Name == nameof(Variable.Id))
|
||||
{
|
||||
if (sortName != nameof(Variable.Id))
|
||||
continue;
|
||||
}
|
||||
//描述
|
||||
var desc = type.GetPropertyDisplayName(item.Name);
|
||||
//数据源增加
|
||||
varExport.TryAdd(desc ?? item.Name, item.GetValue(variable)?.ToString());
|
||||
}
|
||||
//描述
|
||||
var desc = type.GetPropertyDisplayName(item.Name);
|
||||
//数据源增加
|
||||
varExport.TryAdd(desc ?? item.Name, item.GetValue(variable)?.ToString());
|
||||
|
||||
//添加完整设备信息
|
||||
variableExports.Add(varExport);
|
||||
|
||||
}
|
||||
if (variable.AlarmPropertys != null)
|
||||
{
|
||||
Dictionary<string, object> alarmExport = new();
|
||||
deviceDicts.TryGetValue(variable.DeviceId, out var device);
|
||||
//设备实体没有包含设备名称,手动插入
|
||||
alarmExport.TryAdd(ExportString.DeviceName, device?.Name ?? deviceName);
|
||||
alarmExport.TryAdd(ExportString.VariableName, variable.Name);
|
||||
foreach (var item in alarmPropertysInfos)
|
||||
{
|
||||
//描述
|
||||
var desc = alarmPropertysType.GetPropertyDisplayName(item.Name);
|
||||
//数据源增加
|
||||
alarmExport.TryAdd(desc ?? item.Name, item.GetValue(variable.AlarmPropertys)?.ToString());
|
||||
}
|
||||
|
||||
//添加完整设备信息
|
||||
variableExports.Add(varExport);
|
||||
|
||||
//添加完整设备信息
|
||||
alarmExports.Add(alarmExport);
|
||||
}
|
||||
#region 插件sheet
|
||||
if (variable.VariablePropertys != null)
|
||||
{
|
||||
@@ -485,6 +566,7 @@ IReadOnlyDictionary<long, ChannelRuntime> channelDicts)
|
||||
|
||||
//添加设备页
|
||||
sheets.Add(ExportString.VariableName, variableExports);
|
||||
sheets.Add(ExportString.AlarmName, alarmExports);
|
||||
|
||||
//HASH
|
||||
foreach (var item in devicePropertys.Keys)
|
||||
|
@@ -157,7 +157,11 @@
|
||||
</TabItem>
|
||||
|
||||
<TabItem Text=@GatewayLocalizer["AlarmInformation"]>
|
||||
<EditorForm class="p-2" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=2 LabelWidth=250 Model="Model">
|
||||
<ValidateForm Model="Model.AlarmPropertys" @ref=Model.AlarmPropertysValidateForm
|
||||
@key=@($"VariableEditAlarmPropertysValidateForm{Model.Id}")
|
||||
Id=@($"VariableEditAlarmPropertysValidateForm{Model.Id}")>
|
||||
|
||||
<EditorForm class="p-2" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=2 LabelWidth=250 Model="Model.AlarmPropertys">
|
||||
<FieldItems>
|
||||
|
||||
<EditorItem @bind-Field="@context.BoolCloseAlarmText" />
|
||||
@@ -188,9 +192,11 @@
|
||||
<EditorItem @bind-Field="@context.CustomAlarmEnable" />
|
||||
<EditorItem @bind-Field="@context.AlarmDelay" />
|
||||
<EditorItem @bind-Field="@context.AlarmLevel" />
|
||||
|
||||
|
||||
</FieldItems>
|
||||
</EditorForm>
|
||||
|
||||
</ValidateForm>
|
||||
</TabItem>
|
||||
@if (!BatchEditEnable)
|
||||
{
|
||||
|
@@ -80,8 +80,15 @@ public partial class VariableEditComponent
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Model.AlarmPropertysValidateForm?.Validate() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OnValidSubmit != null)
|
||||
await OnValidSubmit.Invoke();
|
||||
|
||||
|
||||
if (OnCloseAsync != null)
|
||||
await OnCloseAsync();
|
||||
await ToastService.Default();
|
||||
@@ -91,11 +98,11 @@ public partial class VariableEditComponent
|
||||
await ToastService.Warn(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
Model.AlarmPropertys ??= new();
|
||||
Model.VariablePropertys ??= new();
|
||||
foreach (var item in Model.VariablePropertys)
|
||||
{
|
||||
|
@@ -255,6 +255,12 @@ public partial class VariableRuntimeInfo : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
variable.AlarmPropertys ??= new();
|
||||
if (variable.AlarmPropertysValidateForm?.Validate() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
variable.VariablePropertys = PluginServiceUtil.SetDict(variable.VariablePropertyModels);
|
||||
variable = variable.AdaptVariable();
|
||||
return await Task.Run(() => GlobalData.VariableRuntimeService.SaveVariableAsync(variable, itemChangedType, AutoRestartThread, default));
|
||||
|
@@ -51,6 +51,8 @@
|
||||
<TableColumn @bind-Field="@context.AlarmText" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.AlarmType" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.RecoveryCode" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.FinishTime" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.ConfirmTime" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.EventTime" Filterable=true Sortable=true Visible=true />
|
||||
<TableColumn @bind-Field="@context.EventType" Filterable=true Sortable=true Visible=true />
|
||||
|
||||
|
@@ -74,6 +74,8 @@
|
||||
"Description": "Description",
|
||||
"DeviceName": "DeviceName",
|
||||
"EventTime": "EventTime",
|
||||
"ConfirmTime": "ConfirmTime",
|
||||
"FinishTime": "FinishTime",
|
||||
"EventType": "EventType",
|
||||
"Name": "Name",
|
||||
"RecoveryCode": "RecoveryCode",
|
||||
|
@@ -74,6 +74,8 @@
|
||||
"Description": "描述",
|
||||
"DeviceName": "采集设备",
|
||||
"EventTime": "事件时间",
|
||||
"ConfirmTime": "确认时间",
|
||||
"FinishTime": "恢复时间",
|
||||
"EventType": "事件类型",
|
||||
"Name": "名称",
|
||||
"RecoveryCode": "恢复值",
|
||||
|
@@ -79,7 +79,7 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheAlarm, IDBHistoryAla
|
||||
using var db = BusinessDatabaseUtil.GetDb((DbType)_driverPropertys.DbType, _driverPropertys.BigTextConnectStr);
|
||||
var query = db.Queryable<HistoryAlarm>().AS(_driverPropertys.TableName)
|
||||
.WhereIF(input.StartTime != null, a => a.EventTime >= input.StartTime)
|
||||
.WhereIF(input.EndTime != null, a => a.EventTime <= input.EndTime)
|
||||
.WhereIF(input.EndTime != null, a => a.AlarmTime <= input.EndTime)
|
||||
.WhereIF(!string.IsNullOrEmpty(input.VariableName), it => it.Name.Contains(input.VariableName))
|
||||
.WhereIF(input.AlarmType != null, a => a.AlarmType == input.AlarmType)
|
||||
.WhereIF(input.EventType != null, a => a.EventType == input.EventType)
|
||||
|
Reference in New Issue
Block a user