mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-24 04:17:08 +08:00
添加部分代码注释
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.0.5</Version>
|
||||
<Title>ThingsGateway.Foundation.Adapter.Modbus</Title>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.0.5</Version>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.0.5</Version>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<OutputType>Library</OutputType>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.0.5</Version>
|
||||
<Title>ThingsGateway.Foundation.Adapter.Siemens</Title>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
|
||||
@@ -3,9 +3,16 @@ using Xunit.Abstractions;
|
||||
|
||||
namespace ThingsGateway.Foundation.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试超时等待
|
||||
/// </summary>
|
||||
public class WaitingTest
|
||||
{
|
||||
private ITestOutputHelper _output;
|
||||
/// <summary>
|
||||
/// 测试超时等待
|
||||
/// </summary>
|
||||
/// <param name="output"></param>
|
||||
public WaitingTest(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
|
||||
@@ -60,7 +60,6 @@ namespace ThingsGateway.Modbus
|
||||
_plc?.Dispose();
|
||||
}
|
||||
private UploadDevice curDevice;
|
||||
private TouchSocketConfig TouchSocketConfig = new();
|
||||
protected override void Init(UploadDevice device)
|
||||
{
|
||||
curDevice = device;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
<Version>1.1.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.1.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace ThingsGateway.OPCDA
|
||||
internal CollectDeviceRunTime Device;
|
||||
private List<CollectVariableRunTime> _deviceVariables = new();
|
||||
internal ThingsGateway.Foundation.Adapter.OPCDA.OPCDAClient PLC = null;
|
||||
public override System.Type DriverUI => typeof(ImportVariable);
|
||||
public override System.Type DriverImportUI => typeof(ImportVariable);
|
||||
|
||||
public OPCDAClient(IServiceScopeFactory scopeFactory) : base(scopeFactory)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.1.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ThingsGateway.OPCUA
|
||||
[DeviceProperty("登录密码", "")] public string Password { get; set; }
|
||||
[DeviceProperty("激活订阅", "")] public bool ActiveSubscribe { get; set; } = true;
|
||||
[DeviceProperty("死区", "")] public float DeadBand { get; set; } = 0;
|
||||
public override Type DriverUI => typeof(ImportVariable);
|
||||
public override Type DriverImportUI => typeof(ImportVariable);
|
||||
[DeviceProperty("自动分组大小", "")] public int GroupSize { get; set; } = 500;
|
||||
public override ThingsGatewayBitConverter ThingsGatewayBitConverter { get; } = new(EndianType.Little);
|
||||
[DeviceProperty("重连频率", "")] public int ReconnectPeriod { get; set; } = 5000;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<Version>1.1.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
<Version>1.1.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<LangVersion>latestMajor</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.1.0</Version>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
/// <inheritdoc cref="UserEventSubscriber"/>
|
||||
public UserEventSubscriber(IServiceProvider services)
|
||||
{
|
||||
this._services = services;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
|
||||
/// <inheritdoc cref="IUserCenterService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class UserCenterService : DbRepository<SysUser>, IUserCenterService
|
||||
@@ -11,6 +12,7 @@
|
||||
private readonly ISysUserService _userService;
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
|
||||
/// <inheritdoc cref="IUserCenterService"/>
|
||||
public UserCenterService(ISysUserService userService,
|
||||
IRelationService relationService,
|
||||
IResourceService resourceService,
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ThingsGateway.Application
|
||||
/// </summary>
|
||||
public class UserIdProvider : IUserIdProvider
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string GetUserId(HubConnectionContext connection)
|
||||
{
|
||||
var feature = connection.Features.Get<IHttpContextFeature>();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.1.0</Version>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<TargetFrameworks>net4.6.2;net6.0;net7.0</TargetFrameworks>
|
||||
<NoWarn>SYSLIB0014;CS8981;</NoWarn>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
|
||||
<Version>1.0.5</Version>
|
||||
<Title>ThingsGateway.Foundation</Title>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
@@ -8,28 +8,31 @@ namespace ThingsGateway.Web.Foundation
|
||||
public class ThingsGatewayCacheConst
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备变量名称
|
||||
/// 采集设备
|
||||
/// </summary>
|
||||
public const string Cache_DeviceVariableName = CacheConst.Cache_Prefix_Web + "DeviceVariableName";
|
||||
/// <summary>
|
||||
/// 设备变量Id
|
||||
/// </summary>
|
||||
public const string Cache_DeviceVariableId = CacheConst.Cache_Prefix_Web + "DeviceVariableId";
|
||||
public const string Cache_CollectDevice = CacheConst.Cache_Prefix_Web + "CollectDevice";
|
||||
|
||||
/// <summary>
|
||||
/// 设备变量组
|
||||
/// </summary>
|
||||
public const string Cache_DeviceVariableGroup = CacheConst.Cache_Prefix_Web + "DeviceVariableGroup";
|
||||
|
||||
/// <summary>
|
||||
/// 设备变量Id
|
||||
/// </summary>
|
||||
public const string Cache_DeviceVariableId = CacheConst.Cache_Prefix_Web + "DeviceVariableId";
|
||||
|
||||
|
||||
|
||||
public const string Cache_CollectDevice = CacheConst.Cache_Prefix_Web + "CollectDevice";
|
||||
public const string Cache_UploadDevice = CacheConst.Cache_Prefix_Web + "UploadDevice";
|
||||
|
||||
/// <summary>
|
||||
/// 设备变量名称
|
||||
/// </summary>
|
||||
public const string Cache_DeviceVariableName = CacheConst.Cache_Prefix_Web + "DeviceVariableName";
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
public const string Cache_DriverPlugin = CacheConst.Cache_Prefix_Web + "Cache_DriverPlugin";
|
||||
|
||||
/// <summary>
|
||||
/// 上传设备
|
||||
/// </summary>
|
||||
public const string Cache_UploadDevice = CacheConst.Cache_Prefix_Web + "UploadDevice";
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,47 @@
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 常量
|
||||
/// </summary>
|
||||
public class ThingsGatewayConst
|
||||
{
|
||||
|
||||
|
||||
|
||||
public const string ThingGateway_AlarmConfig_Base = "THINGSGATEWAY_ALARMCONFIG_BASE";
|
||||
public const string ThingGateway_HisConfig_Base = "THINGSGATEWAY_HISCONFIG_BASE";
|
||||
|
||||
|
||||
public const string Config_Alarm_Enable = "CONFIG_ALARM_ENABLE";
|
||||
|
||||
/// <summary>
|
||||
/// 报警链接
|
||||
/// </summary>
|
||||
public const string Config_Alarm_ConnStr = "CONFIG_ALARM_CONNSTR";
|
||||
|
||||
/// <summary>
|
||||
/// 报警数据库
|
||||
/// </summary>
|
||||
public const string Config_Alarm_DbType = "CONFIG_ALARM_DBTYPE";
|
||||
public const string Config_His_Enable = "CONFIG_HIS_ENABLE";
|
||||
public const string Config_His_DbType = "CONFIG_HIS_DBTYPE";
|
||||
|
||||
/// <summary>
|
||||
/// 报警使能
|
||||
/// </summary>
|
||||
public const string Config_Alarm_Enable = "CONFIG_ALARM_ENABLE";
|
||||
|
||||
/// <summary>
|
||||
/// 历史链接
|
||||
/// </summary>
|
||||
public const string Config_His_ConnStr = "CONFIG_HIS_CONNSTR";
|
||||
|
||||
/// <summary>
|
||||
/// 历史数据库
|
||||
/// </summary>
|
||||
public const string Config_His_DbType = "CONFIG_HIS_DBTYPE";
|
||||
|
||||
/// <summary>
|
||||
/// 历史使能
|
||||
/// </summary>
|
||||
public const string Config_His_Enable = "CONFIG_HIS_ENABLE";
|
||||
|
||||
/// <summary>
|
||||
/// 报警配置
|
||||
/// </summary>
|
||||
public const string ThingGateway_AlarmConfig_Base = "THINGSGATEWAY_ALARMCONFIG_BASE";
|
||||
/// <summary>
|
||||
/// 历史配置
|
||||
/// </summary>
|
||||
public const string ThingGateway_HisConfig_Base = "THINGSGATEWAY_HISCONFIG_BASE";
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,14 @@ namespace ThingsGateway.Web.Foundation
|
||||
public class CollectDbInfoControler : IDynamicApiController
|
||||
{
|
||||
IServiceScopeFactory _scopeFactory;
|
||||
IVariableService _variableService { get; set; }
|
||||
/// <inheritdoc cref="CollectDbInfoControler"/>
|
||||
public CollectDbInfoControler(IServiceScopeFactory scopeFactory, IVariableService variableService)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_variableService = variableService;
|
||||
}
|
||||
|
||||
IVariableService _variableService { get; set; }
|
||||
/// <summary>
|
||||
/// 获取变量信息
|
||||
/// </summary>
|
||||
|
||||
@@ -13,7 +13,7 @@ using ThingsGateway.Core.Extension;
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集设备
|
||||
/// 采集状态信息
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayOpenApi, Order = 200)]
|
||||
[Route("openApi/collectInfo")]
|
||||
@@ -24,8 +24,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
public class CollectInfoControler : IDynamicApiController
|
||||
{
|
||||
IServiceScopeFactory _scopeFactory;
|
||||
CollectDeviceHostService _collectDeviceHostService { get; set; }
|
||||
AlarmHostService _alarmHostService { get; set; }
|
||||
/// <inheritdoc cref="CollectInfoControler"/>
|
||||
public CollectInfoControler(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
@@ -34,6 +33,8 @@ namespace ThingsGateway.Web.Foundation
|
||||
_alarmHostService = serviceScope.ServiceProvider.GetBackgroundService<AlarmHostService>();
|
||||
}
|
||||
|
||||
AlarmHostService _alarmHostService { get; set; }
|
||||
CollectDeviceHostService _collectDeviceHostService { get; set; }
|
||||
/// <summary>
|
||||
/// 获取设备信息
|
||||
/// </summary>
|
||||
|
||||
@@ -9,18 +9,18 @@ using ThingsGateway.Foundation;
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备写入
|
||||
/// 变量写入
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(CateGoryConst.ThingsGatewayOpenApi, Order = 200)]
|
||||
[Route("openApi/rpc")]
|
||||
[Description("设备写入")]
|
||||
[Description("变量写入")]
|
||||
[OpenApiPermission]
|
||||
[LoggingMonitor]
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
public class RpcControler : IDynamicApiController
|
||||
{
|
||||
IServiceScopeFactory _scopeFactory;
|
||||
RpcCore _rpcCore { get; set; }
|
||||
/// <inheritdoc cref="RpcControler"/>
|
||||
public RpcControler(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
@@ -28,6 +28,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
_rpcCore = serviceScope.ServiceProvider.GetService<RpcCore>();
|
||||
}
|
||||
|
||||
RpcCore _rpcCore { get; set; }
|
||||
/// <summary>
|
||||
/// 写入设备
|
||||
/// </summary>
|
||||
|
||||
@@ -9,47 +9,64 @@ namespace ThingsGateway.Web.Foundation;
|
||||
[Tenant(SqlsugarConst.DB_CustomId)]
|
||||
public class AlarmHis : PrimaryIdEntity
|
||||
{
|
||||
/// <inheritdoc cref="MemoryVariable.Name"/>
|
||||
[SugarColumn(ColumnName = "Name", ColumnDescription = "变量名称", IsNullable = false)]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <inheritdoc cref="MemoryVariable.Description"/>
|
||||
[SugarColumn(ColumnName = "Description", ColumnDescription = "描述", IsNullable = true)]
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.DeviceName"/>
|
||||
[SugarColumn(ColumnName = "DeviceName", ColumnDescription = "设备名称", IsNullable = true)]
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectDeviceVariable.VariableAddress"/>
|
||||
[SugarColumn(ColumnName = "VariableAddress", ColumnDescription = "变量地址")]
|
||||
public string VariableAddress { get; set; }
|
||||
|
||||
/// <inheritdoc cref="MemoryVariable.DataTypeEnum"/>
|
||||
[SugarColumn(ColumnName = "DataTypeEnum", ColumnDescription = "数据类型", ColumnDataType = "varchar(100)")]
|
||||
public DataTypeEnum DataTypeEnum { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.Quality"/>
|
||||
[SugarColumn(ColumnName = "Quality", ColumnDescription = "质量戳")]
|
||||
public int Quality { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.Value"/>
|
||||
[SugarColumn(ColumnName = "Value", ColumnDescription = "变量值", IsNullable = false)]
|
||||
public string Value { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.AlarmCode"/>
|
||||
[SugarColumn(ColumnName = "AlarmCode", ColumnDescription = "报警值", IsNullable = false)]
|
||||
public string AlarmCode { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.AlarmLimit"/>
|
||||
[SugarColumn(ColumnName = "AlarmLimit", ColumnDescription = "报警限值", IsNullable = false)]
|
||||
public string AlarmLimit { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.AlarmText"/>
|
||||
[SugarColumn(ColumnName = "AlarmText", ColumnDescription = "报警文本", IsNullable = true)]
|
||||
public string AlarmText { get; set; }
|
||||
|
||||
/// <inheritdoc cref="CollectVariableRunTime.AlarmTime"/>
|
||||
[SugarColumn(ColumnName = "AlarmTime", ColumnDescription = "报警时间", IsNullable = false)]
|
||||
public DateTime AlarmTime { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.EventTime"/>
|
||||
[SugarColumn(ColumnName = "EventTime", ColumnDescription = "事件时间", IsNullable = false)]
|
||||
public DateTime EventTime { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 报警类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "AlarmTypeEnum", ColumnDescription = "报警类型", IsNullable = false, ColumnDataType = "varchar(100)")]
|
||||
public AlarmEnum AlarmTypeEnum { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "EventTypeEnum", ColumnDescription = "事件类型", IsNullable = false, ColumnDataType = "varchar(100)")]
|
||||
public EventEnum EventTypeEnum { get; set; }
|
||||
|
||||
@@ -61,12 +78,33 @@ public class AlarmHis : PrimaryIdEntity
|
||||
/// </summary>
|
||||
public enum AlarmEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Bool On
|
||||
/// </summary>
|
||||
Open,
|
||||
/// <summary>
|
||||
/// Bool Off
|
||||
/// </summary>
|
||||
Close,
|
||||
/// <summary>
|
||||
/// HH
|
||||
/// </summary>
|
||||
HH,
|
||||
/// <summary>
|
||||
/// H
|
||||
/// </summary>
|
||||
H,
|
||||
/// <summary>
|
||||
/// L
|
||||
/// </summary>
|
||||
L,
|
||||
/// <summary>
|
||||
/// LL
|
||||
/// </summary>
|
||||
LL,
|
||||
}
|
||||
/// <summary>
|
||||
@@ -74,16 +112,42 @@ public enum AlarmEnum
|
||||
/// </summary>
|
||||
public enum EventEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 报警产生
|
||||
/// </summary>
|
||||
Alarm,
|
||||
/// <summary>
|
||||
/// 报警确认
|
||||
/// </summary>
|
||||
Check,
|
||||
/// <summary>
|
||||
/// 报警恢复
|
||||
/// </summary>
|
||||
Finish,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库类型
|
||||
/// </summary>
|
||||
public enum SqlDbType
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlServer
|
||||
/// </summary>
|
||||
SqlServer,
|
||||
/// <summary>
|
||||
/// Mysql
|
||||
/// </summary>
|
||||
Mysql,
|
||||
/// <summary>
|
||||
/// Sqlite
|
||||
/// </summary>
|
||||
Sqlite,
|
||||
/// <summary>
|
||||
/// PostgreSQL
|
||||
/// </summary>
|
||||
PostgreSQL,
|
||||
/// <summary>
|
||||
/// Oracle
|
||||
/// </summary>
|
||||
Oracle,
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using ThingsGateway.Core;
|
||||
using ThingsGateway.Foundation;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
/// <summary>
|
||||
|
||||
@@ -31,8 +31,18 @@ public class DriverPlugin : BaseEntity
|
||||
public string FilePath { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插件类型
|
||||
/// </summary>
|
||||
public enum DriverEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集
|
||||
/// </summary>
|
||||
Collect,
|
||||
/// <summary>
|
||||
/// 上传
|
||||
/// </summary>
|
||||
Upload,
|
||||
}
|
||||
|
||||
@@ -21,13 +21,6 @@ public class MemoryVariable : BaseEntity
|
||||
[OrderData(Order = 2)]
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始值
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "InitialValue", ColumnDescription = "初始值", IsNullable = true)]
|
||||
[OrderData(Order = 4)]
|
||||
public string InitialValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 读写权限
|
||||
/// </summary>
|
||||
@@ -43,7 +36,7 @@ public class MemoryVariable : BaseEntity
|
||||
public DataTypeEnum DataTypeEnum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量额外属性Json,通常使用为<上传设备,List属性>
|
||||
/// 变量额外属性Json,通常使用为上传设备,List属性
|
||||
/// </summary>
|
||||
[SugarColumn(IsJson = true, ColumnName = "VariablePropertys", ColumnDescription = "变量属性Json", IsNullable = true)]
|
||||
public Dictionary<long, List<DependencyProperty>> VariablePropertys { get; set; } = new();
|
||||
@@ -199,10 +192,18 @@ public class MemoryVariable : BaseEntity
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 历史类型
|
||||
/// </summary>
|
||||
public enum HisType
|
||||
{
|
||||
/// <summary>
|
||||
/// 改变存储
|
||||
/// </summary>
|
||||
Change,
|
||||
/// <summary>
|
||||
/// 采集存储
|
||||
/// </summary>
|
||||
Collect,
|
||||
}
|
||||
|
||||
|
||||
@@ -2,28 +2,33 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 附加属性
|
||||
/// </summary>
|
||||
public class DependencyProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// 属性描述
|
||||
/// </summary>
|
||||
[Description("描述")]
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 属性名称
|
||||
/// </summary>
|
||||
[Description("名称")]
|
||||
public string PropertyName { get; set; }
|
||||
/// <summary>
|
||||
/// 属性描述
|
||||
/// </summary>
|
||||
[Description("描述")]
|
||||
public string Description { get; set; }
|
||||
/// <summary>
|
||||
/// 属性值
|
||||
/// </summary>
|
||||
[Description("属性值")]
|
||||
public string Value { get; set; }
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Description("备注")]
|
||||
[MaxLength(50)]
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 属性值
|
||||
/// </summary>
|
||||
[Description("属性值")]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -12,25 +12,46 @@ namespace ThingsGateway.Web.Foundation;
|
||||
[Tenant(SqlsugarConst.DB_CustomId)]
|
||||
public class ValueHis : PrimaryIdEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 忽略Id,无实际上传字段
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
public override long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传时间
|
||||
/// </summary>
|
||||
[TimeDbSplitField(DateType.Month)]
|
||||
[JsonConverter(typeof(IsoDateTimeConverter))]
|
||||
[Description("上传时间")]
|
||||
public DateTime CollectTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDataType = "symbol")]
|
||||
[Description("变量名称")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 质量戳
|
||||
/// </summary>
|
||||
[Description("质量戳")]
|
||||
public int Quality { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变量值
|
||||
/// </summary>
|
||||
[Description("变量值")]
|
||||
public double Value { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 数据库类型
|
||||
/// </summary>
|
||||
public enum HisDbType
|
||||
{
|
||||
/// <summary>
|
||||
/// 时序库QuestDB
|
||||
/// </summary>
|
||||
QuestDB,
|
||||
}
|
||||
@@ -5,22 +5,36 @@
|
||||
/// </summary>
|
||||
public enum DataTypeEnum
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
Object,
|
||||
|
||||
/// <inheritdoc/>
|
||||
Bcd,
|
||||
/// <inheritdoc/>
|
||||
DateTime,
|
||||
/// <inheritdoc/>
|
||||
String,
|
||||
|
||||
/// <inheritdoc/>
|
||||
Boolean,
|
||||
/// <inheritdoc/>
|
||||
Byte,
|
||||
/// <inheritdoc/>
|
||||
SByte,
|
||||
/// <inheritdoc/>
|
||||
Int16,
|
||||
/// <inheritdoc/>
|
||||
UInt16,
|
||||
/// <inheritdoc/>
|
||||
Int32,
|
||||
/// <inheritdoc/>
|
||||
UInt32,
|
||||
/// <inheritdoc/>
|
||||
Int64,
|
||||
/// <inheritdoc/>
|
||||
UInt64,
|
||||
/// <inheritdoc/>
|
||||
Single,
|
||||
/// <inheritdoc/>
|
||||
Double,
|
||||
}
|
||||
/// <summary>
|
||||
@@ -28,6 +42,11 @@ public enum DataTypeEnum
|
||||
/// </summary>
|
||||
public static class DataTypeExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取DOTNET RUNTIME TYPE
|
||||
/// </summary>
|
||||
/// <param name="coreDataType"></param>
|
||||
/// <returns></returns>
|
||||
public static Type GetNetType(this DataTypeEnum coreDataType)
|
||||
{
|
||||
switch (coreDataType)
|
||||
@@ -67,6 +86,12 @@ public static class DataTypeExtension
|
||||
return typeof(string);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实际字节长度,不足1写1
|
||||
/// </summary>
|
||||
/// <param name="coreDataType"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetByteLength(this DataTypeEnum coreDataType)
|
||||
{
|
||||
switch (coreDataType)
|
||||
@@ -106,5 +131,4 @@ public static class DataTypeExtension
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -5,12 +5,19 @@
|
||||
/// </summary>
|
||||
public enum ProtectTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 只读
|
||||
/// </summary>
|
||||
[Description("只读")]
|
||||
ReadOnly,
|
||||
|
||||
/// <summary>
|
||||
/// 读写
|
||||
/// </summary>
|
||||
[Description("读写")]
|
||||
ReadWrite,
|
||||
|
||||
/// <summary>
|
||||
/// 只写
|
||||
/// </summary>
|
||||
[Description("只写")]
|
||||
WriteOnly,
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@ using System.Linq;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取后台服务扩展类
|
||||
/// </summary>
|
||||
public static class ServiceExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取后台服务
|
||||
/// 获取后台服务,用于非IHostService
|
||||
/// </summary>
|
||||
public static T GetBackgroundService<T>(this IServiceScopeFactory @this) where T : class, IHostedService
|
||||
{
|
||||
@@ -15,7 +18,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
return hostedService;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取后台服务
|
||||
/// 获取后台服务,注意在后台上直接获取可能会出错
|
||||
/// </summary>
|
||||
public static T GetBackgroundService<T>(this object @this) where T : class, IHostedService
|
||||
{
|
||||
|
||||
@@ -22,22 +22,38 @@ namespace ThingsGateway.Web.Foundation;
|
||||
/// </summary>
|
||||
public class AlarmHostService : BackgroundService, ISingleton
|
||||
{
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger<AlarmHostService> _logger;
|
||||
private GlobalCollectDeviceData _globalCollectDeviceData;
|
||||
private ConcurrentQueue<CollectVariableRunTime> CollectDeviceVariables { get; set; } = new();
|
||||
public ConcurrentList<CollectVariableRunTime> RealAlarmDeviceVariables { get; set; } = new();
|
||||
private ConcurrentQueue<CollectVariableRunTime> HisAlarmDeviceVariables { get; set; } = new();
|
||||
|
||||
public event VariableCahngeEventHandler OnAlarmChanged;
|
||||
public event DelegateOnDeviceChanged OnDeviceStatusChanged;
|
||||
public OperResult StatuString { get; set; } = new OperResult("初始化");
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="AlarmHostService"/>
|
||||
public AlarmHostService(ILogger<AlarmHostService> logger, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = logger;
|
||||
_globalCollectDeviceData = scopeFactory.CreateScope().ServiceProvider.GetService<GlobalCollectDeviceData>();
|
||||
}
|
||||
/// <summary>
|
||||
/// 报警变化事件
|
||||
/// </summary>
|
||||
public event VariableCahngeEventHandler OnAlarmChanged;
|
||||
/// <summary>
|
||||
/// 设备状态变化事件
|
||||
/// </summary>
|
||||
public event DelegateOnDeviceChanged OnDeviceStatusChanged;
|
||||
/// <summary>
|
||||
/// 实时报警列表
|
||||
/// </summary>
|
||||
public ConcurrentList<CollectVariableRunTime> RealAlarmDeviceVariables { get; set; } = new();
|
||||
/// <summary>
|
||||
/// 服务状态
|
||||
/// </summary>
|
||||
public OperResult StatuString { get; set; } = new OperResult("初始化");
|
||||
private ConcurrentQueue<CollectVariableRunTime> CollectDeviceVariables { get; set; } = new();
|
||||
private ConcurrentQueue<CollectVariableRunTime> HisAlarmDeviceVariables { get; set; } = new();
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult<SqlSugarClient>> AlarmConfig()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
@@ -90,18 +106,21 @@ public class AlarmHostService : BackgroundService, ISingleton
|
||||
return OperResult.CreateSuccessResult(sqlSugarClient);
|
||||
}
|
||||
#region worker服务
|
||||
/// <inheritdoc/>
|
||||
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger?.LogInformation("报警服务启动");
|
||||
await base.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger?.LogInformation("报警服务停止");
|
||||
return base.StopAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await Task.Delay(5000, stoppingToken);
|
||||
@@ -127,9 +146,9 @@ public class AlarmHostService : BackgroundService, ISingleton
|
||||
/// 循环线程取消标识
|
||||
/// </summary>
|
||||
public ConcurrentList<CancellationTokenSource> StoppingTokens = new();
|
||||
private Task<Task> RealAlarmTask;
|
||||
private ExpressionEvaluator expressionEvaluator;
|
||||
private Task<Task> HisAlarmTask;
|
||||
|
||||
private Task<Task> RealAlarmTask;
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
@@ -275,6 +294,27 @@ public class AlarmHostService : BackgroundService, ISingleton
|
||||
}
|
||||
);
|
||||
}
|
||||
/// <summary>
|
||||
/// 重启服务
|
||||
/// </summary>
|
||||
public void Restart()
|
||||
{
|
||||
Stop(_globalCollectDeviceData.CollectDevices);
|
||||
Start();
|
||||
}
|
||||
|
||||
internal void Start()
|
||||
{
|
||||
foreach (var item in _globalCollectDeviceData.CollectDevices)
|
||||
{
|
||||
DeviceChange(item);
|
||||
}
|
||||
StoppingTokens.Add(new());
|
||||
Init();
|
||||
RealAlarmTask.Start();
|
||||
HisAlarmTask.Start();
|
||||
|
||||
}
|
||||
|
||||
internal void Stop(IEnumerable<CollectDeviceRunTime> devices = null)
|
||||
{
|
||||
@@ -322,45 +362,6 @@ public class AlarmHostService : BackgroundService, ISingleton
|
||||
StoppingTokens.Remove(StoppingToken);
|
||||
|
||||
}
|
||||
internal void Start()
|
||||
{
|
||||
foreach (var item in _globalCollectDeviceData.CollectDevices)
|
||||
{
|
||||
DeviceChange(item);
|
||||
}
|
||||
StoppingTokens.Add(new());
|
||||
Init();
|
||||
RealAlarmTask.Start();
|
||||
HisAlarmTask.Start();
|
||||
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
Stop(_globalCollectDeviceData.CollectDevices);
|
||||
Start();
|
||||
}
|
||||
|
||||
private void DeviceChange(CollectDeviceRunTime device)
|
||||
{
|
||||
device.DeviceStatusCahnge += DeviceStatusCahnge;
|
||||
device.DeviceVariableRunTimes?.ForEach(v => { v.VariableCollectChange += DeviceVariableChange; });
|
||||
}
|
||||
|
||||
private void DeviceStatusCahnge(CollectDeviceRunTime device)
|
||||
{
|
||||
OnDeviceStatusChanged?.Invoke(device.Adapt<CollectDeviceRunTime>());
|
||||
}
|
||||
|
||||
private void DeviceVariableChange(CollectVariableRunTime variable)
|
||||
{
|
||||
//这里不能序列化变量,报警服务需改变同一个变量指向的属性
|
||||
CollectDeviceVariables.Enqueue(variable);
|
||||
}
|
||||
|
||||
|
||||
private ExpressionEvaluator expressionEvaluator;
|
||||
|
||||
private void AlarmAnalysis(CollectVariableRunTime item)
|
||||
{
|
||||
string limit = string.Empty;
|
||||
@@ -466,7 +467,22 @@ public class AlarmHostService : BackgroundService, ISingleton
|
||||
}
|
||||
}
|
||||
|
||||
private void DeviceChange(CollectDeviceRunTime device)
|
||||
{
|
||||
device.DeviceStatusCahnge += DeviceStatusCahnge;
|
||||
device.DeviceVariableRunTimes?.ForEach(v => { v.VariableCollectChange += DeviceVariableChange; });
|
||||
}
|
||||
|
||||
private void DeviceStatusCahnge(CollectDeviceRunTime device)
|
||||
{
|
||||
OnDeviceStatusChanged?.Invoke(device.Adapt<CollectDeviceRunTime>());
|
||||
}
|
||||
|
||||
private void DeviceVariableChange(CollectVariableRunTime variable)
|
||||
{
|
||||
//这里不能序列化变量,报警服务需改变同一个变量指向的属性
|
||||
CollectDeviceVariables.Enqueue(variable);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 设备子线程服务
|
||||
/// </summary>
|
||||
public class CollectDeviceCore : DisposableObject
|
||||
{
|
||||
/// <summary>
|
||||
@@ -24,8 +27,12 @@ public class CollectDeviceCore : DisposableObject
|
||||
/// 循环线程取消标识
|
||||
/// </summary>
|
||||
public ConcurrentList<CancellationTokenSource> StoppingTokens = new();
|
||||
/// <summary>
|
||||
/// 当前的驱动插件实例
|
||||
/// </summary>
|
||||
internal DriverBase _driver;
|
||||
|
||||
protected ILogger _logger;
|
||||
internal bool isInitSuccess;
|
||||
|
||||
/// <summary>
|
||||
/// 当前设备信息
|
||||
@@ -33,10 +40,9 @@ public class CollectDeviceCore : DisposableObject
|
||||
protected CollectDeviceRunTime _device;
|
||||
|
||||
/// <summary>
|
||||
/// 当前的驱动插件实例
|
||||
/// 日志
|
||||
/// </summary>
|
||||
internal DriverBase _driver;
|
||||
|
||||
protected ILogger _logger;
|
||||
/// <summary>
|
||||
/// 全局插件服务
|
||||
/// </summary>
|
||||
@@ -46,8 +52,8 @@ public class CollectDeviceCore : DisposableObject
|
||||
/// 分包变量
|
||||
/// </summary>
|
||||
protected List<DeviceVariableSourceRead> DeviceVariableSourceReads = new();
|
||||
protected IServiceScopeFactory _scopeFactory;
|
||||
|
||||
private IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="CollectDeviceCore"/>
|
||||
public CollectDeviceCore(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
|
||||
@@ -78,9 +84,9 @@ public class CollectDeviceCore : DisposableObject
|
||||
/// 当前设备全部设备属性,执行初始化后获取正确值
|
||||
/// </summary>
|
||||
public List<DependencyProperty> Propertys { get; protected set; }
|
||||
/// <inheritdoc cref="GlobalCollectDeviceData"/>
|
||||
protected GlobalCollectDeviceData _globalCollectDeviceData { get; set; }
|
||||
protected IDriverPluginService _driverPluginService { get; set; }
|
||||
internal bool isInitSuccess;
|
||||
private IDriverPluginService _driverPluginService { get; set; }
|
||||
/// <summary>
|
||||
/// 初始化,在设备子线程创建或更新时才会执行
|
||||
/// </summary>
|
||||
@@ -136,9 +142,77 @@ public class CollectDeviceCore : DisposableObject
|
||||
}
|
||||
|
||||
#region 设备子线程采集启动停止
|
||||
|
||||
/// <summary>
|
||||
/// 线程
|
||||
/// </summary>
|
||||
protected Task<Task> DeviceTask;
|
||||
|
||||
/// <summary>
|
||||
/// 暂停采集
|
||||
/// </summary>
|
||||
public void PasueThread(bool enable)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
var str = enable == false ? "设备线程采集暂停" : "设备线程采集继续";
|
||||
_logger?.LogInformation($"{str}:{_device.Name}");
|
||||
this.Device.Enable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始采集
|
||||
/// </summary>
|
||||
public virtual void StartThread()
|
||||
{
|
||||
DeviceTask?.Start();
|
||||
}
|
||||
/// <summary>
|
||||
/// 停止采集
|
||||
/// </summary>
|
||||
public virtual void StopThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
CancellationTokenSource StoppingToken = StoppingTokens.LastOrDefault();
|
||||
StoppingToken?.Cancel();
|
||||
_logger?.LogInformation($"{_device.Name}采集线程停止中");
|
||||
var devResult = DeviceTask?.Result;
|
||||
if (devResult?.Status != TaskStatus.Canceled)
|
||||
{
|
||||
if (devResult?.Wait(5000) == true)
|
||||
{
|
||||
_logger?.LogInformation($"{_device.Name}采集线程已停止");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.LogInformation($"{_device.Name}采集线程停止超时,已强制取消");
|
||||
}
|
||||
}
|
||||
DeviceTask?.Dispose();
|
||||
if (StoppingToken != null)
|
||||
{
|
||||
StoppingTokens.Remove(StoppingToken);
|
||||
}
|
||||
_globalCollectDeviceData.CollectDevices.RemoveWhere(it => it.Id == Device.Id);
|
||||
|
||||
try
|
||||
{
|
||||
_driver?.AfterStop();
|
||||
_driver?.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{Device.Name} Dispose Error: {ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
_pluginService.DeleteDriver(DeviceId, Device.PluginId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
@@ -298,69 +372,6 @@ public class CollectDeviceCore : DisposableObject
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停采集
|
||||
/// </summary>
|
||||
public void PasueThread(bool enable)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
var str = enable == false ? "设备线程采集暂停" : "设备线程采集继续";
|
||||
_logger?.LogInformation($"{str}:{_device.Name}");
|
||||
this.Device.Enable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始采集
|
||||
/// </summary>
|
||||
public virtual void StartThread()
|
||||
{
|
||||
DeviceTask?.Start();
|
||||
}
|
||||
public virtual void StopThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
CancellationTokenSource StoppingToken = StoppingTokens.LastOrDefault();
|
||||
StoppingToken?.Cancel();
|
||||
_logger?.LogInformation($"{_device.Name}采集线程停止中");
|
||||
var devResult = DeviceTask?.Result;
|
||||
if (devResult?.Status != TaskStatus.Canceled)
|
||||
{
|
||||
if (devResult?.Wait(5000) == true)
|
||||
{
|
||||
_logger?.LogInformation($"{_device.Name}采集线程已停止");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.LogInformation($"{_device.Name}采集线程停止超时,已强制取消");
|
||||
}
|
||||
}
|
||||
DeviceTask?.Dispose();
|
||||
if (StoppingToken != null)
|
||||
{
|
||||
StoppingTokens.Remove(StoppingToken);
|
||||
}
|
||||
_globalCollectDeviceData.CollectDevices.RemoveWhere(it => it.Id == Device.Id);
|
||||
|
||||
try
|
||||
{
|
||||
_driver?.AfterStop();
|
||||
_driver?.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"{Device.Name} Dispose Error: {ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
_pluginService.DeleteDriver(DeviceId, Device.PluginId);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 驱动信息获取
|
||||
@@ -475,6 +486,13 @@ public class CollectDeviceCore : DisposableObject
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行方法
|
||||
/// </summary>
|
||||
/// <param name="coreMethod"></param>
|
||||
/// <param name="par"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult> InvokeMed(Method coreMethod, params object[] par)
|
||||
{
|
||||
return (OperResult)await coreMethod.InvokeObjectAsync(_driver, par);
|
||||
@@ -531,6 +549,8 @@ public class CollectDeviceCore : DisposableObject
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
@@ -16,12 +16,11 @@ namespace ThingsGateway.Web.Foundation;
|
||||
/// </summary>
|
||||
public class CollectDeviceHostService : BackgroundService
|
||||
{
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
private readonly ILogger<CollectDeviceHostService> _logger;
|
||||
private GlobalCollectDeviceData _globalCollectDeviceData;
|
||||
private PluginCore _pluginService;
|
||||
public ConcurrentList<CollectDeviceCore> CollectDeviceCores { get; private set; } = new();
|
||||
ICollectDeviceService _collectDeviceService { get; set; }
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc/>
|
||||
public CollectDeviceHostService(ILogger<CollectDeviceHostService> logger,
|
||||
IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
@@ -34,42 +33,27 @@ public class CollectDeviceHostService : BackgroundService
|
||||
serviceScope.ServiceProvider.GetService<HardwareInfoService>();
|
||||
_collectDeviceService = serviceScope.ServiceProvider.GetService<ICollectDeviceService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备子线程列表
|
||||
/// </summary>
|
||||
public ConcurrentList<CollectDeviceCore> CollectDeviceCores { get; private set; } = new();
|
||||
ICollectDeviceService _collectDeviceService { get; set; }
|
||||
#region 设备创建更新结束
|
||||
|
||||
/// <summary>
|
||||
/// 更新设备线程
|
||||
/// 控制设备线程启停
|
||||
/// </summary>
|
||||
public async Task UpDeviceThread(long devId, bool isUpdateDb = true)
|
||||
public void ConfigDeviceThread(long deviceId, bool isStart)
|
||||
{
|
||||
if (!_stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
StopOtherHostService(CollectDeviceCores.Select(a => a.Device).ToList());
|
||||
|
||||
var devcore = CollectDeviceCores.FirstOrDefault(it => it?.DeviceId == devId);
|
||||
if (devcore == null) { throw Oops.Bah($"更新设备线程失败,不存在{devId}为id的设备"); }
|
||||
//这里先停止采集,操作会使线程取消,需要重新恢复线程
|
||||
devcore.StopThread();
|
||||
|
||||
CollectDeviceRunTime dev = null;
|
||||
if (isUpdateDb)
|
||||
dev = (await _collectDeviceService.GetCollectDeviceRuntime(devId)).FirstOrDefault();
|
||||
else
|
||||
dev = devcore.Device;
|
||||
if (dev == null) { _logger.LogError($"更新设备线程失败,不存在{devId}为id的设备"); }
|
||||
devcore.Init(dev);
|
||||
devcore.StartThread();
|
||||
|
||||
StartOtherHostService();
|
||||
|
||||
|
||||
}
|
||||
if (deviceId == 0)
|
||||
CollectDeviceCores.ForEach(it => it.PasueThread(isStart));
|
||||
else
|
||||
CollectDeviceCores.FirstOrDefault(it => it.DeviceId == deviceId)?.PasueThread(isStart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除设备线程,并且释放资源
|
||||
/// </summary>
|
||||
/// <param name="devices"></param>
|
||||
public void RemoveDeviceThread(long devId)
|
||||
{
|
||||
var deviceThread = CollectDeviceCores.FirstOrDefault(x => x.DeviceId == devId);
|
||||
@@ -80,7 +64,9 @@ public class CollectDeviceHostService : BackgroundService
|
||||
CollectDeviceCores.Remove(deviceThread);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重启采集服务
|
||||
/// </summary>
|
||||
public async Task RestartDeviceThread()
|
||||
{
|
||||
try
|
||||
@@ -131,7 +117,23 @@ public class CollectDeviceHostService : BackgroundService
|
||||
_logger.LogError(ex, nameof(RestartDeviceThread));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 启动其他后台服务
|
||||
/// </summary>
|
||||
public void StartOtherHostService()
|
||||
{
|
||||
|
||||
|
||||
var alarmHostService = _scopeFactory.GetBackgroundService<AlarmHostService>();
|
||||
var valueHisHostService = _scopeFactory.GetBackgroundService<ValueHisHostService>();
|
||||
alarmHostService?.Start();
|
||||
valueHisHostService?.Start();
|
||||
var uploadDeviceHostService = _scopeFactory.GetBackgroundService<UploadDeviceHostService>();
|
||||
uploadDeviceHostService.StartDeviceThread();
|
||||
}
|
||||
/// <summary>
|
||||
/// 停止其他后台服务
|
||||
/// </summary>
|
||||
public void StopOtherHostService(List<CollectDeviceRunTime> oldDeviceRuntime)
|
||||
{
|
||||
if (oldDeviceRuntime?.Count > 0)
|
||||
@@ -150,35 +152,42 @@ public class CollectDeviceHostService : BackgroundService
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void StartOtherHostService()
|
||||
{
|
||||
|
||||
|
||||
var alarmHostService = _scopeFactory.GetBackgroundService<AlarmHostService>();
|
||||
var valueHisHostService = _scopeFactory.GetBackgroundService<ValueHisHostService>();
|
||||
alarmHostService?.Start();
|
||||
valueHisHostService?.Start();
|
||||
var uploadDeviceHostService = _scopeFactory.GetBackgroundService<UploadDeviceHostService>();
|
||||
uploadDeviceHostService.StartDeviceThread();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 控制设备线程启停
|
||||
/// 更新设备线程
|
||||
/// </summary>
|
||||
public void ConfigDeviceThread(long deviceId, bool isStart)
|
||||
public async Task UpDeviceThread(long devId, bool isUpdateDb = true)
|
||||
{
|
||||
if (deviceId == 0)
|
||||
CollectDeviceCores.ForEach(it => it.PasueThread(isStart));
|
||||
else
|
||||
CollectDeviceCores.FirstOrDefault(it => it.DeviceId == deviceId)?.PasueThread(isStart);
|
||||
}
|
||||
if (!_stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
StopOtherHostService(CollectDeviceCores.Select(a => a.Device).ToList());
|
||||
|
||||
var devcore = CollectDeviceCores.FirstOrDefault(it => it?.DeviceId == devId);
|
||||
if (devcore == null) { throw Oops.Bah($"更新设备线程失败,不存在{devId}为id的设备"); }
|
||||
//这里先停止采集,操作会使线程取消,需要重新恢复线程
|
||||
devcore.StopThread();
|
||||
|
||||
CollectDeviceRunTime dev = null;
|
||||
if (isUpdateDb)
|
||||
dev = (await _collectDeviceService.GetCollectDeviceRuntime(devId)).FirstOrDefault();
|
||||
else
|
||||
dev = devcore.Device;
|
||||
if (dev == null) { _logger.LogError($"更新设备线程失败,不存在{devId}为id的设备"); }
|
||||
devcore.Init(dev);
|
||||
devcore.StartThread();
|
||||
|
||||
StartOtherHostService();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设备信息获取
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备方法
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetDeviceMethods(long devId)
|
||||
{
|
||||
var id = YitIdHelper.NextId();
|
||||
@@ -199,21 +208,12 @@ public class CollectDeviceHostService : BackgroundService
|
||||
|
||||
}
|
||||
|
||||
public DriverBase GetImportUI(long devId)
|
||||
{
|
||||
var result = CollectDeviceCores.FirstOrDefault(a => a.DeviceId == devId);
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return result._driver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备属性
|
||||
/// </summary>
|
||||
/// <param name="driverId"></param>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
public List<DependencyProperty> GetDevicePropertys(long driverId, long devId = 0)
|
||||
{
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
@@ -243,14 +243,37 @@ public class CollectDeviceHostService : BackgroundService
|
||||
_pluginService.DeleteDriver(id, driverId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取导入变量UI
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
public DriverBase GetImportUI(long devId)
|
||||
{
|
||||
var result = CollectDeviceCores.FirstOrDefault(a => a.DeviceId == devId);
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return result._driver;
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region worker服务
|
||||
private CancellationToken _stoppingToken;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await base.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var stoppingToken = new CancellationTokenSource();
|
||||
@@ -273,12 +296,7 @@ public class CollectDeviceHostService : BackgroundService
|
||||
await Task.Delay(2000);
|
||||
await base.StopAsync(cancellationToken);
|
||||
}
|
||||
private CancellationToken _stoppingToken;
|
||||
|
||||
/// <summary>
|
||||
/// 变量触发变化
|
||||
/// </summary>
|
||||
public delegate void VariableCahngeListEventHandler(List<CollectVariableRunTime> collectVariableRunTimes);
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await RestartDeviceThread();
|
||||
@@ -292,15 +310,15 @@ public class CollectDeviceHostService : BackgroundService
|
||||
CollectDeviceCore devcore = CollectDeviceCores[i];
|
||||
if (
|
||||
(devcore.Device.ActiveTime != DateTime.MinValue && devcore.Device.ActiveTime.AddMinutes(3) <= DateTime.Now)
|
||||
|| devcore.isInitSuccess==false
|
||||
|| devcore.isInitSuccess == false
|
||||
)
|
||||
{
|
||||
if (devcore.StoppingTokens.Last().Token.IsCancellationRequested)
|
||||
continue;
|
||||
if (devcore.Device.DeviceStatus == DeviceStatusEnum.Pause)
|
||||
continue;
|
||||
if(devcore.isInitSuccess)
|
||||
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
|
||||
if (!devcore.isInitSuccess)
|
||||
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
|
||||
else
|
||||
_logger?.LogWarning(devcore.Device.Name + "采集线程假死,重启线程中");
|
||||
await UpDeviceThread(devcore.DeviceId, false);
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// <br></br>
|
||||
/// 未完成
|
||||
/// </summary>
|
||||
public class CollectMulDeviceCore : CollectDeviceCore
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public CollectMulDeviceCore(IServiceScopeFactory scopeFactory) : base(scopeFactory)
|
||||
{
|
||||
|
||||
@@ -10,10 +14,12 @@ public class CollectMulDeviceCore : CollectDeviceCore
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void StartThread()
|
||||
{
|
||||
DeviceTask?.Start();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void StopThread()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -8,9 +8,15 @@
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||
public class DeviceMethodAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; }
|
||||
|
||||
/// <inheritdoc cref="DeviceMethodAttribute"/>
|
||||
public DeviceMethodAttribute(string name, string description = "")
|
||||
{
|
||||
Name = name;
|
||||
|
||||
@@ -8,10 +8,15 @@
|
||||
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
||||
public class DevicePropertyAttribute : Attribute
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Remark { get; }
|
||||
|
||||
/// <inheritdoc cref="DevicePropertyAttribute"/>
|
||||
public DevicePropertyAttribute(string name, string remark = null)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
@@ -3,15 +3,20 @@
|
||||
/// <summary>
|
||||
/// 变量属性的特性说明
|
||||
/// <br></br>
|
||||
/// 继承<see cref="DriverBase"/>的上传插件,在需主动暴露的变量配置属性中加上这个特性<see cref="VariablePropertyAttribute"/>
|
||||
/// 继承<see cref="UpLoadBase"/>的上传插件,在需主动暴露的变量配置属性中加上这个特性<see cref="VariablePropertyAttribute"/>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
||||
public class VariablePropertyAttribute : Attribute
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 变量属性名称
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
/// <summary>
|
||||
/// 附加说明
|
||||
/// </summary>
|
||||
public string Remark { get; }
|
||||
|
||||
/// <inheritdoc cref="VariablePropertyAttribute"/>>
|
||||
public VariablePropertyAttribute(string name, string remark = null)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace ThingsGateway.Web.Foundation;
|
||||
/// </summary>
|
||||
public class GlobalCollectDeviceData : ISingleton
|
||||
{
|
||||
/// <inheritdoc cref="GlobalCollectDeviceData"/>
|
||||
public GlobalCollectDeviceData()
|
||||
{
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 报警扩展
|
||||
/// </summary>
|
||||
public static class AlarmHostServiceHelpers
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取bool报警类型
|
||||
/// </summary>
|
||||
|
||||
@@ -6,32 +6,21 @@ using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 表达式扩展
|
||||
/// </summary>
|
||||
public static class ExpressionEvaluatorExtension
|
||||
{
|
||||
static ExpressionEvaluator ExpressionEvaluator;
|
||||
|
||||
static ExpressionEvaluatorExtension()
|
||||
{
|
||||
ExpressionEvaluator = new();
|
||||
ExpressionEvaluator.PreEvaluateVariable += Evaluator_PreEvaluateVariable;
|
||||
}
|
||||
public static void Evaluator_PreEvaluateVariable(object sender, VariablePreEvaluationEventArg e)
|
||||
{
|
||||
var data = App.GetService<GlobalCollectDeviceData>();
|
||||
var obj = data.CollectVariables.FirstOrDefault(it => it.Name == e.Name);
|
||||
if (obj == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (obj.Value != null)
|
||||
e.Value = Convert.ChangeType(obj.Value, obj.DataType);
|
||||
}
|
||||
|
||||
public static ExpressionEvaluator ExpressionEvaluator;
|
||||
|
||||
/// <summary>
|
||||
/// 计算表达式:raw*100
|
||||
/// 计算表达式
|
||||
/// </summary>
|
||||
/// <param name="expressions"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetExpressionsResult(this string expressions, object rawvalue)
|
||||
{
|
||||
if (expressions.IsNullOrEmpty())
|
||||
@@ -46,7 +35,21 @@ namespace ThingsGateway.Web.Foundation
|
||||
var value = ExpressionEvaluator.Evaluate(expressions);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式的扩展变量来源
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public static void Evaluator_PreEvaluateVariable(object sender, VariablePreEvaluationEventArg e)
|
||||
{
|
||||
var data = App.GetService<GlobalCollectDeviceData>();
|
||||
var obj = data.CollectVariables.FirstOrDefault(it => it.Name == e.Name);
|
||||
if (obj == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (obj.Value != null)
|
||||
e.Value = Convert.ChangeType(obj.Value, obj.DataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,29 @@ using System.Reflection;
|
||||
using ThingsGateway.Foundation;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 读写扩展
|
||||
/// </summary>
|
||||
public static class ReadWriteHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据<see cref="OperResult.IsSuccess"/>执行action
|
||||
/// </summary>
|
||||
public static OperResult<T> DealWithReadResult<T>(OperResult<T> read, Action<T> action)
|
||||
{
|
||||
if (!read.IsSuccess || action == null)
|
||||
return read;
|
||||
action(read.Content);
|
||||
return read;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据<see cref="PropertyInfo"/> 数据类型转化返回值类型
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static object ObjToTypeValue(PropertyInfo p, string value)
|
||||
{
|
||||
object _value = null;
|
||||
@@ -45,18 +65,6 @@ public static class ReadWriteHelpers
|
||||
return _value;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据<see cref="OperResult.IsSuccess"/>执行action
|
||||
/// </summary>
|
||||
public static OperResult<T> DealWithReadResult<T>(OperResult<T> read, Action<T> action)
|
||||
{
|
||||
if (!read.IsSuccess || action == null)
|
||||
return read;
|
||||
action(read.Content);
|
||||
return read;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在返回的字节数组中解析每个变量的值
|
||||
/// 根据每个变量的<see cref="CollectVariableRunTime.Index"/>
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 计时器
|
||||
/// </summary>
|
||||
public class TimerTick
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 误差
|
||||
/// </summary>
|
||||
private int offsetTime = 60;
|
||||
/// <summary>
|
||||
/// 时间差
|
||||
/// </summary>
|
||||
private int milliSeconds = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 误差
|
||||
/// </summary>
|
||||
private int offsetTime = 60;
|
||||
/// <inheritdoc cref="TimerTick"/>
|
||||
public TimerTick(int milliSeconds = 1000)
|
||||
{
|
||||
if (milliSeconds < 20)
|
||||
@@ -39,6 +43,10 @@ public class TimerTick
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否到达设置时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsTickHappen() => IsTickHappen(DateTime.Now);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -27,6 +27,16 @@ public class DeviceVariableMedRead
|
||||
/// 字符串转换器,默认支持基础类型和Json。可以自定义。
|
||||
/// </summary>
|
||||
public TouchSocket.Core.StringConverter Converter { get; }
|
||||
/// <summary>
|
||||
/// 需分配的变量
|
||||
/// </summary>
|
||||
public CollectVariableRunTime DeviceVariable { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
public Method MedInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法参数
|
||||
/// </summary>
|
||||
@@ -36,14 +46,6 @@ public class DeviceVariableMedRead
|
||||
/// </summary>
|
||||
public string MedStr { get; set; }
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
public Method MedInfo { get; set; }
|
||||
/// <summary>
|
||||
/// 需分配的变量
|
||||
/// </summary>
|
||||
public CollectVariableRunTime DeviceVariable { get; set; } = new();
|
||||
/// <summary>
|
||||
/// 检测是否达到读取间隔
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
|
||||
@@ -22,13 +22,14 @@ public class DeviceVariableSourceRead
|
||||
/// </summary>
|
||||
public string Address { get; set; }
|
||||
/// <summary>
|
||||
/// 读取长度
|
||||
/// </summary>
|
||||
public string Length { get; set; }
|
||||
/// <summary>
|
||||
/// 需分配的变量列表
|
||||
/// </summary>
|
||||
public List<CollectVariableRunTime> DeviceVariables { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 读取长度
|
||||
/// </summary>
|
||||
public string Length { get; set; }
|
||||
/// <summary>
|
||||
/// 检测是否达到读取间隔
|
||||
/// </summary>
|
||||
|
||||
@@ -15,19 +15,27 @@ namespace ThingsGateway.Web.Foundation;
|
||||
/// </summary>
|
||||
public abstract class DriverBase : IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="TouchSocketConfig"/>
|
||||
/// </summary>
|
||||
public TouchSocketConfig TouchSocketConfig;
|
||||
/// <summary>
|
||||
/// 日志
|
||||
/// </summary>
|
||||
protected ILogger _logger;
|
||||
private bool isLogOut;
|
||||
private ILogger privateLogger;
|
||||
private IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="DriverBase"/>
|
||||
public DriverBase(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
TouchSocketConfig = new TouchSocketConfig();
|
||||
TouchSocketConfig.ConfigureContainer(a => a.RegisterSingleton<ILog>(new EasyLogger(Log_Out)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否输出日志
|
||||
/// </summary>
|
||||
public bool IsLogOut
|
||||
{
|
||||
get => isLogOut;
|
||||
@@ -87,9 +95,11 @@ public abstract class DriverBase : IDisposable
|
||||
/// <returns></returns>
|
||||
public abstract Task BeforStart();
|
||||
|
||||
|
||||
public virtual Type DriverUI { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 导入变量UI
|
||||
/// </summary>
|
||||
public virtual Type DriverImportUI { get; }
|
||||
/// <inheritdoc/>
|
||||
public abstract void Dispose();
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
@@ -125,8 +135,6 @@ public abstract class DriverBase : IDisposable
|
||||
/// <summary>
|
||||
/// 采集驱动读取
|
||||
/// </summary>
|
||||
/// <param name="deviceVariableSourceRead"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<OperResult<byte[]>> ReadSourceAsync(DeviceVariableSourceRead deviceVariableSourceRead, CancellationToken cancellationToken)
|
||||
{
|
||||
ushort length;
|
||||
@@ -152,9 +160,6 @@ public abstract class DriverBase : IDisposable
|
||||
/// <br></br>
|
||||
/// 通常使用<see cref="IReadWrite.ReadAsync(string, int, System.Threading.CancellationToken)"/>可以直接返回正确信息
|
||||
/// </summary>
|
||||
/// <param name="address">变量地址</param>
|
||||
/// <param name="length">读取长度</param>
|
||||
/// <returns></returns>
|
||||
protected abstract Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken);
|
||||
|
||||
private void Log_Out(LogType arg1, object arg2, string arg3, Exception arg4)
|
||||
|
||||
@@ -2,10 +2,20 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 导入变量UI
|
||||
/// </summary>
|
||||
public abstract class DriverUI : ComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备通讯类
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public virtual object Driver { get; set; }
|
||||
/// <summary>
|
||||
/// 获取导入变量列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract List<CollectDeviceVariable> GetVariableList();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,15 +16,28 @@ namespace ThingsGateway.Web.Foundation;
|
||||
/// </summary>
|
||||
public abstract class UpLoadBase : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="TouchSocketConfig"/>
|
||||
/// </summary>
|
||||
public TouchSocketConfig TouchSocketConfig=new();
|
||||
/// <summary>
|
||||
/// 日志
|
||||
/// </summary>
|
||||
protected ILogger _logger;
|
||||
private bool isLogOut;
|
||||
private ILogger privateLogger;
|
||||
/// <summary>
|
||||
/// 服务工厂
|
||||
/// </summary>
|
||||
protected IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="UpLoadBase"/>
|
||||
public UpLoadBase(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否输出日志
|
||||
/// </summary>
|
||||
public bool IsLogOut
|
||||
{
|
||||
get => isLogOut;
|
||||
@@ -52,6 +65,7 @@ public abstract class UpLoadBase : IDisposable
|
||||
/// 返回是否已经在线/成功启动
|
||||
/// </summary>
|
||||
public abstract OperResult Success();
|
||||
/// <inheritdoc/>
|
||||
public abstract void Dispose();
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
@@ -72,9 +86,15 @@ public abstract class UpLoadBase : IDisposable
|
||||
/// <summary>
|
||||
/// 循环执行
|
||||
/// </summary>
|
||||
/// <param name="deviceVariableSourceRead"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Task ExecuteAsync(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="TouchSocket"/> 日志输出
|
||||
/// </summary>
|
||||
/// <param name="arg1"></param>
|
||||
/// <param name="arg2"></param>
|
||||
/// <param name="arg3"></param>
|
||||
/// <param name="arg4"></param>
|
||||
protected void Log_Out(LogType arg1, object arg2, string arg3, Exception arg4)
|
||||
{
|
||||
switch (arg1)
|
||||
|
||||
@@ -4,14 +4,29 @@
|
||||
/// </summary>
|
||||
public enum DeviceStatusEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 在线
|
||||
/// </summary>
|
||||
[Description("在线")]
|
||||
OnLine = 1,
|
||||
/// <summary>
|
||||
/// 离线
|
||||
/// </summary>
|
||||
[Description("离线")]
|
||||
OffLine = 2,
|
||||
/// <summary>
|
||||
/// 暂停
|
||||
/// </summary>
|
||||
[Description("暂停")]
|
||||
Pause = 3,
|
||||
/// <summary>
|
||||
/// 部分失败
|
||||
/// </summary>
|
||||
[Description("部分失败")]
|
||||
OnLineButNoInitialValue = 4,
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
[Description("初始化")]
|
||||
Default = 5,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 变量名称/值表示
|
||||
/// </summary>
|
||||
public class NameVaue
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -20,6 +20,7 @@ public class PluginCore : ISingleton
|
||||
{
|
||||
private readonly ILogger<PluginCore> _logger;
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="PluginCore"/>
|
||||
public PluginCore(ILogger<PluginCore> logger, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
@@ -42,7 +43,12 @@ public class PluginCore : ISingleton
|
||||
/// 插件ID/设备ID集合
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<long, List<long>> DeviceOnDriverPlugins { get; private set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取插件
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
public object AddDriver(long devId, DriverPlugin plugin)
|
||||
{
|
||||
//先判断是否已经拥有插件模块
|
||||
@@ -134,7 +140,11 @@ public class PluginCore : ISingleton
|
||||
return assembly;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试添加插件,返回插件表示类
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<DriverPlugin>> TestAddDriver(DriverPluginAddInput plugin)
|
||||
{
|
||||
var devId = YitIdHelper.NextId();
|
||||
@@ -222,7 +232,11 @@ public class PluginCore : ISingleton
|
||||
assemblyLoadContext.Unload();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除插件
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <param name="pluginId"></param>
|
||||
public void DeleteDriver(long devId, long pluginId)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -10,7 +10,7 @@ using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
/// <summary>
|
||||
/// 驱动插件服务
|
||||
/// 变量写入值服务
|
||||
/// </summary>
|
||||
public class RpcCore : ISingleton
|
||||
{
|
||||
@@ -22,6 +22,7 @@ public class RpcCore : ISingleton
|
||||
private CollectDeviceHostService _collectDeviceHostService;
|
||||
|
||||
private IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="RpcCore"/>
|
||||
public RpcCore(ILogger<RpcCore> logger, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
@@ -46,10 +47,6 @@ public class RpcCore : ISingleton
|
||||
/// <summary>
|
||||
/// 反向RPC入口方法
|
||||
/// </summary>
|
||||
/// <param name="MethodBase"></param>
|
||||
/// <param name="par"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<OperResult> InvokeDeviceMethod(string sourceName, NameVaue item, bool isBlazorWeb = false)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,9 @@ using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 设备子线程服务
|
||||
/// </summary>
|
||||
public class UploadDeviceCore : DisposableObject
|
||||
{
|
||||
|
||||
@@ -27,11 +30,7 @@ public class UploadDeviceCore : DisposableObject
|
||||
/// <summary>
|
||||
/// 当前的驱动插件实例
|
||||
/// </summary>
|
||||
private UpLoadBase _driver
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
private UpLoadBase _driver { get; set; }
|
||||
|
||||
private ILogger _logger;
|
||||
/// <summary>
|
||||
@@ -42,6 +41,7 @@ public class UploadDeviceCore : DisposableObject
|
||||
|
||||
private IServiceScopeFactory _scopeFactory;
|
||||
|
||||
/// <inheritdoc cref="UploadDeviceCore"/>
|
||||
public UploadDeviceCore(IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
|
||||
@@ -86,11 +86,11 @@ public class UploadDeviceCore : DisposableObject
|
||||
SetPluginProperties(_device.DevicePropertys);
|
||||
_driver.IsLogOut = _device.IsLogOut;
|
||||
_driver.Init(_logger, _device);
|
||||
isInitSuccess=true;
|
||||
isInitSuccess = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
isInitSuccess=false;
|
||||
isInitSuccess = false;
|
||||
_logger.LogError(ex, $"{_device.Name}Init失败");
|
||||
}
|
||||
StoppingTokens.Add(new());
|
||||
@@ -227,6 +227,9 @@ public class UploadDeviceCore : DisposableObject
|
||||
{
|
||||
DeviceTask?.Start();
|
||||
}
|
||||
/// <summary>
|
||||
/// 停止上传
|
||||
/// </summary>
|
||||
public void StopThread()
|
||||
{
|
||||
try
|
||||
@@ -288,7 +291,7 @@ public class UploadDeviceCore : DisposableObject
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
@@ -16,9 +16,7 @@ namespace ThingsGateway.Web.Foundation;
|
||||
/// </summary>
|
||||
public class UploadDeviceHostService : BackgroundService
|
||||
{
|
||||
private readonly ILogger<UploadDeviceHostService> _logger;
|
||||
private PluginCore _pluginService;
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="UploadDeviceHostService"/>
|
||||
public UploadDeviceHostService(ILogger<UploadDeviceHostService> logger,
|
||||
IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
@@ -30,8 +28,15 @@ public class UploadDeviceHostService : BackgroundService
|
||||
_uploadDeviceService = serviceScope.ServiceProvider.GetService<IUploadDeviceService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全部设备子线程
|
||||
/// </summary>
|
||||
public ConcurrentList<UploadDeviceCore> UploadDeviceCores { get; private set; } = new();
|
||||
IUploadDeviceService _uploadDeviceService { get; set; }
|
||||
|
||||
private ILogger<UploadDeviceHostService> _logger { get; set; }
|
||||
private PluginCore _pluginService { get; set; }
|
||||
private IServiceScopeFactory _scopeFactory { get; set; }
|
||||
private IUploadDeviceService _uploadDeviceService { get; set; }
|
||||
#region 设备创建更新结束
|
||||
|
||||
/// <summary>
|
||||
@@ -48,7 +53,6 @@ public class UploadDeviceHostService : BackgroundService
|
||||
/// <summary>
|
||||
/// 删除设备线程,并且释放资源
|
||||
/// </summary>
|
||||
/// <param name="devices"></param>
|
||||
public void RemoveDeviceThread()
|
||||
{
|
||||
var dev = UploadDeviceCores;
|
||||
@@ -67,23 +71,9 @@ public class UploadDeviceHostService : BackgroundService
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 启动设备线程
|
||||
/// 重启全部设备
|
||||
/// </summary>
|
||||
/// <param name="devices"></param>
|
||||
public void StartDeviceThread()
|
||||
{
|
||||
var devs = (_uploadDeviceService.GetUploadDeviceRuntime());
|
||||
foreach (var item in devs)
|
||||
{
|
||||
if (!_stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
UploadDeviceCore deviceCollectCore = new(_scopeFactory);
|
||||
deviceCollectCore.Init(item);
|
||||
deviceCollectCore.StartThread();
|
||||
UploadDeviceCores.Add(deviceCollectCore);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <returns></returns>
|
||||
public async Task RestartDeviceThread()
|
||||
{
|
||||
try
|
||||
@@ -103,6 +93,23 @@ public class UploadDeviceHostService : BackgroundService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动设备线程
|
||||
/// </summary>
|
||||
public void StartDeviceThread()
|
||||
{
|
||||
var devs = (_uploadDeviceService.GetUploadDeviceRuntime());
|
||||
foreach (var item in devs)
|
||||
{
|
||||
if (!_stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
UploadDeviceCore deviceCollectCore = new(_scopeFactory);
|
||||
deviceCollectCore.Init(item);
|
||||
deviceCollectCore.StartThread();
|
||||
UploadDeviceCores.Add(deviceCollectCore);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 更新设备线程
|
||||
/// </summary>
|
||||
@@ -129,7 +136,11 @@ public class UploadDeviceHostService : BackgroundService
|
||||
#endregion
|
||||
|
||||
#region 设备信息获取
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备方法
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
public List<string> GetDeviceMethods(long devId)
|
||||
{
|
||||
var id = YitIdHelper.NextId();
|
||||
@@ -151,7 +162,12 @@ public class UploadDeviceHostService : BackgroundService
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备属性
|
||||
/// </summary>
|
||||
/// <param name="driverId"></param>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
public List<DependencyProperty> GetDevicePropertys(long driverId, long devId = 0)
|
||||
{
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
@@ -182,7 +198,12 @@ public class UploadDeviceHostService : BackgroundService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取变量上传属性
|
||||
/// </summary>
|
||||
/// <param name="driverId"></param>
|
||||
/// <param name="dependencyProperties"></param>
|
||||
/// <returns></returns>
|
||||
public List<DependencyProperty> GetVariablePropertys(long driverId, List<DependencyProperty> dependencyProperties = null)
|
||||
{
|
||||
using var serviceScope = _scopeFactory.CreateScope();
|
||||
@@ -216,12 +237,13 @@ public class UploadDeviceHostService : BackgroundService
|
||||
|
||||
#region worker服务
|
||||
private CancellationToken _stoppingToken;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await base.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var stoppingToken = new CancellationTokenSource();
|
||||
@@ -231,6 +253,7 @@ public class UploadDeviceHostService : BackgroundService
|
||||
RemoveDeviceThread();
|
||||
await base.StopAsync(cancellationToken);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
|
||||
@@ -251,10 +274,10 @@ public class UploadDeviceHostService : BackgroundService
|
||||
continue;
|
||||
if (devcore.Device.DeviceStatus == DeviceStatusEnum.Pause)
|
||||
continue;
|
||||
if (devcore.isInitSuccess)
|
||||
if (!devcore.isInitSuccess)
|
||||
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
|
||||
else
|
||||
_logger?.LogWarning(devcore.Device.Name + "上传线程假死,重启线程中");
|
||||
_logger?.LogWarning(devcore.Device.Name + "上传线程假死,重启线程中");
|
||||
UpDeviceThread(devcore.DeviceId, false);
|
||||
i--;
|
||||
num--;
|
||||
|
||||
@@ -24,17 +24,25 @@ public class ValueHisHostService : BackgroundService, ISingleton
|
||||
private GlobalCollectDeviceData _globalCollectDeviceData;
|
||||
private ConcurrentQueue<ValueHis> CollectDeviceVariables { get; set; } = new();
|
||||
private ConcurrentQueue<ValueHis> ChangeDeviceVariables { get; set; } = new();
|
||||
/// <summary>
|
||||
/// 服务状态
|
||||
/// </summary>
|
||||
public OperResult StatuString { get; set; } = new OperResult("初始化");
|
||||
|
||||
|
||||
|
||||
private static IServiceScopeFactory _scopeFactory;
|
||||
/// <inheritdoc cref="ValueHisHostService"/>
|
||||
public ValueHisHostService(ILogger<ValueHisHostService> logger, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
_scopeFactory = scopeFactory;
|
||||
_logger = logger;
|
||||
_globalCollectDeviceData = scopeFactory.CreateScope().ServiceProvider.GetService<GlobalCollectDeviceData>();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<OperResult<SqlSugarClient>> HisConfig()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
@@ -82,18 +90,20 @@ public class ValueHisHostService : BackgroundService, ISingleton
|
||||
return OperResult.CreateSuccessResult(sqlSugarClient);
|
||||
}
|
||||
#region worker服务
|
||||
/// <inheritdoc/>
|
||||
public override async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger?.LogInformation("历史服务启动");
|
||||
await base.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger?.LogInformation("历史服务停止");
|
||||
return base.StopAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
await Task.Delay(5000, stoppingToken);
|
||||
@@ -276,6 +286,9 @@ public class ValueHisHostService : BackgroundService, ISingleton
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新启动服务
|
||||
/// </summary>
|
||||
public void Restart()
|
||||
{
|
||||
Stop(_globalCollectDeviceData.CollectDevices);
|
||||
@@ -305,8 +318,13 @@ public class ValueHisHostService : BackgroundService, ISingleton
|
||||
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// <see cref="ValueHis"/> Master规则
|
||||
/// </summary>
|
||||
public class ValueHisMapper : IRegister
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.ForType<CollectVariableRunTime, ValueHis>()
|
||||
|
||||
@@ -15,11 +15,12 @@ public class TGLogJob : IJob
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
/// <inheritdoc cref="TGLogJob"/>
|
||||
public TGLogJob(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
|
||||
{
|
||||
var db = DbContext.Db.CopyNew();
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
private readonly SqlSugarScope _db;
|
||||
|
||||
/// <inheritdoc cref="TGRunTimeDatabaseLoggingWriter"/>
|
||||
public TGRunTimeDatabaseLoggingWriter()
|
||||
{
|
||||
_db = DbContext.Db;
|
||||
@@ -31,6 +32,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
await Task.Delay(3000);
|
||||
}
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void Write(LogMessage logMsg, bool flush)
|
||||
{
|
||||
var customLevel = App.GetConfig<LogLevel?>("Logging:LogLevel:RunTimeLogCustom") ?? LogLevel.Trace;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 采集设备状态表示
|
||||
/// </summary>
|
||||
public class CollectDeviceRunTime : CollectDevice
|
||||
{
|
||||
/// <summary>
|
||||
@@ -60,9 +63,15 @@ public class CollectDeviceRunTime : CollectDevice
|
||||
}
|
||||
}
|
||||
private DeviceStatusEnum deviceStatus = DeviceStatusEnum.Default;
|
||||
/// <summary>
|
||||
/// 设备状态变化事件
|
||||
/// </summary>
|
||||
public event DelegateOnDeviceChanged DeviceStatusCahnge;
|
||||
|
||||
private string deviceOffMsg;
|
||||
/// <summary>
|
||||
/// 失败原因
|
||||
/// </summary>
|
||||
[Description("失败原因")]
|
||||
public string DeviceOffMsg
|
||||
{
|
||||
@@ -79,5 +88,9 @@ public class CollectDeviceRunTime : CollectDevice
|
||||
set => deviceOffMsg = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 设备变化委托
|
||||
/// </summary>
|
||||
/// <param name="collectDeviceRunTime"></param>
|
||||
public delegate void DelegateOnDeviceChanged(CollectDeviceRunTime collectDeviceRunTime);
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 变量运行状态表示
|
||||
/// </summary>
|
||||
public class CollectVariableRunTime : CollectDeviceVariable
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,6 +18,9 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
[Description("设备名称")]
|
||||
[OrderData(Order = 2)]
|
||||
public string DeviceName { get; set; }
|
||||
/// <summary>
|
||||
/// 数据类型
|
||||
/// </summary>
|
||||
[Description("数据类型")]
|
||||
public Type DataType
|
||||
{
|
||||
@@ -31,19 +37,32 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 原始值
|
||||
/// </summary>
|
||||
[Description("原始值")]
|
||||
[OrderData(Order = 3)]
|
||||
public object RawValue { get; set; }
|
||||
private object _value;
|
||||
/// <summary>
|
||||
/// 实时值
|
||||
/// </summary>
|
||||
[Description("实时值")]
|
||||
[OrderData(Order = 3)]
|
||||
public object Value { get => _value; private set => _value = value; }
|
||||
/// <summary>
|
||||
/// 上次值
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[AdaptIgnore]
|
||||
public object LastSetValue;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="dateTime"></param>
|
||||
public void SetValue(object value,DateTime dateTime=default)
|
||||
{
|
||||
if (value != null)
|
||||
@@ -89,24 +108,29 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
time = dateTime;
|
||||
}
|
||||
CollectTime = DateTime.Now;
|
||||
if (data?.ToString() != _value?.ToString() && LastSetValue != data)
|
||||
if (data?.ToString() != _value?.ToString() && LastSetValue?.ToString() != data?.ToString())
|
||||
{
|
||||
ChangeTime = DateTime.Now;
|
||||
if (Quality == 192)
|
||||
{
|
||||
_value = data;
|
||||
}
|
||||
LastSetValue = data;
|
||||
VariableValueChange?.Invoke(this);
|
||||
}
|
||||
|
||||
VariableCollectChange?.Invoke(this);
|
||||
LastSetValue = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 变化时间
|
||||
/// </summary>
|
||||
[Description("变化时间")]
|
||||
[OrderData(Order = 4)]
|
||||
public DateTime ChangeTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 采集时间
|
||||
/// </summary>
|
||||
[Description("采集时间")]
|
||||
[OrderData(Order = 4)]
|
||||
public DateTime CollectTime { get; set; }
|
||||
@@ -127,7 +151,9 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[AdaptIgnore]
|
||||
public VariableCahngeEventHandler VariableValueChange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 质量戳
|
||||
/// </summary>
|
||||
[Description("质量戳")]
|
||||
[OrderData(Order = 5)]
|
||||
public int Quality { get; private set; }
|
||||
@@ -135,7 +161,7 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
|
||||
#region LoadSourceRead
|
||||
/// <summary>
|
||||
/// <see cref="DriverBase.ReadAsync(string, ushort)"/>返回字节组中的索引位置
|
||||
/// <see cref="DriverBase.ReadAsync(string, int, System.Threading.CancellationToken)"/>返回字节组中的索引位置
|
||||
/// 这个参数值由自动分包方法写入<see cref="DriverBase.LoadSourceRead(List{CollectVariableRunTime})"/>
|
||||
/// </summary>
|
||||
[Description("分包索引")]
|
||||
@@ -170,7 +196,9 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
|
||||
|
||||
#region 报警
|
||||
|
||||
/// <summary>
|
||||
/// 报警使能
|
||||
/// </summary>
|
||||
public bool AlarmEnable
|
||||
{
|
||||
get
|
||||
@@ -178,19 +206,33 @@ public class CollectVariableRunTime : CollectDeviceVariable
|
||||
return LAlarmEnable || LLAlarmEnable || HAlarmEnable || HHAlarmEnable || BoolOpenAlarmEnable || BoolCloseAlarmEnable;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报警时间
|
||||
/// </summary>
|
||||
public DateTime AlarmTime { get; set; }
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
public DateTime EventTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警类型
|
||||
/// </summary>
|
||||
public AlarmEnum AlarmTypeEnum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
/// </summary>
|
||||
public EventEnum EventTypeEnum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警值
|
||||
/// </summary>
|
||||
public string AlarmCode { get; set; }
|
||||
|
||||
[SugarColumn(ColumnName = "AlamLimit", ColumnDescription = "报警限值", IsNullable = false)]
|
||||
/// <summary>
|
||||
/// 报警限值
|
||||
/// </summary>
|
||||
public string AlarmLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 报警文本
|
||||
/// </summary>
|
||||
public string AlarmText { get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
public class DeviceData
|
||||
|
||||
using ThingsGateway.Web.Foundation;
|
||||
/// <summary>
|
||||
/// 设备上传DTO
|
||||
/// </summary>
|
||||
public class DeviceData
|
||||
{
|
||||
/// <inheritdoc cref="CollectDeviceRunTime.PluginName"/>
|
||||
public string pluginName { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceRunTime.DeviceVariablesNum"/>
|
||||
public int deviceVariablesNum { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceRunTime.ActiveTime"/>
|
||||
public DateTime activeTime { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceRunTime.DeviceStatus"/>
|
||||
public int deviceStatus { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceRunTime.DeviceOffMsg"/>
|
||||
public string deviceOffMsg { get; set; }
|
||||
/// <inheritdoc cref="UploadDevice.Name"/>
|
||||
public string name { get; set; }
|
||||
/// <inheritdoc cref="UploadDevice.Description"/>
|
||||
public string description { get; set; }
|
||||
/// <inheritdoc cref="UploadDevice.Enable"/>
|
||||
public bool enable { get; set; }
|
||||
public DateTime createTime { get; set; }
|
||||
public DateTime updateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation;
|
||||
|
||||
/// <summary>
|
||||
/// 上传设备运行状态
|
||||
/// </summary>
|
||||
public class UploadDeviceRunTime : UploadDevice
|
||||
{
|
||||
/// <summary>
|
||||
@@ -36,6 +39,10 @@ public class UploadDeviceRunTime : UploadDevice
|
||||
private DeviceStatusEnum deviceStatus = DeviceStatusEnum.Default;
|
||||
|
||||
private string deviceOffMsg;
|
||||
|
||||
/// <summary>
|
||||
/// 失败原因
|
||||
/// </summary>
|
||||
[Description("失败原因")]
|
||||
public string DeviceOffMsg
|
||||
{
|
||||
|
||||
@@ -1,21 +1,40 @@
|
||||
|
||||
using ThingsGateway.Web.Foundation;
|
||||
/// <summary>
|
||||
/// 上传DTO
|
||||
/// </summary>
|
||||
public class VariableData
|
||||
{
|
||||
/// <inheritdoc cref="MemoryVariable.Name"/>
|
||||
public string name { get; set; }
|
||||
public string deviceName { get; set; }
|
||||
public string rawValue { get; set; }
|
||||
public string value { get; set; }
|
||||
public DateTime changeTime { get; set; }
|
||||
public DateTime collectTime { get; set; }
|
||||
public int quality { get; set; }
|
||||
public string readExpressions { get; set; }
|
||||
public string writeExpressions { get; set; }
|
||||
public int intervalTime { get; set; }
|
||||
public object otherMethod { get; set; }
|
||||
public string variableAddress { get; set; }
|
||||
/// <inheritdoc cref="MemoryVariable.Description"/>
|
||||
public object description { get; set; }
|
||||
public object initialValue { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.DeviceName"/>
|
||||
public string deviceName { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.RawValue"/>
|
||||
public string rawValue { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.Value"/>
|
||||
public string value { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.ChangeTime"/>
|
||||
public DateTime changeTime { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.CollectTime"/>
|
||||
public DateTime collectTime { get; set; }
|
||||
/// <inheritdoc cref="CollectVariableRunTime.Quality"/>
|
||||
public int quality { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceVariable.ReadExpressions"/>
|
||||
public string readExpressions { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceVariable.WriteExpressions"/>
|
||||
public string writeExpressions { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceVariable.IntervalTime"/>
|
||||
public int intervalTime { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceVariable.OtherMethod"/>
|
||||
public object otherMethod { get; set; }
|
||||
/// <inheritdoc cref="CollectDeviceVariable.VariableAddress"/>
|
||||
public string variableAddress { get; set; }
|
||||
|
||||
/// <inheritdoc cref="MemoryVariable.ProtectTypeEnum"/>
|
||||
public int protectTypeEnum { get; set; }
|
||||
/// <inheritdoc cref="MemoryVariable.DataTypeEnum"/>
|
||||
public int dataTypeEnum { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
/// </summary>
|
||||
public class DevConfigSeedData : ISqlSugarEntitySeedData<DriverPlugin>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<DriverPlugin> SeedData()
|
||||
{
|
||||
return SeedDataUtil.GetSeedData<DriverPlugin>("driver_plugin.json");
|
||||
|
||||
@@ -15,6 +15,7 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc cref="ICollectDeviceService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceService
|
||||
{
|
||||
@@ -23,6 +24,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
|
||||
/// <inheritdoc cref="ICollectDeviceService"/>
|
||||
public CollectDeviceService(SysCacheService sysCacheService
|
||||
, IDriverPluginService driverPluginService, IFileService fileService,
|
||||
IServiceScopeFactory scopeFactory)
|
||||
@@ -115,6 +117,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
var data = GetCacheList();
|
||||
return data.FirstOrDefault(it => it.Id == id)?.Name;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public List<DeviceTree> GetTree()
|
||||
{
|
||||
var data = GetCacheList();
|
||||
@@ -122,6 +125,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
return trees;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GetTree()"/>
|
||||
public static List<DeviceTree> GetTree(List<CollectDevice> data)
|
||||
{
|
||||
Dictionary<string, DeviceTree> trees = new();
|
||||
@@ -208,6 +212,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
var data = GetCacheList();
|
||||
return data.FirstOrDefault(it => it.Id == Id);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public List<CollectDevice> GetCacheList()
|
||||
{
|
||||
//先从Cache拿
|
||||
@@ -265,6 +270,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
}
|
||||
|
||||
#region 导入导出
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出采集设备模板", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> Template()
|
||||
{
|
||||
@@ -275,6 +281,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出采集设备表", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> ExportFile()
|
||||
{
|
||||
|
||||
@@ -10,36 +10,52 @@ using ThingsGateway.Web.Foundation;
|
||||
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集设备添加DTO
|
||||
/// </summary>
|
||||
public class CollectDeviceAddInput : CollectDeviceEditInput
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public override string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[MinValue(1, ErrorMessage = "插件不能为空")]
|
||||
public override long PluginId { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 采集设备编辑DTO
|
||||
/// </summary>
|
||||
public class CollectDeviceEditInput : CollectDevice
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public override string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[MinValue(1, ErrorMessage = "插件不能为空")]
|
||||
public override long PluginId { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 采集设备分页查询DTO
|
||||
/// </summary>
|
||||
public class CollectDevicePageInput : BasePageInput
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[Description("设备名称")]
|
||||
public string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[Description("插件名称")]
|
||||
public string PluginName { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[Description("设备组")]
|
||||
public string DeviceGroup { get; set; }
|
||||
}
|
||||
|
||||
|
||||
#region 导入导出
|
||||
/// <inheritdoc/>
|
||||
public class CollectDeviceImport : UploadDeviceImport
|
||||
{
|
||||
|
||||
@@ -47,7 +63,7 @@ namespace ThingsGateway.Application
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集设备
|
||||
/// 采集设备导出DTO
|
||||
/// </summary>
|
||||
[ExcelExporter(Name = "采集设备", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
|
||||
public class CollectDeviceExport : UploadDeviceExport
|
||||
@@ -57,9 +73,14 @@ namespace ThingsGateway.Application
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集设备导入DTO
|
||||
/// </summary>
|
||||
public class DevicePropertyImport : ImportPreviewInput
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 设备ID,已忽略
|
||||
/// </summary>
|
||||
[ImporterHeader(IsIgnore = true)]
|
||||
public virtual long DeviceId { get; set; }
|
||||
|
||||
@@ -93,6 +114,9 @@ namespace ThingsGateway.Application
|
||||
[ExcelExporter(Name = "设备附加属性", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
|
||||
public class DevicePropertyExport
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备ID,已忽略
|
||||
/// </summary>
|
||||
[ExporterHeader(IsIgnore = true)]
|
||||
public virtual long DeviceId { get; set; }
|
||||
/// <summary>
|
||||
@@ -119,12 +143,19 @@ namespace ThingsGateway.Application
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集设备Excel导入表示类
|
||||
/// </summary>
|
||||
public class CollectDeviceWithPropertyImport
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集设备基本属性
|
||||
/// </summary>
|
||||
[ExcelImporter(SheetName = "采集设备")]
|
||||
public CollectDeviceImport CollectDeviceExport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 采集设备附加属性
|
||||
/// </summary>
|
||||
[ExcelImporter(SheetName = "设备附加属性")]
|
||||
public DevicePropertyImport DevicePropertyExcel { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,29 +6,117 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集设备服务
|
||||
/// </summary>
|
||||
public interface ICollectDeviceService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Add(CollectDevice input);
|
||||
/// <summary>
|
||||
/// 复制设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task CopyDev(IEnumerable<CollectDevice> input);
|
||||
/// <summary>
|
||||
/// 复制设备与变量
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task CopyDevAndVar(IEnumerable<CollectDevice> input);
|
||||
/// <summary>
|
||||
/// 上传设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Delete(List<BaseIdInput> input);
|
||||
/// <summary>
|
||||
/// 编辑设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Edit(CollectDeviceEditInput input);
|
||||
/// <summary>
|
||||
/// 导出Excel
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> ExportFile();
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<CollectDevice> GetCacheList();
|
||||
/// <summary>
|
||||
/// 获取设备运行状态DTO
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<CollectDeviceRunTime>> GetCollectDeviceRuntime(long devId = 0);
|
||||
/// <summary>
|
||||
/// 根据ID获取设备
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
CollectDevice GetDeviceById(long Id);
|
||||
/// <summary>
|
||||
/// 根据名称获取ID
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
long? GetIdByName(string name);
|
||||
/// <summary>
|
||||
/// 根据ID获取名称
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
string GetNameById(long id);
|
||||
/// <summary>
|
||||
/// 获取设备组/名称树
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<DeviceTree> GetTree();
|
||||
/// <summary>
|
||||
/// 导入
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Import(Dictionary<string, ImportPreviewOutputBase> input);
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<SqlSugarPagedList<CollectDevice>> Page(CollectDevicePageInput input);
|
||||
/// <summary>
|
||||
/// 导入验证
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> Preview(IBrowserFile file);
|
||||
/// <summary>
|
||||
/// 导出模板
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> Template();
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 设备组/名称树
|
||||
/// </summary>
|
||||
public class DeviceTree
|
||||
{
|
||||
/// <summary>
|
||||
/// 节点名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// 子节点
|
||||
/// </summary>
|
||||
public List<DeviceTree> Childrens { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class CPU
|
||||
{
|
||||
/// <summary>
|
||||
@@ -98,6 +99,7 @@
|
||||
[Description("CPU总占用率")]
|
||||
public UInt64 PercentProcessorTime { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<CpuCore> CpuCoreList { get; set; } = new List<CpuCore>();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class CpuCore
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
[Description("名称")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<Partition> PartitionList { get; set; } = new List<Partition>();
|
||||
/// <summary>
|
||||
/// 这个物理磁盘驱动器上的分区数量所识别出的操作系统。
|
||||
@@ -133,7 +134,7 @@
|
||||
/// </summary>
|
||||
[Description("分区起始偏移量")]
|
||||
public UInt64 StartingOffset { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<Volume> VolumeList { get; set; } = new List<Volume>();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class MemoryStatus
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -11,36 +11,74 @@ using UAParser;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class TGHardwareInfo
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public MemoryStatus MemoryStatus { get; private set; } = new MemoryStatus();
|
||||
/// <inheritdoc/>
|
||||
public List<CPU> CpuList { get; private set; } = new List<CPU>();
|
||||
/// <inheritdoc/>
|
||||
public List<Drive> DriveList { get; private set; } = new List<Drive>();
|
||||
/// <inheritdoc/>
|
||||
public List<Volume> VolumeList => DriveList.SelectMany(a => a.PartitionList.SelectMany(b => b.VolumeList)).ToList();
|
||||
/// <inheritdoc/>
|
||||
public List<Memory> MemoryList { get; private set; } = new List<Memory>();
|
||||
/// <inheritdoc/>
|
||||
public List<NetworkAdapter> NetworkAdapterList { get; private set; } = new List<NetworkAdapter>();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public class TGAPPInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 主机名称
|
||||
/// </summary>
|
||||
[Description("主机名称")]
|
||||
public string HostName { get; set; }
|
||||
/// <summary>
|
||||
/// 操作系统
|
||||
/// </summary>
|
||||
[Description("操作系统")]
|
||||
public string SystemOs { get; set; }
|
||||
/// <summary>
|
||||
/// 系统架构
|
||||
/// </summary>
|
||||
[Description("系统架构")]
|
||||
public string OsArchitecture { get; set; }
|
||||
/// <summary>
|
||||
/// 外网地址
|
||||
/// </summary>
|
||||
[Description("外网地址")]
|
||||
public string RemoteIp { get; set; }
|
||||
/// <summary>
|
||||
/// 本地地址
|
||||
/// </summary>
|
||||
[Description("本地地址")]
|
||||
public string LocalIp { get; set; }
|
||||
/// <summary>
|
||||
/// NET框架
|
||||
/// </summary>
|
||||
[Description("NET框架")]
|
||||
public string FrameworkDescription { get; set; }
|
||||
/// <summary>
|
||||
/// 主机环境
|
||||
/// </summary>
|
||||
[Description("主机环境")]
|
||||
public string Environment { get; set; }
|
||||
/// <summary>
|
||||
/// Stage环境
|
||||
/// </summary>
|
||||
[Description("Stage环境")]
|
||||
public string Stage { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 硬件信息获取
|
||||
/// </summary>
|
||||
public class HardwareInfoService : ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 硬件信息获取
|
||||
/// </summary>
|
||||
public TGHardwareInfo HardwareInfo
|
||||
{
|
||||
get
|
||||
@@ -49,6 +87,9 @@ namespace ThingsGateway.Web.Foundation
|
||||
return data;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 运行信息获取
|
||||
/// </summary>
|
||||
public TGAPPInfo APPInfo
|
||||
{
|
||||
get
|
||||
@@ -68,6 +109,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
}
|
||||
private readonly Hardware.Info.HardwareInfo hardwareInfo = new();
|
||||
ILogger _logger;
|
||||
/// <inheritdoc cref="HardwareInfoService"/>
|
||||
public HardwareInfoService()
|
||||
{
|
||||
Scoped.Create((factory, scope) =>
|
||||
|
||||
@@ -7,11 +7,13 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc cref="IDriverPluginService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public partial class DriverPluginService : DbRepository<DriverPlugin>, IDriverPluginService
|
||||
{
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
|
||||
/// <inheritdoc cref="IDriverPluginService"/>
|
||||
public DriverPluginService(SysCacheService sysCacheService)
|
||||
{
|
||||
_sysCacheService = sysCacheService;
|
||||
@@ -99,6 +101,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
});
|
||||
return driverPluginCategories.ToList();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public List<DriverPlugin> GetCacheListAsync()
|
||||
{
|
||||
//先从Cache拿
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件分组
|
||||
/// </summary>
|
||||
public class DriverPluginCategory
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件ID
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
/// <summary>
|
||||
/// 插件名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// 插件子组
|
||||
/// </summary>
|
||||
public List<DriverPluginCategory> Children { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -7,23 +7,33 @@ using ThingsGateway.Web.Foundation;
|
||||
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件添加DTO
|
||||
/// </summary>
|
||||
public class DriverPluginAddInput
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 主程序集
|
||||
/// </summary>
|
||||
[Description("主程序集")]
|
||||
[Required(ErrorMessage = "主程序集不能为空")]
|
||||
public IBrowserFile MainFile { get; set; }
|
||||
/// <summary>
|
||||
/// 附属程序集
|
||||
/// </summary>
|
||||
[Description("附属程序集")]
|
||||
public List<IBrowserFile> OtherFiles { get; set; } = new();
|
||||
|
||||
}
|
||||
public class DriverPluginEditInput
|
||||
{
|
||||
public DriverEnum DriverTypeEnum { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 插件分页
|
||||
/// </summary>
|
||||
public class DriverPluginPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件名称
|
||||
/// </summary>
|
||||
[Description("插件名称")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,14 +2,51 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件服务
|
||||
/// </summary>
|
||||
public interface IDriverPluginService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加/更新插件
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Add(DriverPluginAddInput input);
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<DriverPlugin> GetCacheListAsync();
|
||||
/// <summary>
|
||||
/// 根据ID获取插件信息
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
DriverPlugin GetDriverPluginById(long Id);
|
||||
/// <summary>
|
||||
/// 根据分类获取插件树
|
||||
/// </summary>
|
||||
/// <param name="driverTypeEnum"></param>
|
||||
/// <returns></returns>
|
||||
List<DriverPluginCategory> GetDriverPluginChildrenList(DriverEnum driverTypeEnum);
|
||||
/// <summary>
|
||||
/// 根据ID获取名称
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
long? GetIdByName(string name);
|
||||
/// <summary>
|
||||
/// 根据名称获取ID
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
string GetNameById(long id);
|
||||
/// <summary>
|
||||
/// 分页
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<SqlSugarPagedList<DriverPlugin>> Page(DriverPluginPageInput input);
|
||||
}
|
||||
}
|
||||
@@ -10,36 +10,55 @@ using ThingsGateway.Web.Foundation;
|
||||
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传设备添加DTO
|
||||
/// </summary>
|
||||
public class UploadDeviceAddInput : UploadDeviceEditInput
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public override string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[MinValue(1, ErrorMessage = "插件不能为空")]
|
||||
public override long PluginId { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 上传设备修改DTO
|
||||
/// </summary>
|
||||
public class UploadDeviceEditInput : UploadDevice
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public override string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[MinValue(1, ErrorMessage = "插件不能为空")]
|
||||
public override long PluginId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传设备分页查询
|
||||
/// </summary>
|
||||
public class UploadDevicePageInput : BasePageInput
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[Description("设备名称")]
|
||||
public string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[Description("插件名称")]
|
||||
public string PluginName { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[Description("设备组")]
|
||||
public string DeviceGroup { get; set; }
|
||||
}
|
||||
|
||||
|
||||
#region 导入导出
|
||||
/// <summary>
|
||||
/// 上传设备导入DTO
|
||||
/// </summary>
|
||||
public class UploadDeviceImport : ImportPreviewInput
|
||||
{
|
||||
|
||||
@@ -86,7 +105,7 @@ namespace ThingsGateway.Application
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传设备
|
||||
/// 上传设备导出DTO
|
||||
/// </summary>
|
||||
[ExcelExporter(Name = "上传设备", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
|
||||
public class UploadDeviceExport
|
||||
@@ -131,12 +150,19 @@ namespace ThingsGateway.Application
|
||||
public virtual bool IsLogOut { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传设备导入表示类
|
||||
/// </summary>
|
||||
public class UploadDeviceWithPropertyImport
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传设备基本属性
|
||||
/// </summary>
|
||||
[ExcelImporter(SheetName = "上传设备")]
|
||||
public UploadDeviceImport UploadDeviceExport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传设备附加属性
|
||||
/// </summary>
|
||||
[ExcelImporter(SheetName = "设备附加属性")]
|
||||
public DevicePropertyImport DevicePropertyExcel { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,21 +6,91 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传设备服务
|
||||
/// </summary>
|
||||
public interface IUploadDeviceService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加上传设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Add(UploadDevice input);
|
||||
/// <summary>
|
||||
/// 复制设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task CopyDev(IEnumerable<UploadDevice> input);
|
||||
/// <summary>
|
||||
/// 删除设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Delete(List<BaseIdInput> input);
|
||||
/// <summary>
|
||||
/// 编辑设备
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Edit(UploadDeviceEditInput input);
|
||||
/// <summary>
|
||||
/// 导出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> ExportFile();
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<UploadDevice> GetCacheList();
|
||||
/// <summary>
|
||||
/// 根据ID获取设备
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
UploadDevice GetDeviceById(long Id);
|
||||
/// <summary>
|
||||
/// 根据名称获取ID
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
long? GetIdByName(string name);
|
||||
/// <summary>
|
||||
/// 根据ID获取名称
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
string GetNameById(long id);
|
||||
/// <summary>
|
||||
/// 获取上传设备运行状态DTO
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
List<UploadDeviceRunTime> GetUploadDeviceRuntime(long devId = 0);
|
||||
/// <summary>
|
||||
/// 导入
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Import(Dictionary<string, ImportPreviewOutputBase> input);
|
||||
/// <summary>
|
||||
/// 分页
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<SqlSugarPagedList<UploadDevice>> Page(UploadDevicePageInput input);
|
||||
/// <summary>
|
||||
/// 导入验证
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> Preview(IBrowserFile file);
|
||||
/// <summary>
|
||||
/// 导出模板
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> Template();
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc cref="IUploadDeviceService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceService
|
||||
{
|
||||
@@ -21,6 +22,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IServiceScopeFactory _scopeFactory;
|
||||
|
||||
/// <inheritdoc cref="IUploadDeviceService"/>
|
||||
public UploadDeviceService(SysCacheService sysCacheService
|
||||
, IDriverPluginService driverPluginService, IFileService fileService,
|
||||
IServiceScopeFactory scopeFactory)
|
||||
@@ -129,6 +131,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
var data = GetCacheList();
|
||||
return data.FirstOrDefault(it => it.Id == Id);
|
||||
}
|
||||
/// <inheritdoc cref="IUploadDeviceService"/>
|
||||
public List<UploadDevice> GetCacheList()
|
||||
{
|
||||
//先从Cache拿
|
||||
@@ -182,6 +185,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
}
|
||||
|
||||
#region 导入导出
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出上传设备模板", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> Template()
|
||||
{
|
||||
@@ -192,6 +196,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出上传设备表", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> ExportFile()
|
||||
{
|
||||
|
||||
@@ -6,34 +6,41 @@ using OfficeOpenXml.Table;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using ThingsGateway.Core;
|
||||
using ThingsGateway.Foundation;
|
||||
using ThingsGateway.Web.Foundation;
|
||||
|
||||
namespace ThingsGateway.Application
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加变量DTO
|
||||
/// </summary>
|
||||
public class VariableAddInput : VariableEditInput
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[MinValue(100, ErrorMessage = "低于最小值")]
|
||||
public override int IntervalTime { get; set; } = 1000;
|
||||
public override long DeviceId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override long DeviceId { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 修改变量DTO
|
||||
/// </summary>
|
||||
public class VariableEditInput : CollectDeviceVariable, IValidatableObject
|
||||
{
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Required(ErrorMessage = "不能为空")]
|
||||
public override string Name { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[MinValue(1, ErrorMessage = "不能为空")]
|
||||
public override long DeviceId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public override long DeviceId { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[MinValue(100, ErrorMessage = "低于最小值")]
|
||||
public override int IntervalTime { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(VariableAddress) && string.IsNullOrEmpty(OtherMethod))
|
||||
@@ -46,10 +53,13 @@ namespace ThingsGateway.Application
|
||||
/// </summary>
|
||||
public class VariablePageInput : BasePageInput
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[Description("变量名称")]
|
||||
public string Name { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[Description("设备名称")]
|
||||
public string DeviceName { get; set; }
|
||||
/// <inheritdoc/>
|
||||
[Description("变量地址")]
|
||||
public string VariableAddress { get; set; }
|
||||
|
||||
@@ -59,8 +69,12 @@ namespace ThingsGateway.Application
|
||||
|
||||
|
||||
#region 导入导出
|
||||
/// <summary>
|
||||
/// 变量导入DTO
|
||||
/// </summary>
|
||||
public class CollectDeviceVariableImport : ImportPreviewInput, IValidatableObject
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(VariableAddress) && string.IsNullOrEmpty(OtherMethod))
|
||||
@@ -123,12 +137,6 @@ namespace ThingsGateway.Application
|
||||
public string Description { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始值
|
||||
/// </summary>
|
||||
[ImporterHeader(Name = "初始值")]
|
||||
public string InitialValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 读写权限
|
||||
/// </summary>
|
||||
@@ -326,7 +334,9 @@ namespace ThingsGateway.Application
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 变量导出DTO
|
||||
/// </summary>
|
||||
[ExcelExporter(Name = "变量", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
|
||||
public class CollectDeviceVariableExport
|
||||
{
|
||||
@@ -363,12 +373,6 @@ namespace ThingsGateway.Application
|
||||
[ExporterHeader(DisplayName = "变量地址")]
|
||||
public string VariableAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始值
|
||||
/// </summary>
|
||||
[ExporterHeader(DisplayName = "初始值")]
|
||||
public string InitialValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 读写权限
|
||||
/// </summary>
|
||||
@@ -585,16 +589,29 @@ namespace ThingsGateway.Application
|
||||
public bool HisEnable { get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 变量上传属性导入DTO
|
||||
/// </summary>
|
||||
public class VariablePropertyImport : ImportPreviewInput
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 设备ID
|
||||
/// </summary>
|
||||
[ImporterHeader(IsIgnore = true)]
|
||||
public virtual long DeviceId { get; set; }
|
||||
/// <summary>
|
||||
/// 变量ID
|
||||
/// </summary>
|
||||
[ImporterHeader(IsIgnore = true)]
|
||||
public long VariableId { get; set; }
|
||||
/// <summary>
|
||||
/// 变量名称
|
||||
/// </summary>
|
||||
[ImporterHeader(Name = "变量名称")]
|
||||
public string VariableName { get; set; }
|
||||
/// <summary>
|
||||
/// 设备名称
|
||||
/// </summary>
|
||||
[ImporterHeader(Name = "上传设备名称")]
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
@@ -617,13 +634,19 @@ namespace ThingsGateway.Application
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 变量上传属性
|
||||
/// 变量上传属性导出DTO
|
||||
/// </summary>
|
||||
[ExcelExporter(Name = "变量上传属性", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
|
||||
public class VariablePropertyExport
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备ID
|
||||
/// </summary>
|
||||
[ExporterHeader(IsIgnore = true)]
|
||||
public virtual long DeviceId { get; set; }
|
||||
/// <summary>
|
||||
/// 变量ID
|
||||
/// </summary>
|
||||
[ExporterHeader(IsIgnore = true)]
|
||||
public long VariableId { get; set; }
|
||||
/// <summary>
|
||||
@@ -655,11 +678,19 @@ namespace ThingsGateway.Application
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 变量Excel导入表示类
|
||||
/// </summary>
|
||||
public class CollectDeviceVariableWithPropertyImport
|
||||
{
|
||||
/// <summary>
|
||||
/// 变量基本属性
|
||||
/// </summary>
|
||||
[ExcelImporter(SheetName = "变量")]
|
||||
public CollectDeviceVariableImport CollectDeviceVariableExport { get; set; }
|
||||
/// <summary>
|
||||
/// 变量上传属性
|
||||
/// </summary>
|
||||
[ExcelImporter(SheetName = "变量上传属性")]
|
||||
public VariablePropertyImport DevicePropertyExcel { get; set; }
|
||||
|
||||
|
||||
@@ -6,23 +6,98 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 变量数据服务
|
||||
/// </summary>
|
||||
public interface IVariableService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库DB
|
||||
/// </summary>
|
||||
ISqlSugarClient Context { get; set; }
|
||||
/// <summary>
|
||||
/// 添加变量
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Add(CollectDeviceVariable input);
|
||||
/// <summary>
|
||||
/// 清空变量
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task Clear();
|
||||
/// <summary>
|
||||
/// 删除变量
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Delete(List<BaseIdInput> input);
|
||||
/// <summary>
|
||||
/// 删除变量缓存
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
void DeleteVariableFromCache(List<long> ids = null);
|
||||
void DeleteVariableFromCache(long userId);
|
||||
/// <summary>
|
||||
/// 删除变量缓存
|
||||
/// </summary>
|
||||
void DeleteVariableFromCache(long id);
|
||||
/// <summary>
|
||||
/// 编辑变量
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Edit(CollectDeviceVariable input);
|
||||
/// <summary>
|
||||
/// 导出
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> ExportFile();
|
||||
/// <summary>
|
||||
/// 导出
|
||||
/// </summary>
|
||||
/// <param name="collectDeviceVariables"></param>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> ExportFile(List<CollectDeviceVariable> collectDeviceVariables);
|
||||
/// <summary>
|
||||
/// 获取变量运行状态DTO
|
||||
/// </summary>
|
||||
/// <param name="devId"></param>
|
||||
/// <returns></returns>
|
||||
Task<List<CollectVariableRunTime>> GetCollectDeviceVariableRuntime(long devId = 0);
|
||||
/// <summary>
|
||||
/// 根据名称获取ID
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
long GetIdByName(string name);
|
||||
/// <summary>
|
||||
/// 根据ID获取名称
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
string GetNameById(long Id);
|
||||
/// <summary>
|
||||
/// 导入
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task Import(Dictionary<string, ImportPreviewOutputBase> input);
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<SqlSugarPagedList<CollectDeviceVariable>> Page(VariablePageInput input);
|
||||
/// <summary>
|
||||
/// 导入验证
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
Task<Dictionary<string, ImportPreviewOutputBase>> Preview(IBrowserFile file);
|
||||
/// <summary>
|
||||
/// 导出模板
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<MemoryStream> Template();
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ using ThingsGateway.Core;
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc cref="IVariableService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class VariableService : DbRepository<CollectDeviceVariable>, IVariableService
|
||||
{
|
||||
@@ -25,6 +26,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
private readonly IUploadDeviceService _uploadDeviceService;
|
||||
private readonly FileService _fileService;
|
||||
|
||||
/// <inheritdoc cref="IVariableService"/>
|
||||
public VariableService(SysCacheService sysCacheService,
|
||||
ICollectDeviceService collectDeviceService, FileService fileService,
|
||||
IUploadDeviceService uploadDeviceService
|
||||
@@ -198,6 +200,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
|
||||
|
||||
#region 导入导出
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出变量模板", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> Template()
|
||||
{
|
||||
@@ -209,6 +212,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出变量表", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> ExportFile()
|
||||
{
|
||||
@@ -266,6 +270,7 @@ namespace ThingsGateway.Web.Foundation
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("导出变量表", IsRecordPar = false)]
|
||||
public async Task<MemoryStream> ExportFile(List<CollectDeviceVariable> collectDeviceVariables)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 运行日志分页DTO
|
||||
/// </summary>
|
||||
public class RuntimeLogPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
@@ -17,6 +19,9 @@ namespace ThingsGateway.Web.Foundation
|
||||
public string Level { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// RPC日志分页DTO
|
||||
/// </summary>
|
||||
public class RpcLogPageInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -2,9 +2,21 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC日志服务
|
||||
/// </summary>
|
||||
public interface IRpcLogService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 删除
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task Delete();
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<SqlSugarPagedList<RpcLog>> Page(RpcLogPageInput input);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,21 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行日志服务
|
||||
/// </summary>
|
||||
public interface IRuntimeLogService : ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 删除
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task Delete();
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<SqlSugarPagedList<RuntimeLog>> Page(RuntimeLogPageInput input);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc cref="IRpcLogService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class RpcLogService : DbRepository<RpcLog>, IRpcLogService
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace ThingsGateway.Web.Foundation
|
||||
{
|
||||
/// <inheritdoc cref="IRuntimeLogService"/>
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public class RuntimeLogService : DbRepository<RuntimeLog>, IRuntimeLogService
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[AppStartup(99)]
|
||||
public class Startup : AppStartup
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<NoWarn>CS1591;</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
@@ -214,11 +214,6 @@
|
||||
</MCol>
|
||||
|
||||
|
||||
<MCol Md=6 Cols=12 class="px-1">
|
||||
<MSubheader Class="font-weight-black"> @(context.Description(x => x.InitialValue)) </MSubheader>
|
||||
<MTextField Dense Outlined HideDetails="@("auto")" @bind-Value=@context.InitialValue />
|
||||
</MCol>
|
||||
|
||||
|
||||
<MCol Md=6 Cols=12 class="px-1">
|
||||
<MSubheader Class="font-weight-black"> @(context.Description(x => x.ProtectTypeEnum)) </MSubheader>
|
||||
|
||||
@@ -528,12 +528,12 @@
|
||||
async Task ImportVaiable(long devId)
|
||||
{
|
||||
var driver = this.GetBackgroundService<CollectDeviceHostService>().GetImportUI(devId);
|
||||
if (driver?.DriverUI == null)
|
||||
if (driver?.DriverImportUI == null)
|
||||
{
|
||||
await PopupService.EnqueueSnackbarAsync("插件未实现导入变量", AlertTypes.Warning);
|
||||
return;
|
||||
}
|
||||
_importComponent = new BootstrapDynamicComponent(driver.DriverUI, new Dictionary<string, object>()
|
||||
_importComponent = new BootstrapDynamicComponent(driver.DriverImportUI, new Dictionary<string, object>()
|
||||
{
|
||||
[nameof(DriverUI.Driver)] = driver
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@inject UserResoures UserResoures
|
||||
@layout MainLayout
|
||||
<AppDataTable @ref="_datatable" TItem="DriverPlugin" SearchItem="DriverPluginPageInput"
|
||||
AddItem="DriverPluginAddInput" EditItem="DriverPluginEditInput"
|
||||
AddItem="DriverPluginAddInput" EditItem="object"
|
||||
SearchModel="@search" IsMenuOperTemplate=false
|
||||
QueryCall="QueryCall" AddCall="AddCall"
|
||||
FilterHeaders="FilterHeaders" Filters="Filters" ShowDetailButton
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<NoWarn>BL0005;CS0168;</NoWarn>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,17 +5,26 @@ using Masa.Blazor;
|
||||
|
||||
namespace ThingsGateway.Web.Rcl.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 标签页表示
|
||||
/// </summary>
|
||||
/// <param name="Title">标题</param>
|
||||
/// <param name="Href">Path</param>
|
||||
/// <param name="Icon">图标</param>
|
||||
public record PageTabItem(string Title, string Href, string Icon);
|
||||
/// <summary>
|
||||
/// 用户菜单等资源管理
|
||||
/// 自定义资源管理
|
||||
/// </summary>
|
||||
public class UserResoures : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 主题
|
||||
/// </summary>
|
||||
public APPThemes Themes = new();
|
||||
private IAuthService _authService;
|
||||
private CookieStorage _cookieStorage;
|
||||
private IUserCenterService _userCenterService;
|
||||
|
||||
/// <inheritdoc cref="UserResoures"/>>
|
||||
public UserResoures(CookieStorage cookieStorage, MasaBlazor masaBlazor, IHttpContextAccessor httpContextAccessor,
|
||||
IAuthService authService,
|
||||
ResourceService resourceService,
|
||||
@@ -28,31 +37,64 @@ namespace ThingsGateway.Web.Rcl.Core
|
||||
_resourceService = resourceService;
|
||||
if (httpContextAccessor.HttpContext is not null) InitCookie(httpContextAccessor.HttpContext.Request.Cookies);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前用户
|
||||
/// </summary>
|
||||
public SysUser CurrentUser { get; set; }
|
||||
/// <summary>
|
||||
/// 是否黑暗主题
|
||||
/// </summary>
|
||||
public bool IsDark => _masaBlazor.Theme.Dark;
|
||||
|
||||
/// <summary>
|
||||
/// 全部个人菜单
|
||||
/// </summary>
|
||||
public List<SysResource> Menus { get; set; }
|
||||
/// <summary>
|
||||
/// 全部快捷方式
|
||||
/// </summary>
|
||||
public List<SysResource> WorkbenchOutputs { get; set; }
|
||||
/// <summary>
|
||||
/// 相同等级的个人菜单
|
||||
/// </summary>
|
||||
public List<SysResource> SameLevelMenus { get; private set; } = new();
|
||||
/// <summary>
|
||||
/// 全部相同等级的菜单
|
||||
/// </summary>
|
||||
public List<SysResource> AllSameLevelMenus { get; private set; } = new();
|
||||
/// <summary>
|
||||
/// 全部标签页
|
||||
/// </summary>
|
||||
public List<PageTabItem> PageTabItems = new();
|
||||
|
||||
private MasaBlazor _masaBlazor { get; set; }
|
||||
private IResourceService _resourceService { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化全部内容
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task InitAllAsync()
|
||||
{
|
||||
await InitUserAsync();
|
||||
await InitMenuAsync();
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化用户信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task InitUserAsync()
|
||||
{
|
||||
CurrentUser = await _authService.GetLoginUser();
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化菜单信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task InitMenuAsync()
|
||||
{
|
||||
var ids = await _userCenterService.GetLoginWorkbench();
|
||||
@@ -63,18 +105,29 @@ namespace ThingsGateway.Web.Rcl.Core
|
||||
SameLevelMenus = Menus.TreeToList();
|
||||
PageTabItems = AllSameLevelMenus.SameLevelMenuPasePageTab();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按钮授权检查
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsHasButtonWithRole(string code)
|
||||
{
|
||||
if (UserManager.SuperAdmin) return true;
|
||||
return CurrentUser.ButtonCodeList.Contains(code.ToLower());
|
||||
}
|
||||
/// <summary>
|
||||
/// 页面授权检查
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsHasPageWithRole(string code)
|
||||
{
|
||||
if (UserManager.SuperAdmin) return true;
|
||||
return AllSameLevelMenus.Select(a => a.Component).Contains(code.ToLower());
|
||||
}
|
||||
//设置深浅主题统一由这个方法为入口
|
||||
/// <summary>
|
||||
/// 设置深浅主题统一由这个方法为入口
|
||||
/// </summary>
|
||||
public void SetDarkOrLightTheme()
|
||||
{
|
||||
Themes.IsDark = !Themes.IsDark;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<NoWarn>BL0005;CS0168;</NoWarn>
|
||||
<!--<GenerateDocumentationFile>True</GenerateDocumentationFile>-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -4,11 +4,20 @@ using System.Linq;
|
||||
|
||||
namespace ThingsGateway.Web.Rcl
|
||||
{
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־ҳ<D6BE><D2B3>
|
||||
/// </summary>
|
||||
public partial class Vislog
|
||||
{
|
||||
private IAppDataTable _datatable;
|
||||
private VisitLogPageInput search = new();
|
||||
/// <summary>
|
||||
/// <20><>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD>
|
||||
/// </summary>
|
||||
public List<StringFilters> CategoryFilters { get; set; } = new();
|
||||
/// <summary>
|
||||
/// ִ<>н<EFBFBD><D0BD><EFBFBD><EFBFBD>˵<EFBFBD>
|
||||
/// </summary>
|
||||
public List<StringFilters> ExeStatus { get; set; } = new();
|
||||
|
||||
private void FilterHeaders(List<DataTableHeader<DevLogVisit>> datas)
|
||||
@@ -65,7 +74,7 @@ namespace ThingsGateway.Web.Rcl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
CategoryFilters.Add(new StringFilters() { Key = T("<22><>¼"), Value = CateGoryConst.Log_LOGIN });
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user