diff --git a/src/Admin/ThingsGateway.Admin.Razor/Pages/HardwareInfoPage.razor b/src/Admin/ThingsGateway.Admin.Razor/Pages/HardwareInfoPage.razor index 9db02b464..68b27a45f 100644 --- a/src/Admin/ThingsGateway.Admin.Razor/Pages/HardwareInfoPage.razor +++ b/src/Admin/ThingsGateway.Admin.Razor/Pages/HardwareInfoPage.razor @@ -90,8 +90,8 @@
@((100 - (availableMemory * 100.00 / memory)).ToString("F2") + " %")
@Localizer["WorkingSet"] @(HardwareJob.HardwareInfo.WorkingSet + " MB") - @Localizer["AvailableMemory"] @((availableMemory / 1024.00 / 1024 / 1024).ToString("F2") + " GB") - @Localizer["TotalMemory"] @((memory / 1024.00 / 1024 / 1024).ToString("F2") + " GB") + @Localizer["AvailableMemory"] @((availableMemory / 1024.00 / 1024).ToString("F2") + " GB") + @Localizer["TotalMemory"] @((memory / 1024.00 / 1024).ToString("F2") + " GB") diff --git a/src/Admin/ThingsGateway.AdminServer/Program/Startup.cs b/src/Admin/ThingsGateway.AdminServer/Program/Startup.cs index c290893a9..9c0130f3a 100644 --- a/src/Admin/ThingsGateway.AdminServer/Program/Startup.cs +++ b/src/Admin/ThingsGateway.AdminServer/Program/Startup.cs @@ -107,7 +107,7 @@ public class Startup : AppStartup .AddHubOptions(options => { //单个传入集线器消息的最大大小。默认 32 KB - options.MaximumReceiveMessageSize = 1024 * 1024; + options.MaximumReceiveMessageSize = 32 * 1024 * 1024; //可为客户端上载流缓冲的最大项数。 如果达到此限制,则会阻止处理调用,直到服务器处理流项。 options.StreamBufferCapacity = 30; options.ClientTimeoutInterval = TimeSpan.FromMinutes(2); @@ -126,7 +126,7 @@ public class Startup : AppStartup }).AddHubOptions(options => { //单个传入集线器消息的最大大小。默认 32 KB - options.MaximumReceiveMessageSize = 1024 * 1024; + options.MaximumReceiveMessageSize = 32 * 1024 * 1024; //可为客户端上载流缓冲的最大项数。 如果达到此限制,则会阻止处理调用,直到服务器处理流项。 options.StreamBufferCapacity = 30; options.ClientTimeoutInterval = TimeSpan.FromMinutes(2); diff --git a/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs b/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs index ca67b29c7..80b6237c0 100644 --- a/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs +++ b/src/Admin/ThingsGateway.NewLife.X/Common/MachineInfo.cs @@ -88,11 +88,11 @@ public class MachineInfo : IExtend [DisplayName("磁盘序列号")] public String? DiskID { get; set; } - /// 内存总量。单位Byte + /// 内存总量。单位KB [DisplayName("内存总量")] public UInt64 Memory { get; set; } - /// 可用内存。单位Byte + /// 可用内存。单位KB [DisplayName("可用内存")] public UInt64 AvailableMemory { get; set; } @@ -337,7 +337,7 @@ public class MachineInfo : IExtend #if NETFRAMEWORK || WINDOWS { var ci = new Microsoft.VisualBasic.Devices.ComputerInfo(); - Memory = ci.TotalPhysicalMemory; + Memory = (ulong)(ci.TotalPhysicalMemory / 1024.0); } #endif @@ -557,7 +557,7 @@ public class MachineInfo : IExtend //if (dic2.TryGetValue("Model Name", out str)) Product = str; if (dic.TryGetValue("Model Identifier", out var str)) Product = str; if (dic.TryGetValue("Processor Name", out str)) Processor = str; - if (dic.TryGetValue("Memory", out str)) Memory = (UInt64)str.TrimEnd("GB").Trim().ToLong() * 1024 * 1024 * 1024; + if (dic.TryGetValue("Memory", out str)) Memory = (UInt64)str.TrimEnd("GB").Trim().ToLong() * 1024 * 1024; if (dic.TryGetValue("Serial Number (system)", out str)) Serial = str; if (dic.TryGetValue("Hardware UUID", out str)) UUID = str; if (dic.TryGetValue("Processor Name", out str)) Processor = str; @@ -594,8 +594,8 @@ public class MachineInfo : IExtend ms.Init(); if (GlobalMemoryStatusEx(ref ms)) { - Memory = ms.ullTotalPhys; - AvailableMemory = ms.ullAvailPhys; + Memory = (ulong)(ms.ullTotalPhys / 1024.0); + AvailableMemory = (ulong)(ms.ullAvailPhys / 1024.0); } GetSystemTimes(out var idleTime, out var kernelTime, out var userTime); @@ -695,15 +695,15 @@ public class MachineInfo : IExtend if (dic != null) { if (dic.TryGetValue("MemTotal", out var str) && !str.IsNullOrEmpty()) - Memory = (UInt64)str.TrimEnd(" kB").ToInt() * 1024; + Memory = (UInt64)str.TrimEnd(" kB").ToLong(); if (dic.TryGetValue("MemAvailable", out str) && !str.IsNullOrEmpty()) - AvailableMemory = (UInt64)str.TrimEnd(" kB").ToInt() * 1024; + AvailableMemory = (UInt64)str.TrimEnd(" kB").ToLong(); else if (dic.TryGetValue("MemFree", out str) && !str.IsNullOrEmpty()) AvailableMemory = - (UInt64)(str.TrimEnd(" kB").ToInt() + - dic["Buffers"]?.TrimEnd(" kB").ToInt() ?? 0 + - dic["Cached"]?.TrimEnd(" kB").ToInt() ?? 0) * 1024; + (UInt64)(str.TrimEnd(" kB").ToLong() + + dic["Buffers"]?.TrimEnd(" kB").ToLong() ?? 0 + + dic["Cached"]?.TrimEnd(" kB").ToLong() ?? 0); } // A2/A4温度获取,Buildroot,CPU温度和主板温度 diff --git a/src/Admin/ThingsGateway.NewLife.X/Logger/Logger.cs b/src/Admin/ThingsGateway.NewLife.X/Logger/Logger.cs index 6afef49dc..c22cc48fa 100644 --- a/src/Admin/ThingsGateway.NewLife.X/Logger/Logger.cs +++ b/src/Admin/ThingsGateway.NewLife.X/Logger/Logger.cs @@ -245,7 +245,7 @@ public abstract class Logger : ILog sb.AppendFormat("#CPU: {0}\r\n", Environment.ProcessorCount); if (mi != null) { - sb.AppendFormat("#Memory: {0:n0}M/{1:n0}M\r\n", mi.AvailableMemory / 1024 / 1024, mi.Memory / 1024 / 1024); + sb.AppendFormat("#Memory: {0:n0}M/{1:n0}M\r\n", mi.AvailableMemory / 1024, mi.Memory / 1024); sb.AppendFormat("#Processor: {0}\r\n", mi.Processor); if (!mi.Product.IsNullOrEmpty()) sb.AppendFormat("#Product: {0} / {1}\r\n", mi.Product, mi.Vendor); if (mi.Temperature > 0) sb.AppendFormat("#Temperature: {0}\r\n", mi.Temperature); diff --git a/src/Admin/ThingsGateway.Razor/Common/ImportPreviewOutput.cs b/src/Admin/ThingsGateway.Razor/Common/ImportPreviewOutput.cs index abe98a191..e12b4c548 100644 --- a/src/Admin/ThingsGateway.Razor/Common/ImportPreviewOutput.cs +++ b/src/Admin/ThingsGateway.Razor/Common/ImportPreviewOutput.cs @@ -44,3 +44,14 @@ public class ImportPreviewOutput : ImportPreviewOutputBase where T : class /// public Dictionary Data { get; set; } = new(); } +/// +/// 导入预览 +/// +/// +public class ImportPreviewListOutput : ImportPreviewOutputBase where T : class +{ + /// + /// 数据 + /// + public List Data { get; set; } = new(); +} diff --git a/src/Admin/ThingsGateway.SqlSugar/Sugar/Abstract/QueryableProvider/QueryableExecuteSql.cs b/src/Admin/ThingsGateway.SqlSugar/Sugar/Abstract/QueryableProvider/QueryableExecuteSql.cs index 27fde6e37..b5ca064f2 100644 --- a/src/Admin/ThingsGateway.SqlSugar/Sugar/Abstract/QueryableProvider/QueryableExecuteSql.cs +++ b/src/Admin/ThingsGateway.SqlSugar/Sugar/Abstract/QueryableProvider/QueryableExecuteSql.cs @@ -683,7 +683,7 @@ namespace ThingsGateway.SqlSugar var entityInfo = this.Context.EntityMaintenance.GetEntityInfo(); var columns = UtilMethods.GetColumnInfo(dr); var cacheKey = "ForEachDataReader" + typeof(T).GetHashCode() + string.Join(",", columns.Select(it => it.Item1 + it.Item2.Name + "_")); - IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate("cacheKey", () => + IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () => { var cacheResult = new IDataReaderEntityBuilder(this.Context, dr, columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T)); @@ -703,15 +703,15 @@ namespace ThingsGateway.SqlSugar this.Context.Ado.Close(); } } - public IEnumerable ForEachDataReader() + public IEnumerable GetEnumerable() { var queryable = this.Clone(); var sql = queryable.ToSql(); var dr = this.Context.Ado.GetDataReader(sql.Key, sql.Value); var entityInfo = this.Context.EntityMaintenance.GetEntityInfo(); var columns = UtilMethods.GetColumnInfo(dr); - var cacheKey = "ForEachDataReader" + typeof(T).GetHashCode() + string.Join(",", columns.Select(it => it.Item1 + it.Item2.Name + "_")); - IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate("cacheKey", () => + var cacheKey = "GetEnumerable" + typeof(T).GetHashCode() + string.Join(",", columns.Select(it => it.Item1 + it.Item2.Name + "_")); + IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () => { var cacheResult = new IDataReaderEntityBuilder(this.Context, dr, columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T)); @@ -743,7 +743,7 @@ namespace ThingsGateway.SqlSugar var entityInfo = this.Context.EntityMaintenance.GetEntityInfo(); var columns = UtilMethods.GetColumnInfo(dr); var cacheKey = "ForEachDataReader" + typeof(T).GetHashCode() + string.Join(",", columns.Select(it => it.Item1 + it.Item2.Name + "_")); - IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate("cacheKey", () => + IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () => { var cacheResult = new IDataReaderEntityBuilder(this.Context, dr, columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T)); @@ -775,8 +775,8 @@ namespace ThingsGateway.SqlSugar var dr = await Context.Ado.GetDataReaderAsync(sql.Key, sql.Value).ConfigureAwait(false); var entityInfo = this.Context.EntityMaintenance.GetEntityInfo(); var columns = UtilMethods.GetColumnInfo(dr); - var cacheKey = "ForEachDataReader" + typeof(T).GetHashCode() + string.Join(",", columns.Select(it => it.Item1 + it.Item2.Name + "_")); - IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate("cacheKey", () => + var cacheKey = "GetAsyncEnumerable" + typeof(T).GetHashCode() + string.Join(",", columns.Select(it => it.Item1 + it.Item2.Name + "_")); + IDataReaderEntityBuilder entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () => { var cacheResult = new IDataReaderEntityBuilder(this.Context, dr, columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T)); @@ -784,7 +784,6 @@ namespace ThingsGateway.SqlSugar }); - using (dr) { while (dr.Read()) diff --git a/src/Admin/ThingsGateway.SqlSugar/Sugar/Interface/IIncludes.cs b/src/Admin/ThingsGateway.SqlSugar/Sugar/Interface/IIncludes.cs index d021ef69c..1bbb0ae31 100644 --- a/src/Admin/ThingsGateway.SqlSugar/Sugar/Interface/IIncludes.cs +++ b/src/Admin/ThingsGateway.SqlSugar/Sugar/Interface/IIncludes.cs @@ -33,7 +33,7 @@ namespace ThingsGateway.SqlSugar NavISugarQueryable Includes(Expression>> include1, Expression> include2, Expression> include3); NavISugarQueryable Includes(Expression> include1, Expression>> include2, Expression>> include3); IAsyncEnumerable GetAsyncEnumerable(); - IEnumerable ForEachDataReader(); + IEnumerable GetEnumerable(); } /// diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 20ad19492..36ef22edc 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,8 +1,8 @@ - 10.9.15 - 10.9.14 + 10.9.16 + 10.9.16 2.9.5 10.9.5 8.0.17 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs b/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs index 58f7e4512..777997d91 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Mapper/GatewayMapper.cs @@ -28,7 +28,6 @@ public static partial class GatewayMapper [MapProperty(nameof(Variable.InitValue), nameof(VariableRuntime.Value))] public static partial VariableRuntime AdaptVariableRuntime(this Variable src); - public static partial List AdaptListVariable(this IEnumerable src); public static partial DeviceRuntime AdaptDeviceRuntime(this Device src); diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelService.cs index 2c7249a9a..1ffd526f3 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelService.cs @@ -323,8 +323,8 @@ internal sealed class ChannelService : BaseService, IChannelService { if (item.Key == ExportString.ChannelName) { - var channelImports = ((ImportPreviewOutput)item.Value).Data; - channels = channelImports.Select(a => a.Value).ToList(); + var channelImports = ((ImportPreviewListOutput)item.Value).Data; + channels = channelImports; break; } } @@ -334,8 +334,16 @@ internal sealed class ChannelService : BaseService, IChannelService ManageHelper.CheckChannelCount(insertData.Count); using var db = GetDB(); - await db.BulkCopyAsync(insertData, 100000).ConfigureAwait(false); - await db.BulkUpdateAsync(upData, 100000).ConfigureAwait(false); + if (GlobalData.HardwareJob.HardwareInfo.MachineInfo.AvailableMemory > 2 * 1024 * 1024) + { + await db.BulkCopyAsync(insertData, 200000).ConfigureAwait(false); + await db.BulkUpdateAsync(upData, 200000).ConfigureAwait(false); + } + else + { + await db.BulkCopyAsync(insertData, 10000).ConfigureAwait(false); + await db.BulkUpdateAsync(upData, 10000).ConfigureAwait(false); + } DeleteChannelFromCache(); return channels.Select(a => a.Id).ToHashSet(); } @@ -352,11 +360,10 @@ internal sealed class ChannelService : BaseService, IChannelService //导入检验结果 Dictionary ImportPreviews = new(); //设备页 - ImportPreviewOutput channelImportPreview = new(); foreach (var sheetName in sheetNames) { var rows = MiniExcel.Query(path, useHeaderRow: true, sheetName: sheetName).Cast>(); - SetChannelData(dataScope, channelDicts, ImportPreviews, channelImportPreview, sheetName, rows); + SetChannelData(dataScope, channelDicts, ImportPreviews, sheetName, rows); } return ImportPreviews; @@ -367,16 +374,15 @@ internal sealed class ChannelService : BaseService, IChannelService } } - public void SetChannelData(HashSet? dataScope, Dictionary channelDicts, Dictionary ImportPreviews, ImportPreviewOutput channelImportPreview, string sheetName, IEnumerable> rows) + public void SetChannelData(HashSet? dataScope, Dictionary channelDicts, Dictionary ImportPreviews, string sheetName, IEnumerable> rows) { #region sheet if (sheetName == ExportString.ChannelName) { int row = 1; - ImportPreviewOutput importPreviewOutput = new(); + ImportPreviewListOutput importPreviewOutput = new(); ImportPreviews.Add(sheetName, importPreviewOutput); - channelImportPreview = importPreviewOutput; List channels = new(); var type = typeof(Channel); // 获取目标类型的所有属性,并根据是否需要过滤 IgnoreExcelAttribute 进行筛选 @@ -451,7 +457,7 @@ internal sealed class ChannelService : BaseService, IChannelService return; } }); - importPreviewOutput.Data = channels.ToDictionary(a => a.Name); + importPreviewOutput.Data = channels.DistinctBy(a => a.Name).ToList(); } #endregion sheet diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelServiceHelpers.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelServiceHelpers.cs index 85f9d56e0..a51ae99c4 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelServiceHelpers.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/ChannelServiceHelpers.cs @@ -133,7 +133,6 @@ public static class ChannelServiceHelpers //导入检验结果 Dictionary ImportPreviews = new(); //设备页 - ImportPreviewOutput channelImportPreview = new(); var sheetNames = uSheetDatas.sheets.Keys.ToList(); foreach (var sheetName in sheetNames) @@ -156,10 +155,11 @@ public static class ChannelServiceHelpers rows.Add(expando); } - GlobalData.ChannelService.SetChannelData(dataScope, channelDicts, ImportPreviews, channelImportPreview, sheetName, rows); - if (channelImportPreview.HasError) + GlobalData.ChannelService.SetChannelData(dataScope, channelDicts, ImportPreviews, sheetName, rows); + var data = ImportPreviews?.FirstOrDefault().Value; + if (data?.HasError == true) { - throw new(channelImportPreview.Results.FirstOrDefault(a => !a.Success).ErrorMessage ?? "error"); + throw new(data.Results.FirstOrDefault(a => !a.Success).ErrorMessage ?? "error"); } } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/IChannelService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/IChannelService.cs index 1f17d0d3f..1959246bb 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/IChannelService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Channel/IChannelService.cs @@ -95,7 +95,7 @@ internal interface IChannelService Task BatchSaveAsync(List input, ItemChangedType type); - void SetChannelData(HashSet? dataScope, Dictionary channelDicts, Dictionary ImportPreviews, ImportPreviewOutput channelImportPreview, string sheetName, IEnumerable> rows); + void SetChannelData(HashSet? dataScope, Dictionary channelDicts, Dictionary ImportPreviews, string sheetName, IEnumerable> rows); /// /// 保存是否输出日志和日志等级 diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs index 1f8909998..fce701c2d 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceService.cs @@ -337,8 +337,8 @@ internal sealed class DeviceService : BaseService, IDeviceService { channelDicts.TryGetValue(a, out var channel); var pluginKey = channel?.PluginName; - return (a, pluginKey); - }).ToList(); + return pluginKey; + }).ToHashSet(); var sheets = DeviceServiceHelpers.ExportSheets(devices, plugins, deviceDicts, channelDicts, pluginSheetNames); // IEnumerable 延迟执行 @@ -362,18 +362,18 @@ internal sealed class DeviceService : BaseService, IDeviceService /// 导出文件 /// [OperDesc("ExportDevice", isRecordPar: false, localizerType: typeof(Device))] - public async Task ExportMemoryStream(List? data, string channelName = null, string plugin = null) + public async Task ExportMemoryStream(List? models, string channelName = null, string plugin = null) { var deviceDicts = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); var channelDicts = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); - var pluginSheetNames = data.Select(a => a.ChannelId).Select(a => + var pluginSheetNames = models.Select(a => a.ChannelId).Select(a => { channelDicts.TryGetValue(a, out var channel); - var pluginKey = channel?.PluginName ?? plugin; - return (a, pluginKey); - }).ToList(); + var pluginKey = channel?.PluginName; + return pluginKey; + }).ToHashSet(); - var sheets = DeviceServiceHelpers.ExportSheets(data, deviceDicts, channelDicts, pluginSheetNames, channelName); + var sheets = DeviceServiceHelpers.ExportSheets(models, deviceDicts, channelDicts, pluginSheetNames, channelName); var memoryStream = new MemoryStream(); await memoryStream.SaveAsAsync(sheets).ConfigureAwait(false); memoryStream.Seek(0, SeekOrigin.Begin); @@ -407,8 +407,16 @@ internal sealed class DeviceService : BaseService, IDeviceService ManageHelper.CheckDeviceCount(insertData.Count); using var db = GetDB(); - await db.BulkCopyAsync(insertData, 100000).ConfigureAwait(false); - await db.BulkUpdateAsync(upData, 100000).ConfigureAwait(false); + if (GlobalData.HardwareJob.HardwareInfo.MachineInfo.AvailableMemory > 2 * 1024 * 1024) + { + await db.BulkCopyAsync(insertData, 200000).ConfigureAwait(false); + await db.BulkUpdateAsync(upData, 200000).ConfigureAwait(false); + } + else + { + await db.BulkCopyAsync(insertData, 10000).ConfigureAwait(false); + await db.BulkUpdateAsync(upData, 10000).ConfigureAwait(false); + } DeleteDeviceFromCache(); return devices.Select(a => a.Id).ToHashSet(); } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceServiceHelpers.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceServiceHelpers.cs index c840e9b6d..5c3366796 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceServiceHelpers.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Device/DeviceServiceHelpers.cs @@ -27,8 +27,8 @@ public static class DeviceServiceHelpers { channelDicts.TryGetValue(a, out var channel); var pluginKey = channel?.PluginName; - return (a, pluginKey); - }).ToList(); + return pluginKey; + }).ToHashSet(); var data = ExportSheets(models, deviceDicts, channelDicts, pluginSheetNames); // IEnumerable 延迟执行 return USheetDataHelpers.GetUSheetDatas(data); @@ -39,7 +39,7 @@ public static class DeviceServiceHelpers IEnumerable? data, Dictionary? deviceDicts, Dictionary channelDicts, -IEnumerable<(long, string)>? pluginSheetNames, +HashSet pluginSheetNames, string? channelName = null) { if (data?.Any() != true) @@ -51,14 +51,13 @@ IEnumerable<(long, string)>? pluginSheetNames, ConcurrentDictionary)> propertysDict = new(); - foreach (var dName in pluginSheetNames.DistinctBy(a => a.Item2)) + foreach (var plugin in pluginSheetNames) { - var filtResult = PluginServiceUtil.GetFileNameAndTypeName(dName.Item2); - var ids = pluginSheetNames.Where(a => a.Item2 == dName.Item2).Select(a => a.Item1).ToHashSet(); - var pluginSheets = GetPluginSheets(data.Where(a => ids.Contains(a.ChannelId)), propertysDict, dName.Item2); + var filtered = FilterPluginDevices(data, plugin, channelDicts); + var filtResult = PluginServiceUtil.GetFileNameAndTypeName(plugin); + var pluginSheets = GetPluginSheets(filtered, propertysDict, plugin); result.Add(filtResult.TypeName, pluginSheets); } - return result; } @@ -68,7 +67,7 @@ IAsyncEnumerable? data1, IAsyncEnumerable? data2, Dictionary? deviceDicts, Dictionary channelDicts, -IEnumerable<(long, string)>? pluginSheetNames, +HashSet pluginSheetNames, string? channelName = null) { if (data1 == null || data2 == null) @@ -78,19 +77,51 @@ string? channelName = null) result.Add(ExportString.DeviceName, GetDeviceSheets(data1, deviceDicts, channelDicts, channelName)); ConcurrentDictionary)> propertysDict = new(); - foreach (var dName in pluginSheetNames.DistinctBy(a => a.Item2)) + + foreach (var plugin in pluginSheetNames) { - var filtResult = PluginServiceUtil.GetFileNameAndTypeName(dName.Item2); - var ids = pluginSheetNames.Where(a => a.Item2 == dName.Item2).Select(a => a.Item1).ToHashSet(); - var pluginSheets = GetPluginSheets(data2.Where(a => ids.Contains(a.ChannelId)), propertysDict, dName.Item2); + var filtered = FilterPluginDevices(data2, plugin, channelDicts); + var filtResult = PluginServiceUtil.GetFileNameAndTypeName(plugin); + var pluginSheets = GetPluginSheets(filtered, propertysDict, plugin); result.Add(filtResult.TypeName, pluginSheets); } return result; } - - - + static IAsyncEnumerable FilterPluginDevices(IAsyncEnumerable data, string plugin, Dictionary channelDicts) + { + return data.Where(device => + { + if (channelDicts.TryGetValue(device.ChannelId, out var channel)) + { + if (channel.PluginName == plugin) + return true; + else + return false; + } + else + { + return true; + } + }); + } + static IEnumerable FilterPluginDevices(IEnumerable data, string plugin, Dictionary channelDicts) + { + return data.Where(device => + { + if (channelDicts.TryGetValue(device.ChannelId, out var channel)) + { + if (channel.PluginName == plugin) + return true; + else + return false; + } + else + { + return true; + } + }); + } static IEnumerable> GetDeviceSheets( IEnumerable data, diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs index c9e6d0478..ee9678188 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/GatewayMonitor/GatewayMonitorHostedService.cs @@ -42,7 +42,9 @@ internal sealed class GatewayMonitorHostedService : BackgroundService, IGatewayM //网关启动时,获取所有通道 var channelRuntimes = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).AdaptListChannelRuntime(); var deviceRuntimes = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).AdaptListDeviceRuntime(); - var variableRuntimes = (await GlobalData.VariableService.GetAllAsync().ConfigureAwait(false)).AdaptListVariableRuntime(); + + var variableRuntimes = GlobalData.VariableService.GetAllVariableRuntime(); + foreach (var channelRuntime in channelRuntimes) { try diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableRuntimeService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableRuntimeService.cs index bb1fef421..6c2af6c14 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableRuntimeService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableRuntimeService.cs @@ -30,7 +30,6 @@ namespace ThingsGateway.Gateway.Application Task> PreviewAsync(IBrowserFile browserFile); Task SaveVariableAsync(Variable input, ItemChangedType type, bool restart, CancellationToken cancellationToken); - void PreheatCache(); Task ExportMemoryStream(List data, string devName); } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableService.cs index d75b90d03..a75a2494c 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/IVariableService.cs @@ -88,8 +88,6 @@ internal interface IVariableService /// 查询分页选项 Task> PageAsync(ExportFilter exportFilter); - Task PreheatCache(); - /// /// 异步预览导入的数据。 /// @@ -113,5 +111,6 @@ internal interface IVariableService Task> GetByDeviceIdAsync(List deviceIds); void DeleteVariableCache(); - Task>> SetVariableData(HashSet? dataScope, Dictionary deviceDicts, Dictionary ImportPreviews, ImportPreviewOutput> deviceImportPreview, Dictionary driverPluginNameDict, ConcurrentDictionary, Dictionary)> propertysDict, string sheetName, IEnumerable> rows); + ImportPreviewOutput> SetVariableData(HashSet? dataScope, Dictionary deviceDicts, Dictionary ImportPreviews, ImportPreviewOutput> deviceImportPreview, Dictionary driverPluginNameDict, ConcurrentDictionary, Dictionary)> propertysDict, string sheetName, IEnumerable> rows); + List GetAllVariableRuntime(); } diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableRuntimeService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableRuntimeService.cs index 1c103bf56..efde3d53a 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableRuntimeService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableRuntimeService.cs @@ -286,8 +286,6 @@ public class VariableRuntimeService : IVariableRuntimeService } } - public void PreheatCache() => GlobalData.VariableService.PreheatCache(); - public Task ExportMemoryStream(List data, string deviceName) => GlobalData.VariableService.ExportMemoryStream(data, deviceName); diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs index 8ac4e6e4a..abfa93aea 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableService.cs @@ -21,7 +21,6 @@ using System.Text; using ThingsGateway.Extension.Generic; using ThingsGateway.Foundation.Extension.Dynamic; -using ThingsGateway.NewLife; using ThingsGateway.SqlSugar; using TouchSocket.Core; @@ -212,9 +211,19 @@ internal sealed class VariableService : BaseService, IVariableService var result = await db.UseTranAsync(async () => { - await db.BulkCopyAsync(newChannels, 100000).ConfigureAwait(false); - await db.BulkCopyAsync(newDevices, 100000).ConfigureAwait(false); - await db.BulkCopyAsync(newVariables, 100000).ConfigureAwait(false); + if (GlobalData.HardwareJob.HardwareInfo.MachineInfo.AvailableMemory > 2 * 1024 * 1024) + { + await db.BulkCopyAsync(newChannels, 200000).ConfigureAwait(false); + await db.BulkCopyAsync(newDevices, 200000).ConfigureAwait(false); + await db.BulkCopyAsync(newVariables, 200000).ConfigureAwait(false); + } + else + { + await db.BulkCopyAsync(newChannels, 10000).ConfigureAwait(false); + await db.BulkCopyAsync(newDevices, 10000).ConfigureAwait(false); + await db.BulkCopyAsync(newVariables, 10000).ConfigureAwait(false); + } + }).ConfigureAwait(false); if (result.IsSuccess)//如果成功了 { @@ -372,6 +381,12 @@ internal sealed class VariableService : BaseService, IVariableService /// /// 查询条件 public async Task> PageAsync(ExportFilter exportFilter) + { + var whereQuery = await GetWhereQueryFunc(exportFilter).ConfigureAwait(false); + + return await QueryAsync(exportFilter.QueryPageOptions, whereQuery).ConfigureAwait(false); + } + private async Task, ISugarQueryable>> GetWhereQueryFunc(ExportFilter exportFilter) { var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); HashSet? deviceId = null; @@ -384,7 +399,7 @@ internal sealed class VariableService : BaseService, IVariableService { deviceId = (await _deviceService.GetAllAsync().ConfigureAwait(false)).Where(a => a.ChannelId == exportFilter.ChannelId).Select(a => a.Id).ToHashSet(); } - return await QueryAsync(exportFilter.QueryPageOptions, a => a + var whereQuery = (ISugarQueryable a) => a .WhereIF(!exportFilter.QueryPageOptions.SearchText.IsNullOrWhiteSpace(), a => a.Name.Contains(exportFilter.QueryPageOptions.SearchText!)) .WhereIF(exportFilter.PluginType == PluginTypeEnum.Collect, a => a.DeviceId == exportFilter.DeviceId) .WhereIF(deviceId != null, a => deviceId.Contains(a.DeviceId)) @@ -393,9 +408,34 @@ internal sealed class VariableService : BaseService, IVariableService .WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) - .WhereIF(exportFilter.PluginType == PluginTypeEnum.Business, u => SqlFunc.JsonLike(u.VariablePropertys, exportFilter.DeviceId.ToString())) + .WhereIF(exportFilter.PluginType == PluginTypeEnum.Business, u => SqlFunc.JsonLike(u.VariablePropertys, exportFilter.DeviceId.ToString())); + return whereQuery; + } - ).ConfigureAwait(false); + private async Task, IEnumerable>> GetWhereEnumerableFunc(ExportFilter exportFilter) + { + var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false); + HashSet? deviceId = null; + if (!exportFilter.PluginName.IsNullOrWhiteSpace()) + { + var channel = (await _channelService.GetAllAsync().ConfigureAwait(false)).Where(a => a.PluginName == exportFilter.PluginName).Select(a => a.Id).ToHashSet(); + deviceId = (await _deviceService.GetAllAsync().ConfigureAwait(false)).Where(a => channel.Contains(a.ChannelId)).Select(a => a.Id).ToHashSet(); + } + else if (exportFilter.ChannelId != null) + { + deviceId = (await _deviceService.GetAllAsync().ConfigureAwait(false)).Where(a => a.ChannelId == exportFilter.ChannelId).Select(a => a.Id).ToHashSet(); + } + var whereQuery = (IEnumerable a) => a + .WhereIF(!exportFilter.QueryPageOptions.SearchText.IsNullOrWhiteSpace(), a => a.Name.Contains(exportFilter.QueryPageOptions.SearchText!)) + .WhereIF(exportFilter.PluginType == PluginTypeEnum.Collect, a => a.DeviceId == exportFilter.DeviceId) + .WhereIF(deviceId != null, a => deviceId.Contains(a.DeviceId)) + + .WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询 + .WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId) + + + .WhereIF(exportFilter.PluginType == PluginTypeEnum.Business, u => SqlFunc.JsonLike(u.VariablePropertys, exportFilter.DeviceId.ToString())); + return whereQuery; } /// @@ -424,15 +464,36 @@ internal sealed class VariableService : BaseService, IVariableService App.CacheService.Remove(ThingsGatewayCacheConst.Cache_Variable); } + + public List GetAllVariableRuntime() + { + using (var db = DbContext.GetDB()) + { + var deviceVariables = db.Queryable().OrderBy(a => a.Id).GetEnumerable(); + return deviceVariables.AdaptListVariableRuntime(); + } + } #region 导出 /// /// 导出文件 /// [OperDesc("ExportVariable", isRecordPar: false, localizerType: typeof(Variable))] - public async Task ExportMemoryStream(List data, string deviceName = null) + public async Task ExportMemoryStream(List variables, string deviceName = null) { - var sheets = await VariableServiceHelpers.ExportCoreAsync(data, deviceName).ConfigureAwait(false); + var deviceDicts = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); + var channelDicts = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); + var pluginSheetNames = variables.Where(a => a.VariablePropertys?.Count > 0).SelectMany(a => a.VariablePropertys).Select(a => + { + if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) + { + var pluginKey = channel?.PluginName; + using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); + return new KeyValuePair(pluginKey, businessBase.VariablePropertys); + } + return new KeyValuePair(string.Empty, null); + }).Where(a => a.Value != null).DistinctBy(a => a.Key).ToDictionary(); + var sheets = VariableServiceHelpers.ExportSheets(variables, deviceDicts, channelDicts, pluginSheetNames); // IEnumerable 延迟执行 var memoryStream = new MemoryStream(); await memoryStream.SaveAsAsync(sheets).ConfigureAwait(false); @@ -446,11 +507,52 @@ internal sealed class VariableService : BaseService, IVariableService [OperDesc("ExportVariable", isRecordPar: false, localizerType: typeof(Variable))] public async Task> ExportVariableAsync(ExportFilter exportFilter) { - var data = (await PageAsync(exportFilter).ConfigureAwait(false)); - var sheets = await VariableServiceHelpers.ExportCoreAsync(data.Items, sortName: exportFilter.QueryPageOptions.SortName, sortOrder: exportFilter.QueryPageOptions.SortOrder).ConfigureAwait(false); - return sheets; - } + if (GlobalData.HardwareJob.HardwareInfo.MachineInfo.AvailableMemory < 4 * 1024 * 1024) + { + var whereQuery = await GetWhereEnumerableFunc(exportFilter).ConfigureAwait(false); + //导出 + var variables = GlobalData.IdVariables.Select(a => a.Value).GetQuery(exportFilter.QueryPageOptions, whereQuery, exportFilter.FilterKeyValueAction); + + var deviceDicts = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); + var channelDicts = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); + var pluginSheetNames = variables.Where(a => a.VariablePropertys?.Count > 0).SelectMany(a => a.VariablePropertys).Select(a => + { + if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) + { + var pluginKey = channel?.PluginName; + using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); + return new KeyValuePair(pluginKey, businessBase.VariablePropertys); + } + return new KeyValuePair(string.Empty, null); + }).Where(a => a.Value != null).DistinctBy(a => a.Key).ToDictionary(); + + var sheets = VariableServiceHelpers.ExportSheets(variables, deviceDicts, channelDicts, pluginSheetNames); // IEnumerable 延迟执行 + + return sheets; + + } + else + { + var data = (await PageAsync(exportFilter).ConfigureAwait(false)); + var sheets = await VariableServiceHelpers.ExportCoreAsync(data.Items, sortName: exportFilter.QueryPageOptions.SortName, sortOrder: exportFilter.QueryPageOptions.SortOrder).ConfigureAwait(false); + return sheets; + } + + } + private async Task> GetAsyncEnumerableData(ExportFilter exportFilter) + { + var whereQuery = await GetEnumerableData(exportFilter).ConfigureAwait(false); + return whereQuery.GetAsyncEnumerable(); + } + private async Task> GetEnumerableData(ExportFilter exportFilter) + { + var db = GetDB(); + var whereQuery = await GetWhereQueryFunc(exportFilter).ConfigureAwait(false); + + return GetQuery(db, exportFilter.QueryPageOptions, whereQuery, exportFilter.FilterKeyValueAction); + + } #endregion 导出 @@ -475,53 +577,21 @@ internal sealed class VariableService : BaseService, IVariableService var insertData = variables.Where(a => !a.IsUp).ToList(); ManageHelper.CheckVariableCount(insertData.Count); using var db = GetDB(); - await db.BulkCopyAsync(insertData, 100000).ConfigureAwait(false); - await db.BulkUpdateAsync(upData, 100000).ConfigureAwait(false); + if (GlobalData.HardwareJob.HardwareInfo.MachineInfo.AvailableMemory > 2 * 1024 * 1024) + { + await db.BulkCopyAsync(insertData, 200000).ConfigureAwait(false); + await db.BulkUpdateAsync(upData, 200000).ConfigureAwait(false); + } + else + { + await db.BulkCopyAsync(insertData, 10000).ConfigureAwait(false); + await db.BulkUpdateAsync(upData, 10000).ConfigureAwait(false); + } DeleteVariableCache(); return variables.Select(a => a.Id).ToHashSet(); } - private static readonly WaitLock _cacheLock = new(); - private async Task>> GetVariableImportData() - { - var key = ThingsGatewayCacheConst.Cache_Variable; - var datas = App.CacheService.Get>>(key); - - if (datas == null) - { - try - { - await _cacheLock.WaitAsync().ConfigureAwait(false); - datas = App.CacheService.Get>>(key); - if (datas == null) - { - using var db = GetDB(); - datas = (await db.Queryable().Select().ToListAsync().ConfigureAwait(false)).GroupBy(a => a.DeviceId).ToDictionary(a => a.Key, a => a.ToDictionary(a => a.Name)); - - App.CacheService.Set(key, datas); - } - } - finally - { - _cacheLock.Release(); - } - } - return datas; - } - - public Task PreheatCache() - { - return GetVariableImportData(); - } - private sealed class DeviecIdVariableImportData - { - public long Id { get; set; } - public string Name { get; set; } - public long DeviceId { get; set; } - public long CreateOrgId { get; set; } - public long CreateUserId { get; set; } - } public async Task> PreviewAsync(IBrowserFile browserFile) { @@ -552,7 +622,7 @@ internal sealed class VariableService : BaseService, IVariableService // 获取当前工作表的所有行数据 var rows = MiniExcel.Query(path, useHeaderRow: true, sheetName: sheetName).Cast>(); - deviceImportPreview = await SetVariableData(dataScope, deviceDicts, ImportPreviews, deviceImportPreview, driverPluginNameDict, propertysDict, sheetName, rows).ConfigureAwait(false); + deviceImportPreview = SetVariableData(dataScope, deviceDicts, ImportPreviews, deviceImportPreview, driverPluginNameDict, propertysDict, sheetName, rows); } return ImportPreviews; @@ -564,7 +634,7 @@ internal sealed class VariableService : BaseService, IVariableService } } - public async Task>> SetVariableData(HashSet? dataScope, Dictionary deviceDicts, Dictionary ImportPreviews, ImportPreviewOutput> deviceImportPreview, Dictionary driverPluginNameDict, ConcurrentDictionary, Dictionary)> propertysDict, string sheetName, IEnumerable> rows) + public ImportPreviewOutput> SetVariableData(HashSet? dataScope, Dictionary deviceDicts, Dictionary ImportPreviews, ImportPreviewOutput> deviceImportPreview, Dictionary driverPluginNameDict, ConcurrentDictionary, Dictionary)> propertysDict, string sheetName, IEnumerable> rows) { // 变量页处理 if (sheetName == ExportString.VariableName) @@ -581,8 +651,6 @@ internal sealed class VariableService : BaseService, IVariableService var variableProperties = type.GetRuntimeProperties().Where(a => (a.GetCustomAttribute() == null) && a.CanWrite) .ToDictionary(a => type.GetPropertyDisplayName(a.Name), a => (a, a.IsNullableType())); - var dbVariableDicts = await GetVariableImportData().ConfigureAwait(false); - // 并行处理每一行数据 rows.ParallelForEachStreamed((item, state, index) => { @@ -629,7 +697,7 @@ internal sealed class VariableService : BaseService, IVariableService return; } - if (dbVariableDicts.TryGetValue(variable.DeviceId, out var dbvar1s) && dbvar1s.TryGetValue(variable.Name, out var dbvar1)) + if (GlobalData.IdDevices.TryGetValue(variable.DeviceId, out var dbvar1s) && dbvar1s.VariableRuntimes.TryGetValue(variable.Name, out var dbvar1)) { variable.Id = dbvar1.Id; variable.CreateOrgId = dbvar1.CreateOrgId; diff --git a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs index 0548de7d7..4f5f5adac 100644 --- a/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs +++ b/src/Gateway/ThingsGateway.Gateway.Application/Services/Variable/VariableServiceHelpers.cs @@ -21,12 +21,295 @@ namespace ThingsGateway.Gateway.Application; public static class VariableServiceHelpers { - public static async Task ExportVariableAsync(IEnumerable models, string sortName = nameof(Variable.Id), SortOrder sortOrder = SortOrder.Asc) + public static async Task ExportVariableAsync(IEnumerable variables, string sortName = nameof(Variable.Id), SortOrder sortOrder = SortOrder.Asc) { - var data = await ExportCoreAsync(models, sortName: sortName, sortOrder: sortOrder).ConfigureAwait(false); - + var deviceDicts = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); + var channelDicts = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).ToDictionary(a => a.Id); + var pluginSheetNames = variables.Where(a => a.VariablePropertys?.Count > 0).SelectMany(a => a.VariablePropertys).Select(a => + { + if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) + { + var pluginKey = channel?.PluginName; + using var businessBase = (BusinessBase)GlobalData.PluginService.GetDriver(pluginKey); + return new KeyValuePair(pluginKey, businessBase.VariablePropertys); + } + return new KeyValuePair(string.Empty, null); + }).Where(a => a.Value != null).DistinctBy(a => a.Key).ToDictionary(); + var data = ExportSheets(variables, deviceDicts, channelDicts, pluginSheetNames); // IEnumerable 延迟执行 return USheetDataHelpers.GetUSheetDatas(data); } + static IAsyncEnumerable FilterPluginDevices( + IAsyncEnumerable data, + string pluginName, +Dictionary deviceDicts, + Dictionary channelDicts) + { + return data.Where(variable => + { + if (variable.VariablePropertys == null) + return false; + + foreach (var a in variable.VariablePropertys) + { + if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) + + { + if (channel.PluginName == pluginName) + return true; + } + } + + return false; + }); + } + static IEnumerable FilterPluginDevices( +IEnumerable data, +string pluginName, +Dictionary deviceDicts, +Dictionary channelDicts) + { + return data.Where(variable => + { + if (variable.VariablePropertys == null) + return false; + + foreach (var a in variable.VariablePropertys) + { + if (deviceDicts.TryGetValue(a.Key, out var device) && channelDicts.TryGetValue(device.ChannelId, out var channel)) + { + if (channel.PluginName == pluginName) + return true; + } + } + + return false; + }); + } + + + public static Dictionary ExportSheets( + IEnumerable data, + Dictionary deviceDicts, + Dictionary channelDicts, + Dictionary pluginDrivers, + string? deviceName = null) + { + var sheets = new Dictionary(); + var propertysDict = new ConcurrentDictionary)>(); + + // 主变量页 + sheets.Add(ExportString.VariableName, GetVariableSheets(data, deviceDicts, deviceName)); + + // 插件页(动态推导) + foreach (var plugin in pluginDrivers.Keys.Distinct()) + { + var filtered = FilterPluginDevices(data, plugin, deviceDicts, channelDicts); + var pluginName = PluginServiceUtil.GetFileNameAndTypeName(plugin).Item2; + sheets.Add(pluginName, GetPluginSheets(filtered, deviceDicts, channelDicts, plugin, pluginDrivers, propertysDict)); + } + + return sheets; + } + + static IEnumerable> GetVariableSheets( + IEnumerable data, + Dictionary deviceDicts, + string? deviceName) + { + var type = typeof(Variable); + var propertyInfos = type.GetRuntimeProperties() + .Where(a => a.GetCustomAttribute(false) == null) + .OrderBy(a => + { + var order = a.GetCustomAttribute()?.Order ?? int.MaxValue; + if (order < 0) order += 10000000; + else if (order == 0) order = 10000000; + return order; + }); + + foreach (var variable in data) + { + yield return GetVariable(deviceDicts, deviceName, type, propertyInfos, variable); + } + } + + private static Dictionary GetVariable(Dictionary deviceDicts, string? deviceName, Type type, IOrderedEnumerable propertyInfos, Variable variable) + { + var row = new Dictionary(); + deviceDicts.TryGetValue(variable.DeviceId, out var device); + row.TryAdd(ExportString.DeviceName, device?.Name ?? deviceName); + + foreach (var item in propertyInfos) + { + var desc = type.GetPropertyDisplayName(item.Name); + row.TryAdd(desc ?? item.Name, item.GetValue(variable)?.ToString()); + } + + return row; + } + + static IEnumerable> GetPluginSheets( + IEnumerable data, + Dictionary deviceDicts, + Dictionary channelDicts, + string plugin, + Dictionary pluginDrivers, + ConcurrentDictionary)> propertysDict) + { + if (!pluginDrivers.TryGetValue(plugin, out var variablePropertyBase)) + yield break; + + if (!propertysDict.TryGetValue(plugin, out var propertys)) + { + var driverProperties = variablePropertyBase; + var driverPropertyType = driverProperties.GetType(); + propertys.Item1 = driverProperties; + propertys.Item2 = driverPropertyType.GetRuntimeProperties() + .Where(a => a.GetCustomAttribute() != null) + .ToDictionary( + a => driverPropertyType.GetPropertyDisplayName(a.Name, a => a.GetCustomAttribute(true)?.Description)); + propertysDict.TryAdd(plugin, propertys); + } + if (propertys.Item2?.Count == null || propertys.Item2?.Count == 0) + { + yield break; + } + foreach (var variable in data) + { + if (variable.VariablePropertys == null) + continue; + + foreach (var item in variable.VariablePropertys) + { + if (!(deviceDicts.TryGetValue(item.Key, out var businessDevice) && + deviceDicts.TryGetValue(variable.DeviceId, out var collectDevice))) + continue; + + channelDicts.TryGetValue(businessDevice.ChannelId, out var channel); + if (channel?.PluginName != plugin) + continue; + + yield return GetPlugin(propertys, variable, item, businessDevice, collectDevice); + } + } + } + + private static Dictionary GetPlugin((VariablePropertyBase, Dictionary) propertys, Variable variable, KeyValuePair> item, Device businessDevice, Device collectDevice) + { + var row = new Dictionary + { + { ExportString.DeviceName, collectDevice.Name }, + { ExportString.BusinessDeviceName, businessDevice.Name }, + { ExportString.VariableName, variable.Name } + }; + + foreach (var kv in propertys.Item2) + { + var propDict = item.Value; + if (propDict.TryGetValue(kv.Value.Name, out var dependencyProperty)) + { + row.TryAdd(kv.Key, dependencyProperty); + } + else + { + row.TryAdd(kv.Key, ThingsGatewayStringConverter.Default.Serialize(null, kv.Value.GetValue(propertys.Item1))); + } + } + + return row; + } + + public static Dictionary ExportSheets( + IAsyncEnumerable data, + Dictionary deviceDicts, + Dictionary channelDicts, + Dictionary pluginDrivers, + string? deviceName = null) + { + var sheets = new Dictionary(); + var propertysDict = new ConcurrentDictionary)>(); + + // 主变量页 + sheets.Add(ExportString.VariableName, GetVariableSheets(data, deviceDicts, deviceName)); + + // 插件页(动态推导) + foreach (var plugin in pluginDrivers.Keys.Distinct()) + { + var filtered = FilterPluginDevices(data, plugin, deviceDicts, channelDicts); + var pluginName = PluginServiceUtil.GetFileNameAndTypeName(plugin).Item2; + sheets.Add(pluginName, GetPluginSheets(filtered, deviceDicts, channelDicts, plugin, pluginDrivers, propertysDict)); + } + + return sheets; + } + + static async IAsyncEnumerable> GetVariableSheets( + IAsyncEnumerable data, + Dictionary deviceDicts, + string? deviceName) + { + var type = typeof(Variable); + var propertyInfos = type.GetRuntimeProperties() + .Where(a => a.GetCustomAttribute(false) == null) + .OrderBy(a => + { + var order = a.GetCustomAttribute()?.Order ?? int.MaxValue; + if (order < 0) order += 10000000; + else if (order == 0) order = 10000000; + return order; + }); + + await foreach (var variable in data.ConfigureAwait(false)) + { + yield return GetVariable(deviceDicts, deviceName, type, propertyInfos, variable); + } + } + + static async IAsyncEnumerable> GetPluginSheets( + IAsyncEnumerable data, + Dictionary deviceDicts, + Dictionary channelDicts, + string plugin, + Dictionary pluginDrivers, + ConcurrentDictionary)> propertysDict) + { + if (!pluginDrivers.TryGetValue(plugin, out var variablePropertyBase)) + yield break; + + if (!propertysDict.TryGetValue(plugin, out var propertys)) + { + var driverProperties = variablePropertyBase; + var driverPropertyType = driverProperties.GetType(); + propertys.Item1 = driverProperties; + propertys.Item2 = driverPropertyType.GetRuntimeProperties() + .Where(a => a.GetCustomAttribute() != null) + .ToDictionary( + a => driverPropertyType.GetPropertyDisplayName(a.Name, a => a.GetCustomAttribute(true)?.Description)); + propertysDict.TryAdd(plugin, propertys); + } + if (propertys.Item2?.Count == null || propertys.Item2?.Count == 0) + { + yield break; + } + await foreach (var variable in data.ConfigureAwait(false)) + { + if (variable.VariablePropertys == null) + continue; + + foreach (var item in variable.VariablePropertys) + { + if (!(deviceDicts.TryGetValue(item.Key, out var businessDevice) && + deviceDicts.TryGetValue(variable.DeviceId, out var collectDevice))) + continue; + + channelDicts.TryGetValue(businessDevice.ChannelId, out var channel); + if (channel?.PluginName != plugin) + continue; + + yield return GetPlugin(propertys, variable, item, businessDevice, collectDevice); + } + } + } public static async Task> ExportCoreAsync(IEnumerable data, string deviceName = null, string sortName = nameof(Variable.Id), SortOrder sortOrder = SortOrder.Asc) { @@ -67,7 +350,6 @@ public static class VariableServiceHelpers ; #endregion 列名称 - var varName = nameof(Variable.Name); data.ParallelForEachStreamed((variable, state, index) => { Dictionary varExport = new(); @@ -83,10 +365,6 @@ public static class VariableServiceHelpers } //描述 var desc = type.GetPropertyDisplayName(item.Name); - if (item.Name == varName) - { - varName = desc; - } //数据源增加 varExport.TryAdd(desc ?? item.Name, item.GetValue(variable)?.ToString()); } @@ -128,7 +406,8 @@ public static class VariableServiceHelpers var variablePropertyType = variableProperty.GetType(); propertys.Item2 = variablePropertyType.GetRuntimeProperties() .Where(a => a.GetCustomAttribute() != null) - .ToDictionary(a => variablePropertyType.GetPropertyDisplayName(a.Name, a => a.GetCustomAttribute(true)?.Description)); + .ToDictionary(a => variablePropertyType.GetPropertyDisplayName(a.Name, a => + a.GetCustomAttribute(true)?.Description)); propertysDict.TryAdd(channel.PluginName, propertys); } @@ -263,7 +542,7 @@ public static class VariableServiceHelpers rows.Add(expando); } - deviceImportPreview = await GlobalData.VariableService.SetVariableData(dataScope, deviceDicts, ImportPreviews, deviceImportPreview, driverPluginNameDict, propertysDict, sheetName, rows).ConfigureAwait(false); + deviceImportPreview = GlobalData.VariableService.SetVariableData(dataScope, deviceDicts, ImportPreviews, deviceImportPreview, driverPluginNameDict, propertysDict, sheetName, rows); if (ImportPreviews.Any(a => a.Value.HasError)) { throw new(ImportPreviews.FirstOrDefault(a => a.Value.HasError).Value.Results.FirstOrDefault(a => !a.Success).ErrorMessage ?? "error"); diff --git a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Channel/ChannelTable.razor b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Channel/ChannelTable.razor index db6d8c4e0..f0b1ec798 100644 --- a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Channel/ChannelTable.razor +++ b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Channel/ChannelTable.razor @@ -39,48 +39,55 @@ - context.CacheTimeout) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.CheckClearTime) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.ConnectTimeout) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.Heartbeat) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.HeartbeatTime) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.DtuSeviceType) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.DtuId) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.CacheTimeout) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.CheckClearTime) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.ConnectTimeout) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.Heartbeat) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.HeartbeatTime) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.DtuSeviceType) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.DtuId) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.PluginType) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.PortName) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RemoteUrl) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.BindUrl) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.MaxClientCount) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.MaxConcurrentCount) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.PluginType) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.PortName) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RemoteUrl) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.BindUrl) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.MaxClientCount) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.MaxConcurrentCount) ShowTips=true Filterable=true Sortable=true Visible=false /> - + - - - - + @if ((AuthorizeButton("导出"))) + { + + + + } + @if ((AuthorizeButton("导入"))) + { + + + } diff --git a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Device/DeviceTable.razor b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Device/DeviceTable.razor index 1cd56589c..44b116f86 100644 --- a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Device/DeviceTable.razor +++ b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Device/DeviceTable.razor @@ -28,10 +28,10 @@ IsPagination=true> - context.Name) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.Description) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.IntervalTime) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.ChannelName) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.Name) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.Description) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.IntervalTime) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.ChannelName) ShowTips=true Filterable=true Sortable=true Visible=true /> @@ -40,25 +40,25 @@ - context.ActiveTime) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.DeviceStatus) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.ActiveTime) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.DeviceStatus) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.Pause) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.LastErrorMessage) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.Pause) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.LastErrorMessage) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.PluginName) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.PluginName) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.DeviceVariableCount) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.MethodVariableCount) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.SourceVariableCount) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.DeviceVariableCount) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.MethodVariableCount) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.SourceVariableCount) ShowTips=true Filterable=true Sortable=true Visible=true /> - context.ChannelId) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RedundantEnable) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RedundantType) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RedundantDeviceId) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RedundantScanIntervalTime) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RedundantScript) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> - context.RedundantSwitchType) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> + context.ChannelId) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RedundantEnable) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RedundantType) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RedundantDeviceId) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RedundantScanIntervalTime) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RedundantScript) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> + context.RedundantSwitchType) Ignore="true" ShowTips=true Filterable=true Sortable=true Visible=false /> @@ -66,28 +66,35 @@ - + - - - - + + @if ((AuthorizeButton("导出"))) + { + + + } + @if ((AuthorizeButton("导入"))) + { + + + } diff --git a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Variable/VariableRuntimeInfo.razor b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Variable/VariableRuntimeInfo.razor index d47aa4e0f..ddae10e8f 100644 --- a/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Variable/VariableRuntimeInfo.razor +++ b/src/Gateway/ThingsGateway.Gateway.Razor/Pages/GatewayMonitorPage/Variable/VariableRuntimeInfo.razor @@ -29,8 +29,8 @@ OnQueryAsync="OnQueryAsync" IsPagination=true> - context.DeviceId) ShowTips=true Filterable=true Sortable=true Visible=false /> - context.DeviceName) ShowTips=true Filterable=true Sortable=true Visible=true /> + context.DeviceId) ShowTips=true Filterable=true Sortable=true Visible=false /> + context.DeviceName) ShowTips=true Filterable=true Sortable=true Visible=true /> @@ -38,19 +38,19 @@ - context.ChangeTime) Filterable=true Sortable=true Visible=false /> - context.CollectTime) Filterable=true Sortable=true Visible=true /> - context.IsOnline) Filterable=true Sortable=true Visible=true /> - context.LastErrorMessage) Filterable=true Sortable=true Visible=false /> + context.ChangeTime) Filterable=true Sortable=true Visible=false /> + context.CollectTime) Filterable=true Sortable=true Visible=true /> + context.IsOnline) Filterable=true Sortable=true Visible=true /> + context.LastErrorMessage) Filterable=true Sortable=true Visible=false /> - context.LastSetValue) Visible=false ShowTips=true Formatter=@(JsonFormatter) /> + context.LastSetValue) Visible=false ShowTips=true Formatter=@(JsonFormatter) /> - context.RawValue) Visible=false ShowTips=true Formatter=@(JsonFormatter) /> - context.Value) Visible=true ShowTips=true Formatter=@(JsonFormatter) /> + context.RawValue) Visible=false ShowTips=true Formatter=@(JsonFormatter) /> + context.Value) Visible=true ShowTips=true Formatter=@(JsonFormatter) /> - context.RuntimeType) Filterable=true Sortable=true Visible=true /> + context.RuntimeType) Filterable=true Sortable=true Visible=true /> @@ -70,7 +70,7 @@ - +