mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-10-31 23:53:58 +08:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 77bfabc41d | ||
|   | 6427ee6ee0 | ||
|   | 4c95997d62 | 
| @@ -17,8 +17,7 @@ | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<None Include="$(OutputPath)\$(TargetFileName)" Pack="true" | ||||
| 			  PackagePath="analyzers/dotnet/cs" Visible="false" /> | ||||
| 		<None Include="$(OutputPath)\$(TargetFileName)" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
|  | ||||
| @@ -27,6 +26,6 @@ | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" /> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" Private="false" /> | ||||
| 	</ItemGroup> | ||||
| </Project> | ||||
|   | ||||
| @@ -1,29 +1,25 @@ | ||||
| using Microsoft.CodeAnalysis; | ||||
| using Microsoft.CodeAnalysis.CSharp; | ||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
| using Microsoft.CodeAnalysis.Text; | ||||
|  | ||||
| using System.Text; | ||||
|  | ||||
| namespace Microsoft.AspNetCore.Components; | ||||
|  | ||||
| [Generator] | ||||
| public partial class SetParametersAsyncGenerator : ISourceGenerator | ||||
| public sealed partial class SetParametersAsyncGenerator : IIncrementalGenerator | ||||
| { | ||||
|  | ||||
|     private string m_DoNotGenerateSetParametersAsyncAttribute = """ | ||||
|          | ||||
|     private const string m_DoNotGenerateSetParametersAsyncAttribute = """  | ||||
|     using System; | ||||
|     namespace Microsoft.AspNetCore.Components | ||||
|     { | ||||
|         [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] | ||||
|             internal sealed class DoNotGenerateSetParametersAsyncAttribute : Attribute | ||||
|             { | ||||
|             } | ||||
|         internal sealed class DoNotGenerateSetParametersAsyncAttribute : Attribute { } | ||||
|     } | ||||
| """; | ||||
|  | ||||
|  | ||||
|         """ | ||||
|         ; | ||||
|     private string m_GenerateSetParametersAsyncAttribute = """ | ||||
|          | ||||
|     private const string m_GenerateSetParametersAsyncAttribute = """  | ||||
|     using System; | ||||
|     namespace Microsoft.AspNetCore.Components | ||||
|     { | ||||
| @@ -33,12 +29,9 @@ public partial class SetParametersAsyncGenerator : ISourceGenerator | ||||
|             public bool RequireExactMatch { get; set; } | ||||
|         } | ||||
|     } | ||||
| """; | ||||
|  | ||||
|  | ||||
|         """ | ||||
|         ; | ||||
|     private string m_GlobalGenerateSetParametersAsyncAttribute = """ | ||||
|          | ||||
|     private const string m_GlobalGenerateSetParametersAsyncAttribute = """  | ||||
|     using System; | ||||
|     namespace Microsoft.AspNetCore.Components | ||||
|     { | ||||
| @@ -46,18 +39,10 @@ public partial class SetParametersAsyncGenerator : ISourceGenerator | ||||
|         internal sealed class GlobalGenerateSetParametersAsyncAttribute : Attribute | ||||
|         { | ||||
|             public bool Enable { get; } | ||||
|  | ||||
|                 public GlobalGenerateSetParametersAsyncAttribute(bool enable = true) | ||||
|                 { | ||||
|                     Enable = enable; | ||||
|             public GlobalGenerateSetParametersAsyncAttribute(bool enable = true) { Enable = enable; } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         } | ||||
|  | ||||
|  | ||||
|         """ | ||||
|         ; | ||||
| """; | ||||
|  | ||||
|     private static readonly DiagnosticDescriptor ParameterNameConflict = new DiagnosticDescriptor( | ||||
|         id: "TG0001", | ||||
| @@ -68,36 +53,64 @@ public partial class SetParametersAsyncGenerator : ISourceGenerator | ||||
|         isEnabledByDefault: true, | ||||
|         description: "Parameter names must be case insensitive to be usable in routes. Rename the parameter to not be in conflict with other parameters."); | ||||
|  | ||||
|     public void Initialize(GeneratorInitializationContext context) | ||||
|     public void Initialize(IncrementalGeneratorInitializationContext context) | ||||
|     { | ||||
|         context.RegisterForPostInitialization(a => | ||||
|         // 注入 attribute 源码 | ||||
|         context.RegisterPostInitializationOutput(ctx => | ||||
|         { | ||||
|             a.AddSource(nameof(m_DoNotGenerateSetParametersAsyncAttribute), m_DoNotGenerateSetParametersAsyncAttribute); | ||||
|             a.AddSource(nameof(m_GenerateSetParametersAsyncAttribute), m_GenerateSetParametersAsyncAttribute); | ||||
|             a.AddSource(nameof(m_GlobalGenerateSetParametersAsyncAttribute), m_GlobalGenerateSetParametersAsyncAttribute); | ||||
|             ctx.AddSource("DoNotGenerateSetParametersAsyncAttribute.g.cs", SourceText.From(m_DoNotGenerateSetParametersAsyncAttribute, Encoding.UTF8)); | ||||
|             ctx.AddSource("GenerateSetParametersAsyncAttribute.g.cs", SourceText.From(m_GenerateSetParametersAsyncAttribute, Encoding.UTF8)); | ||||
|             ctx.AddSource("GlobalGenerateSetParametersAsyncAttribute.g.cs", SourceText.From(m_GlobalGenerateSetParametersAsyncAttribute, Encoding.UTF8)); | ||||
|         }); | ||||
|  | ||||
|         // Register a syntax receiver that will be created for each generation pass | ||||
|         context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); | ||||
|         // 筛选 ClassDeclarationSyntax | ||||
|         var classDeclarations = context.SyntaxProvider | ||||
|             .CreateSyntaxProvider( | ||||
|                 predicate: static (node, _) => node is ClassDeclarationSyntax, | ||||
|                 transform: static (ctx, _) => (ClassDeclarationSyntax)ctx.Node) | ||||
|             .Where(static c => c is not null); | ||||
|  | ||||
|         // 合并 Compilation | ||||
|         var compilationProvider = context.CompilationProvider; | ||||
|  | ||||
|         var candidateClasses = classDeclarations.Combine(compilationProvider); | ||||
|  | ||||
|         context.RegisterSourceOutput(candidateClasses, static (spc, tuple) => | ||||
|         { | ||||
|             var (classDeclaration, compilation) = tuple; | ||||
|             Execute(spc, compilation, classDeclaration); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     public void Execute(GeneratorExecutionContext context) | ||||
|     { | ||||
|         // https://github.com/dotnet/AspNetCore.Docs/blob/1e199f340780f407a685695e6c4d953f173fa891/aspnetcore/blazor/webassembly-performance-best-practices.md#implement-setparametersasync-manually | ||||
|         if (context.SyntaxReceiver is not SyntaxReceiver receiver) | ||||
|     private static void Execute(SourceProductionContext context, Compilation compilation, ClassDeclarationSyntax classDeclaration) | ||||
|     { | ||||
|         var model = compilation.GetSemanticModel(classDeclaration.SyntaxTree); | ||||
|         var classSymbol = model.GetDeclaredSymbol(classDeclaration); | ||||
|         if (classSymbol is null || classSymbol.Name == "_Imports") | ||||
|             return; | ||||
|  | ||||
|         var positiveAttr = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.GenerateSetParametersAsyncAttribute"); | ||||
|         var negativeAttr = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.DoNotGenerateSetParametersAsyncAttribute"); | ||||
|  | ||||
|         if (classSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, negativeAttr))) | ||||
|             return; | ||||
|  | ||||
|         if (!IsPartial(classSymbol) || !IsComponent(classDeclaration, classSymbol, compilation)) | ||||
|             return; | ||||
|  | ||||
|         var globalEnable = compilation.Assembly.GetAttributes() | ||||
|             .FirstOrDefault(a => a.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.GlobalGenerateSetParametersAsyncAttribute") | ||||
|             ?.ConstructorArguments.FirstOrDefault().Value as bool? ?? false; | ||||
|  | ||||
|         var hasPositive = classSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, positiveAttr)); | ||||
|  | ||||
|         if (!globalEnable && !hasPositive) | ||||
|             return; | ||||
|  | ||||
|         GenerateSetParametersAsyncMethod(context, classSymbol); | ||||
|     } | ||||
|  | ||||
|         var candidate_classes = GetCandidateClasses(receiver, context); | ||||
|  | ||||
|         foreach (var class_symbol in candidate_classes.Distinct(SymbolEqualityComparer.Default).Cast<INamedTypeSymbol>()) | ||||
|         { | ||||
|             GenerateSetParametersAsyncMethod(context, class_symbol); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void GenerateSetParametersAsyncMethod(GeneratorExecutionContext context, INamedTypeSymbol class_symbol) | ||||
|     private static void GenerateSetParametersAsyncMethod(SourceProductionContext context, INamedTypeSymbol class_symbol) | ||||
|     { | ||||
|         var force_exact_match = class_symbol.GetAttributes().Any(a => a.NamedArguments.Any(na => na.Key == "RequireExactMatch" && na.Value.Value is bool v && v)); | ||||
|         var namespaceName = class_symbol.ContainingNamespace.ToDisplayString(); | ||||
| @@ -386,6 +399,31 @@ namespace {namespaceName} | ||||
| #pragma warning restore CS0162"); | ||||
|     } | ||||
|  | ||||
|     private static bool IsPartial(INamedTypeSymbol symbol) | ||||
|     { | ||||
|         return symbol.DeclaringSyntaxReferences | ||||
|             .Select(r => r.GetSyntax()) | ||||
|             .OfType<ClassDeclarationSyntax>() | ||||
|             .Any(c => c.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))); | ||||
|     } | ||||
|  | ||||
|     private static bool IsComponent(ClassDeclarationSyntax classDeclaration, INamedTypeSymbol symbol, Compilation compilation) | ||||
|     { | ||||
|         if (HasUserDefinedSetParametersAsync(symbol)) | ||||
|             return false; | ||||
|  | ||||
|         if (classDeclaration.SyntaxTree.FilePath.EndsWith(".razor") || classDeclaration.SyntaxTree.FilePath.EndsWith(".razor.cs")) | ||||
|             return true; | ||||
|  | ||||
|         var iComponent = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.IComponent"); | ||||
|         var componentBase = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.ComponentBase"); | ||||
|  | ||||
|         if (iComponent == null || componentBase == null) | ||||
|             return false; | ||||
|  | ||||
|         return symbol.AllInterfaces.Contains(iComponent) || SymbolEqualityComparer.Default.Equals(symbol.BaseType, componentBase); | ||||
|     } | ||||
|  | ||||
|     private static bool HasUserDefinedSetParametersAsync(INamedTypeSymbol classSymbol) | ||||
|     { | ||||
|         return classSymbol | ||||
| @@ -398,137 +436,4 @@ namespace {namespaceName} | ||||
|                 !m.IsStatic); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private static bool IsPartial(INamedTypeSymbol symbol) | ||||
|     { | ||||
|         return symbol.DeclaringSyntaxReferences | ||||
|             .Select(r => r.GetSyntax()) | ||||
|             .OfType<ClassDeclarationSyntax>() | ||||
|             .Any(c => c.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))); | ||||
|     } | ||||
|     private static bool IsComponent(ClassDeclarationSyntax classDeclarationSyntax, INamedTypeSymbol symbol, Compilation compilation) | ||||
|     { | ||||
|         if (HasUserDefinedSetParametersAsync(symbol)) | ||||
|         { | ||||
|             // 用户自己写了方法,不生成 | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (!IsPartial(symbol)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (classDeclarationSyntax.SyntaxTree.FilePath.EndsWith(".razor") || classDeclarationSyntax.SyntaxTree.FilePath.EndsWith(".razor.cs")) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         var iComponent = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.IComponent"); | ||||
|         var componentBase = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.ComponentBase"); | ||||
|         if (iComponent == null || componentBase == null) | ||||
|             return false; | ||||
|  | ||||
|         if (SymbolEqualityComparer.Default.Equals(symbol, iComponent)) | ||||
|             return true; | ||||
|         if (SymbolEqualityComparer.Default.Equals(symbol, componentBase)) | ||||
|             return true; | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Enumerate methods with at least one Group attribute | ||||
|     /// </summary> | ||||
|     private static IEnumerable<INamedTypeSymbol> GetCandidateClasses(SyntaxReceiver receiver, GeneratorExecutionContext context) | ||||
|     { | ||||
|         var compilation = context.Compilation; | ||||
|         var positiveAttributeSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.GenerateSetParametersAsyncAttribute"); | ||||
|         var negativeAttributeSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.DoNotGenerateSetParametersAsyncAttribute"); | ||||
|  | ||||
|         // loop over the candidate methods, and keep the ones that are actually annotated | ||||
|  | ||||
|         // 找特性 | ||||
|         var assemblyAttributes = compilation.Assembly.GetAttributes(); | ||||
|  | ||||
|         var enableAttr = assemblyAttributes.FirstOrDefault(attr => | ||||
|             attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.GlobalGenerateSetParametersAsyncAttribute"); | ||||
|  | ||||
|         var globalEnable = false; | ||||
|         if (enableAttr != null) | ||||
|         { | ||||
|             var arg = enableAttr.ConstructorArguments.FirstOrDefault(); | ||||
|             if (arg.Value is bool b) | ||||
|                 globalEnable = b; | ||||
|         } | ||||
|  | ||||
|         foreach (ClassDeclarationSyntax class_declaration in receiver.CandidateClasses) | ||||
|         { | ||||
|             var model = compilation.GetSemanticModel(class_declaration.SyntaxTree); | ||||
|             var class_symbol = model.GetDeclaredSymbol(class_declaration); | ||||
|             if (class_symbol is null) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|             if (class_symbol.Name == "_Imports") | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // 是否拒绝生成 | ||||
|             var hasNegative = class_symbol.GetAttributes().Any(ad => | ||||
|                 ad.AttributeClass?.Equals(negativeAttributeSymbol, SymbolEqualityComparer.Default) == true); | ||||
|  | ||||
|             if (hasNegative) | ||||
|                 continue; | ||||
|  | ||||
|  | ||||
|             if (IsComponent(class_declaration, class_symbol, compilation)) | ||||
|             { | ||||
|                 if (globalEnable) | ||||
|                 { | ||||
|                     yield return class_symbol; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // 必须显式标注 Positive Attribute | ||||
|                     var hasPositive = class_symbol.GetAttributes().Any(ad => | ||||
|                         ad.AttributeClass?.Equals(positiveAttributeSymbol, SymbolEqualityComparer.Default) == true); | ||||
|  | ||||
|                     if (hasPositive) | ||||
|                         yield return class_symbol; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|  | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Created on demand before each generation pass | ||||
|     /// </summary> | ||||
|     internal class SyntaxReceiver : ISyntaxReceiver | ||||
|     { | ||||
|         public List<ClassDeclarationSyntax> CandidateClasses { get; } = new List<ClassDeclarationSyntax>(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation | ||||
|         /// </summary> | ||||
|         public void OnVisitSyntaxNode(SyntaxNode syntax_node) | ||||
|         { | ||||
|             // any class with at least one attribute is a candidate for property generation | ||||
|             if (syntax_node is ClassDeclarationSyntax classDeclarationSyntax) | ||||
|             { | ||||
|                 CandidateClasses.Add(classDeclarationSyntax); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|  | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Components | ||||
| { | ||||
|     internal static class SourceGeneratorContextExtension | ||||
|     { | ||||
|         public static void AddCode(this GeneratorExecutionContext context, string hint_name, string code) | ||||
|         public static void AddCode(this SourceProductionContext context, string hint_name, string code) | ||||
|         { | ||||
|             context.AddSource(hint_name.Replace("<", "_").Replace(">", "_"), SourceText.From(code, Encoding.UTF8)); | ||||
|         } | ||||
|   | ||||
| @@ -1,13 +0,0 @@ | ||||
| using Microsoft.CodeAnalysis; | ||||
| using Microsoft.CodeAnalysis.CSharp; | ||||
|  | ||||
| namespace Microsoft.AspNetCore.Components | ||||
| { | ||||
|     internal static class StringExtension | ||||
|     { | ||||
|         public static string NormalizeWhitespace(this string code) | ||||
|         { | ||||
|             return CSharpSyntaxTree.ParseText(code).GetRoot().NormalizeWhitespace().ToFullString(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
|  | ||||
| @@ -41,9 +39,9 @@ public class OpenApiController : ControllerBase | ||||
|     [AllowAnonymous] | ||||
|     public async Task<OpenApiLoginOutput> LoginAsync([FromBody] OpenApiLoginInput input) | ||||
|     { | ||||
|         var output = await _authService.LoginAsync(input.Adapt<LoginInput>(), false).ConfigureAwait(false); | ||||
|         var output = await _authService.LoginAsync(input.AdaptLoginInput(), false).ConfigureAwait(false); | ||||
|  | ||||
|         var openApiLoginOutput = output.Adapt<OpenApiLoginOutput>(); | ||||
|         var openApiLoginOutput = output.AdaptOpenApiLoginOutput(); | ||||
|  | ||||
|         return openApiLoginOutput; | ||||
|     } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
| @@ -31,7 +31,7 @@ public class SysUser : BaseEntity | ||||
|     ///</summary> | ||||
|     [SugarColumn(ColumnDescription = "头像", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] | ||||
|     [AutoGenerateColumn(Visible = true, Sortable = false, Filterable = false)] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     public virtual string? Avatar { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://thingsgateway.cn/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Application; | ||||
| [Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)] | ||||
| public static partial class AdminMapper | ||||
| { | ||||
|     public static partial LoginInput AdaptLoginInput(this OpenApiLoginInput src); | ||||
|     public static partial OpenApiLoginOutput AdaptOpenApiLoginOutput(this LoginOutput src); | ||||
|     public static partial SessionOutput AdaptSessionOutput(this SysUser src); | ||||
|     public static partial SysUser AdaptSysUser(this SysUser src); | ||||
|     public static partial UserSelectorOutput AdaptUserSelectorOutput(this SysUser src); | ||||
|     public static partial List<SysResource> AdaptListSysResource(this IEnumerable<SysResource> src); | ||||
|     public static partial AppConfig AdaptAppConfig(this AppConfig src); | ||||
|     public static partial WorkbenchInfo AdaptWorkbenchInfo(this WorkbenchInfo src); | ||||
|     public static partial QueryData<UserSelectorOutput> AdaptQueryDataUserSelectorOutput(this QueryData<SysUser> src); | ||||
|     public static partial LoginInput AdaptLoginInput(this LoginInput src); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.SqlSugar; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Application; | ||||
| @@ -69,7 +67,7 @@ internal sealed class SessionService : BaseService<SysUser>, ISessionService | ||||
|  | ||||
|             var r = items.Select((it) => | ||||
|             { | ||||
|                 var reuslt = it.Adapt<SessionOutput>(); | ||||
|                 var reuslt = it.AdaptSessionOutput(); | ||||
|                 if (verificatInfoDicts.TryGetValue(it.Id, out var verificatInfos)) | ||||
|                 { | ||||
|                     reuslt.VerificatCount = verificatInfos.Count;//令牌数量 | ||||
| @@ -94,7 +92,7 @@ internal sealed class SessionService : BaseService<SysUser>, ISessionService | ||||
|  | ||||
|             var r = items.Select((it) => | ||||
|             { | ||||
|                 var reuslt = it.Adapt<SessionOutput>(); | ||||
|                 var reuslt = it.AdaptSessionOutput(); | ||||
|                 if (verificatInfoDicts.TryGetValue(it.Id, out var verificatInfos)) | ||||
|                 { | ||||
|                     reuslt.VerificatCount = verificatInfos.Count;//令牌数量 | ||||
| @@ -117,7 +115,7 @@ internal sealed class SessionService : BaseService<SysUser>, ISessionService | ||||
|  | ||||
|             var r = items.Select((it) => | ||||
|             { | ||||
|                 var reuslt = it.Adapt<SessionOutput>(); | ||||
|                 var reuslt = it.AdaptSessionOutput(); | ||||
|                 if (verificatInfoDicts.TryGetValue(it.Id, out var verificatInfos)) | ||||
|                 { | ||||
|                     reuslt.VerificatCount = verificatInfos.Count;//令牌数量 | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.DataEncryption; | ||||
| using ThingsGateway.Extension; | ||||
| using ThingsGateway.Extension.Generic; | ||||
| @@ -452,7 +450,7 @@ internal sealed class SysUserService : BaseService<SysUser>, ISysUserService | ||||
|  | ||||
|         if (changedType == ItemChangedType.Add) | ||||
|         { | ||||
|             var sysUser = input.Adapt<SysUser>(); | ||||
|             var sysUser = input.AdaptSysUser(); | ||||
|             //获取默认密码 | ||||
|             sysUser.Avatar = input.Avatar; | ||||
|             sysUser.Password = await GetDefaultPassWord(true).ConfigureAwait(false);//设置密码 | ||||
| @@ -872,7 +870,7 @@ internal sealed class SysUserService : BaseService<SysUser>, ISysUserService | ||||
|             sysUser.OrgAndPosIdList.AddRange(sysUser.OrgId, sysUser.PositionId ?? 0);//添加组织和职位Id | ||||
|             if (sysUser.DirectorId != null) | ||||
|             { | ||||
|                 sysUser.DirectorInfo = (await GetUserByIdAsync(sysUser.DirectorId.Value).ConfigureAwait(false)).Adapt<UserSelectorOutput>();//获取主管信息 | ||||
|                 sysUser.DirectorInfo = (await GetUserByIdAsync(sysUser.DirectorId.Value).ConfigureAwait(false)).AdaptUserSelectorOutput();//获取主管信息 | ||||
|             } | ||||
|  | ||||
|             //获取按钮码 | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" /> | ||||
| 		<PackageReference Include="Rougamo.Fody" Version="5.0.1" /> | ||||
| 	</ItemGroup> | ||||
| 	<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| using ThingsGateway.NewLife; | ||||
| using ThingsGateway.NewLife.Extension; | ||||
| @@ -88,7 +86,7 @@ public class BlazorAppContext | ||||
|         if (UserManager.UserId > 0) | ||||
|         { | ||||
|             url = url.StartsWith('/') ? url : $"/{url}"; | ||||
|             var sysResources = (await ResourceService.GetAllAsync()).Adapt<List<SysResource>>(); | ||||
|             var sysResources = (await ResourceService.GetAllAsync()).AdaptListSysResource(); | ||||
|             if (TitleLocalizer != null) | ||||
|             { | ||||
|                 sysResources.ForEach(a => | ||||
| @@ -121,7 +119,7 @@ public class BlazorAppContext | ||||
|                 CurrentModuleId = moduleId.Value; | ||||
|             } | ||||
|             UserWorkBench = await UserCenterService.GetLoginWorkbenchAsync(UserManager.UserId); | ||||
|             OwnMenus = (await UserCenterService.GetOwnMenuAsync(UserManager.UserId, 0)).Adapt<List<SysResource>>(); | ||||
|             OwnMenus = (await UserCenterService.GetOwnMenuAsync(UserManager.UserId, 0)).AdaptListSysResource(); | ||||
|  | ||||
|             if (TitleLocalizer != null) | ||||
|             { | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| @@ -30,7 +28,7 @@ public partial class AppConfigPage | ||||
|  | ||||
|     protected override async Task OnParametersSetAsync() | ||||
|     { | ||||
|         AppConfig = (await SysDictService.GetAppConfigAsync()).Adapt<AppConfig>(); | ||||
|         AppConfig = (await SysDictService.GetAppConfigAsync()).AdaptAppConfig(); | ||||
|         await base.OnParametersSetAsync(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Razor; | ||||
| @@ -47,10 +45,7 @@ public partial class RoleChoiceDialog | ||||
|     private ISysRoleService? SysRoleService { get; set; } | ||||
|     private async Task<QueryData<SysRole>> OnQueryAsync(QueryPageOptions options) | ||||
|     { | ||||
|         var data = await SysRoleService.PageAsync(options, a => a.Where(b => b.OrgId == OrgId)); | ||||
|         QueryData<SysRole> queryData = data.Adapt<QueryData<SysRole>>(); | ||||
|  | ||||
|         return queryData; | ||||
|         return await SysRoleService.PageAsync(options, a => a.Where(b => b.OrgId == OrgId)); | ||||
|     } | ||||
|     #region 查询 | ||||
|     private long OrgId { get; set; } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Razor; | ||||
| @@ -56,7 +54,7 @@ public partial class UserChoiceDialog | ||||
|             OrgId = OrgId, | ||||
|             PositionId = PositionId, | ||||
|         }); | ||||
|         QueryData<UserSelectorOutput> queryData = data.Adapt<QueryData<UserSelectorOutput>>(); | ||||
|         QueryData<UserSelectorOutput> queryData = data.AdaptQueryDataUserSelectorOutput(); | ||||
|  | ||||
|         return queryData; | ||||
|     } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| @@ -37,9 +35,9 @@ public partial class UserCenterPage | ||||
|  | ||||
|     protected override async Task OnParametersSetAsync() | ||||
|     { | ||||
|         SysUser = AppContext.CurrentUser.Adapt<SysUser>(); | ||||
|         SysUser = AppContext.CurrentUser.AdaptSysUser(); | ||||
|         SysUser.Avatar = AppContext.Avatar; | ||||
|         WorkbenchInfo = (await UserCenterService.GetLoginWorkbenchAsync(SysUser.Id)).Adapt<WorkbenchInfo>(); | ||||
|         WorkbenchInfo = (await UserCenterService.GetLoginWorkbenchAsync(SysUser.Id)).AdaptWorkbenchInfo(); | ||||
|  | ||||
|         await base.OnParametersSetAsync(); | ||||
|     } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Razor; | ||||
| @@ -122,31 +120,4 @@ public static class ResourceUtil | ||||
|         return trees; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 构建树节点 | ||||
|     /// </summary> | ||||
|     public static List<TreeViewItem<T>> BuildTreeItemList<T>(IEnumerable<SysResource> sysresources, List<long> selectedItems, Microsoft.AspNetCore.Components.RenderFragment<T> render, long parentId = 0, TreeViewItem<T>? parent = null, Func<SysResource, bool> disableFunc = null) where T : class | ||||
|     { | ||||
|         if (sysresources == null) return null; | ||||
|         var trees = new List<TreeViewItem<T>>(); | ||||
|         var roots = sysresources.Where(i => i.ParentId == parentId).OrderBy(i => i.SortCode); | ||||
|         foreach (var node in roots) | ||||
|         { | ||||
|             var item = new TreeViewItem<T>(node.Adapt<T>()) | ||||
|             { | ||||
|                 Text = node.Title, | ||||
|                 Icon = node.Icon, | ||||
|                 IsDisabled = disableFunc == null ? false : disableFunc(node), | ||||
|                 IsActive = selectedItems.Any(v => node.Id == v), | ||||
|                 IsExpand = true, | ||||
|                 Parent = parent, | ||||
|                 Template = render, | ||||
|                 CheckedState = selectedItems.Any(i => i == node.Id) ? CheckboxState.Checked : CheckboxState.UnChecked | ||||
|             }; | ||||
|             item.Items = BuildTreeItemList(sysresources, selectedItems, render, node.Id, item, disableFunc) ?? new(); | ||||
|             trees.Add(item); | ||||
|         } | ||||
|         return trees; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -11,8 +11,6 @@ | ||||
| #pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.Extensions.Localization; | ||||
| @@ -71,7 +69,7 @@ public partial class Login | ||||
|  | ||||
|     private async Task LoginAsync(EditContext context) | ||||
|     { | ||||
|         var model = loginModel.Adapt<LoginInput>(); | ||||
|         var model = loginModel.AdaptLoginInput(); | ||||
|         model.Password = DESEncryption.Encrypt(model.Password); | ||||
|         try | ||||
|         { | ||||
|   | ||||
| @@ -45,9 +45,7 @@ | ||||
| 		</Content> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<!--安装服务守护--> | ||||
| 	<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> | ||||
|  | ||||
|   | ||||
| @@ -11,8 +11,6 @@ | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using MiniExcelLibs; | ||||
| using MiniExcelLibs.Attributes; | ||||
| using MiniExcelLibs.OpenXml; | ||||
|   | ||||
| @@ -210,7 +210,7 @@ public static class AppServiceCollectionExtensions | ||||
|         services.AddStartups(); | ||||
|  | ||||
|         // 添加对象映射 | ||||
|         services.AddObjectMapper(); | ||||
|         //services.AddObjectMapper(); | ||||
|  | ||||
|         // 默认内置 GBK,Windows-1252, Shift-JIS, GB2312 编码支持 | ||||
|         Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); | ||||
|   | ||||
| @@ -1,59 +1,59 @@ | ||||
| // ------------------------------------------------------------------------ | ||||
| // 版权信息 | ||||
| // 版权归百小僧及百签科技(广东)有限公司所有。 | ||||
| // 所有权利保留。 | ||||
| // 官方网站:https://baiqian.com | ||||
| // | ||||
| // 许可证信息 | ||||
| // 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。 | ||||
| // 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 | ||||
| // ------------------------------------------------------------------------ | ||||
| //// ------------------------------------------------------------------------ | ||||
| //// 版权信息 | ||||
| //// 版权归百小僧及百签科技(广东)有限公司所有。 | ||||
| //// 所有权利保留。 | ||||
| //// 官方网站:https://baiqian.com | ||||
| //// | ||||
| //// 许可证信息 | ||||
| //// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。 | ||||
| //// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。 | ||||
| //// ------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
| //using Mapster; | ||||
|  | ||||
| using System.Reflection; | ||||
| //using System.Reflection; | ||||
|  | ||||
| using ThingsGateway; | ||||
| //using ThingsGateway; | ||||
|  | ||||
| namespace Microsoft.Extensions.DependencyInjection; | ||||
| //namespace Microsoft.Extensions.DependencyInjection; | ||||
|  | ||||
| /// <summary> | ||||
| /// 对象映射拓展类 | ||||
| /// </summary> | ||||
| [SuppressSniffer] | ||||
| public static class ObjectMapperServiceCollectionExtensions | ||||
| { | ||||
| ///// <summary> | ||||
| ///// 对象映射拓展类 | ||||
| ///// </summary> | ||||
| //[SuppressSniffer] | ||||
| //public static class ObjectMapperServiceCollectionExtensions | ||||
| //{ | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 添加对象映射 | ||||
|     /// </summary> | ||||
|     /// <param name="services">服务集合</param> | ||||
|     /// <returns></returns> | ||||
|     public static IServiceCollection AddObjectMapper(this IServiceCollection services) | ||||
|     { | ||||
|         // 判断是否安装了 Mapster 程序集 | ||||
|         return services.AddObjectMapper(App.Assemblies.ToArray()); | ||||
|     } | ||||
| //    /// <summary> | ||||
| //    /// 添加对象映射 | ||||
| //    /// </summary> | ||||
| //    /// <param name="services">服务集合</param> | ||||
| //    /// <returns></returns> | ||||
| //    public static IServiceCollection AddObjectMapper(this IServiceCollection services) | ||||
| //    { | ||||
| //        // 判断是否安装了 Mapster 程序集 | ||||
| //        return services.AddObjectMapper(App.Assemblies.ToArray()); | ||||
| //    } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 添加对象映射 | ||||
|     /// </summary> | ||||
|     /// <param name="services">服务集合</param> | ||||
|     /// <param name="assemblies">扫描的程序集</param> | ||||
|     /// <returns></returns> | ||||
|     public static IServiceCollection AddObjectMapper(this IServiceCollection services, params Assembly[] assemblies) | ||||
|     { | ||||
|         // 获取全局映射配置 | ||||
|         var config = TypeAdapterConfig.GlobalSettings; | ||||
| //    /// <summary> | ||||
| //    /// 添加对象映射 | ||||
| //    /// </summary> | ||||
| //    /// <param name="services">服务集合</param> | ||||
| //    /// <param name="assemblies">扫描的程序集</param> | ||||
| //    /// <returns></returns> | ||||
| //    public static IServiceCollection AddObjectMapper(this IServiceCollection services, params Assembly[] assemblies) | ||||
| //    { | ||||
| //        // 获取全局映射配置 | ||||
| //        var config = TypeAdapterConfig.GlobalSettings; | ||||
|  | ||||
|         //config.Compiler = exp => exp.CompileFast(); | ||||
| //        //config.Compiler = exp => exp.CompileFast(); | ||||
|  | ||||
|         // 扫描所有继承  IRegister 接口的对象映射配置 | ||||
|         if (assemblies?.Length > 0) config.Scan(assemblies); | ||||
| //        // 扫描所有继承  IRegister 接口的对象映射配置 | ||||
| //        if (assemblies?.Length > 0) config.Scan(assemblies); | ||||
|  | ||||
|         // 配置支持依赖注入 | ||||
|         services.AddSingleton(config); | ||||
| //        // 配置支持依赖注入 | ||||
| //        services.AddSingleton(config); | ||||
|  | ||||
|         return services; | ||||
|     } | ||||
| } | ||||
| //        return services; | ||||
| //    } | ||||
| //} | ||||
|   | ||||
| @@ -36,7 +36,7 @@ | ||||
| 		<PackageReference Include="Ben.Demystifier" Version="0.4.1" /> | ||||
| 		<!--<PackageReference Include="FastExpressionCompiler" Version="5.3.0" />--> | ||||
| 		<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" /> | ||||
| 		<PackageReference Include="Mapster" Version="7.4.0" /> | ||||
| 		<!--<PackageReference Include="Mapster" Version="7.4.0" />--> | ||||
| 		<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" /> | ||||
| 		<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" /> | ||||
| 	</ItemGroup> | ||||
|   | ||||
| @@ -1,30 +1,30 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://thingsgateway.cn/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| ////------------------------------------------------------------------------------ | ||||
| ////  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| ////  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| ////  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| ////  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| ////  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| ////  使用文档:https://thingsgateway.cn/ | ||||
| ////  QQ群:605534569 | ||||
| ////------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
| //using Mapster; | ||||
|  | ||||
| using System.Text; | ||||
| //using System.Text; | ||||
|  | ||||
| namespace ThingsGateway.Razor; | ||||
| //namespace ThingsGateway.Razor; | ||||
|  | ||||
| /// <summary> | ||||
| /// <see cref="Encoding"/> Master规则 | ||||
| /// </summary> | ||||
| public class EncodingMapper : IRegister | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public void Register(TypeAdapterConfig config) | ||||
|     { | ||||
|         config.ForType<Encoding, Encoding>() | ||||
|             .Ignore(dest => dest.EncoderFallback) | ||||
|             .Ignore(dest => dest.DecoderFallback) | ||||
|               .ConstructUsing(src => Encoding.GetEncoding(src.CodePage)); | ||||
|     } | ||||
| } | ||||
| ///// <summary> | ||||
| ///// <see cref="Encoding"/> Master规则 | ||||
| ///// </summary> | ||||
| //public class EncodingMapper : IRegister | ||||
| //{ | ||||
| //    /// <inheritdoc/> | ||||
| //    public void Register(TypeAdapterConfig config) | ||||
| //    { | ||||
| //        config.ForType<Encoding, Encoding>() | ||||
| //            .Ignore(dest => dest.EncoderFallback) | ||||
| //            .Ignore(dest => dest.DecoderFallback) | ||||
| //              .ConstructUsing(src => Encoding.GetEncoding(src.CodePage)); | ||||
| //    } | ||||
| //} | ||||
|   | ||||
| @@ -35,7 +35,10 @@ | ||||
| 	</ItemGroup>--> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<ProjectReference Include="..\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" /> | ||||
| 		<ProjectReference Include="..\BlazorSetParametersAsyncGenerator\BlazorSetParametersAsyncGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer"> | ||||
| 			<ExcludeAssets>all</ExcludeAssets> | ||||
| 			<IncludeAssets>Analyzer</IncludeAssets> | ||||
| 		</ProjectReference> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| </Project> | ||||
|   | ||||
| @@ -73,7 +73,7 @@ namespace TDengineAdo | ||||
|  | ||||
|         protected override void Dispose(bool disposing) | ||||
|         { | ||||
|             connection.Dispose(); | ||||
|             connection?.Dispose(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,8 @@ | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="SqlSugarCore.Dm" Version="8.8.0" /> | ||||
| 		<PackageReference Include="SqlSugarCore.Kdbndp" Version="9.3.7.613" /> | ||||
| 		<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" /> | ||||
| 		<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.20" /> | ||||
| 		<!--<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" />--> | ||||
| 		<PackageReference Include="MySqlConnector" Version="2.4.0" /> | ||||
| 		<PackageReference Include="Npgsql" Version="9.0.3" /> | ||||
| 		<PackageReference Include="CsvHelper" Version="33.1.0" /> | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| <Project> | ||||
|  | ||||
| 	<PropertyGroup> | ||||
| 		<PluginVersion>10.9.1</PluginVersion> | ||||
| 		<ProPluginVersion>10.9.1</ProPluginVersion> | ||||
| 		<AuthenticationVersion>2.9.0</AuthenticationVersion> | ||||
| 		<SourceGeneratorVersion>10.9.1</SourceGeneratorVersion> | ||||
| 		<PluginVersion>10.9.4</PluginVersion> | ||||
| 		<ProPluginVersion>10.9.4</ProPluginVersion> | ||||
| 		<AuthenticationVersion>2.9.4</AuthenticationVersion> | ||||
| 		<SourceGeneratorVersion>10.9.4</SourceGeneratorVersion> | ||||
| 		<NET8Version>8.0.17</NET8Version> | ||||
| 		<NET9Version>9.0.6</NET9Version> | ||||
| 		<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages> | ||||
| @@ -26,7 +26,7 @@ | ||||
| 		<AnalysisModeStyle>None</AnalysisModeStyle> | ||||
|  | ||||
| 		<NoWarn> | ||||
| 			CS8603;CS8618;CS1591;CS8625;CS8602;CS8604;CS8600;CS8601;CS8714;CS8619;CS8629;CS8765;CS8634;CS8621;CS8767;CS8633;CS8620;CS8610;CS8631;CS8605;CS8622;CS8613;NU5100;NU5104;NU1903;NU1902;CA1813;CA1852;CA1822;CA2100;CA2008;CA1812;CA1508;CA1512;CA1513;CA1810;CA1814;CA1815;CA1835;CA1819;CA1823;CA2002;CA5350;CA5351;CA5358;CA5384;CA5392;CA1805;CA1851;CA1510;CA5401;CA2022;CA1848;CA2000;CA5394;CA3003;CA1515;CA1849;CA1863;CA5400 | ||||
| 			CS8603;CS8618;CS1591;CS8625;CS8602;CS8604;CS8600;CS8601;CS8714;CS8619;CS8629;CS8765;CS8634;CS8621;CS8767;CS8633;CS8620;CS8610;CS8631;CS8605;CS8622;CS8613;NU5100;NU5104;NU1903;NU1902;CA1813;CA1852;CA1822;CA2100;CA2008;CA1812;CA1508;CA1512;CA1513;CA1810;CA1814;CA1815;CA1835;CA1819;CA1823;CA2002;CA5350;CA5351;CA5358;CA5384;CA5392;CA1805;CA1851;CA1510;CA5401;CA2022;CA1848;CA2000;CA5394;CA3003;CA1515;CA1849;CA1863;CA5400;NETSDK1206 | ||||
| 		</NoWarn> | ||||
| 		<TargetFrameworks>net8.0;</TargetFrameworks> | ||||
| 		<LangVersion>13.0</LangVersion> | ||||
|   | ||||
| @@ -104,7 +104,7 @@ internal sealed class VariableCodeBuilder | ||||
|  | ||||
|     private void BuildMethod(StringBuilder stringBuilder, IPropertySymbol propertySymbol) | ||||
|     { | ||||
|         var attributeData = propertySymbol.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == VariableSyntaxReceiver.VariableRuntimeAttributeTypeName); | ||||
|         var attributeData = propertySymbol.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == VariableObjectSyntaxFilter.VariableRuntimeAttributeTypeName); | ||||
|         stringBuilder.AppendLine(); | ||||
|         stringBuilder.AppendLine($"public ValueTask<OperResult> Write{propertySymbol.Name}Async({propertySymbol.Type} value,CancellationToken cancellationToken=default)"); | ||||
|         stringBuilder.AppendLine("{"); | ||||
| @@ -120,7 +120,7 @@ internal sealed class VariableCodeBuilder | ||||
|             .OfType<IPropertySymbol>() | ||||
|             .Where(m => | ||||
|             { | ||||
|                 return m.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == VariableSyntaxReceiver.VariableRuntimeAttributeTypeName); | ||||
|                 return m.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == VariableObjectSyntaxFilter.VariableRuntimeAttributeTypeName); | ||||
|             }); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,32 +8,23 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 | ||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 | ||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 | ||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home | ||||
| //  Github源代码仓库:https://github.com/RRQM | ||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ | ||||
| //  交流QQ群:234762506 | ||||
| //  感谢您的下载和使用 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| #if !NET45_OR_GREATER | ||||
|  | ||||
| using Microsoft.CodeAnalysis; | ||||
| using Microsoft.CodeAnalysis.CSharp; | ||||
| using Microsoft.CodeAnalysis.Text; | ||||
|  | ||||
| using System.Text; | ||||
|  | ||||
| namespace ThingsGateway.Foundation; | ||||
|  | ||||
| /// <summary> | ||||
| /// 源生成 | ||||
| /// 增量源生成器:VariableObject | ||||
| /// </summary> | ||||
| [Generator] | ||||
| public class VariableObjectSourceGenerator : ISourceGenerator | ||||
| public sealed class VariableObjectSourceGenerator : IIncrementalGenerator | ||||
| { | ||||
|     private string m_generatorVariableAttribute = @" | ||||
|     private const string AttributeSource = @" | ||||
| using System; | ||||
|  | ||||
| namespace ThingsGateway.Foundation | ||||
| @@ -46,43 +37,45 @@ namespace ThingsGateway.Foundation | ||||
|     { | ||||
|     } | ||||
| } | ||||
|  | ||||
| "; | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public void Initialize(GeneratorInitializationContext context) | ||||
|     public void Initialize(IncrementalGeneratorInitializationContext context) | ||||
|     { | ||||
|         //Debugger.Launch(); | ||||
|         context.RegisterForPostInitialization(a => | ||||
|         context.RegisterPostInitializationOutput(ctx => | ||||
|         { | ||||
|             a.AddSource(nameof(m_generatorVariableAttribute), m_generatorVariableAttribute); | ||||
|             ctx.AddSource("GeneratorVariableAttribute.g.cs", SourceText.From(AttributeSource, Encoding.UTF8)); | ||||
|         }); | ||||
|         context.RegisterForSyntaxNotifications(() => new VariableSyntaxReceiver()); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public void Execute(GeneratorExecutionContext context) | ||||
|     { | ||||
|         var s = context.Compilation.GetMetadataReference(context.Compilation.Assembly); | ||||
|         var variableObjectTypes = context.SyntaxProvider | ||||
|             .CreateSyntaxProvider( | ||||
|                 predicate: VariableObjectSyntaxFilter.IsCandidate, | ||||
|                 transform: VariableObjectSyntaxFilter.GetVariableObjectType) | ||||
|             .Where(static t => t is not null) | ||||
|             .Select(static (t, _) => (INamedTypeSymbol)t!)  // 明确转成 INamedTypeSymbol | ||||
|             .Collect(); | ||||
|  | ||||
|         if (context.SyntaxReceiver is VariableSyntaxReceiver receiver) | ||||
|  | ||||
|         var compilationAndTypes = context.CompilationProvider.Combine(variableObjectTypes); | ||||
|  | ||||
|         context.RegisterSourceOutput(compilationAndTypes, (spc, source) => | ||||
|         { | ||||
|             var builders = receiver | ||||
|                 .GetVariableObjectTypes(context.Compilation) | ||||
|                 .Select(i => new VariableCodeBuilder(i)) | ||||
|                 .Distinct(); | ||||
|             foreach (var builder in builders) | ||||
|             var (compilation, types) = source; | ||||
|  | ||||
|             foreach (var typeSymbol in types.ToList().Distinct(SymbolEqualityComparer.Default).OfType<INamedTypeSymbol>()) | ||||
|             { | ||||
|                 var builder = new VariableCodeBuilder(typeSymbol); | ||||
|                 if (builder.TryToSourceText(out var sourceText)) | ||||
|                 { | ||||
|                     var tree = CSharpSyntaxTree.ParseText(sourceText); | ||||
|                     var root = tree.GetRoot().NormalizeWhitespace(); | ||||
|                     var ret = root.ToFullString(); | ||||
|                     context.AddSource($"{builder.GetFileName()}.g.cs", ret); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|                     spc.AddSource($"{builder.GetFileName()}.g.cs", SourceText.From(ret, Encoding.UTF8)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -0,0 +1,52 @@ | ||||
| using Microsoft.CodeAnalysis; | ||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
|  | ||||
| internal static class VariableObjectSyntaxFilter | ||||
| { | ||||
|     public const string GeneratorVariableAttributeTypeName = "ThingsGateway.Foundation.GeneratorVariableAttribute"; | ||||
|     public const string VariableRuntimeAttributeTypeName = "ThingsGateway.Foundation.VariableRuntimeAttribute"; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 语法筛选器:只筛选 ClassDeclarationSyntax | ||||
|     /// </summary> | ||||
|     public static bool IsCandidate(SyntaxNode syntaxNode, CancellationToken _) | ||||
|     { | ||||
|         return syntaxNode is ClassDeclarationSyntax; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 语义分析:判断是否是带 GeneratorVariableAttribute 的类 | ||||
|     /// </summary> | ||||
|     public static INamedTypeSymbol? GetVariableObjectType(GeneratorSyntaxContext context, CancellationToken _) | ||||
|     { | ||||
|         var classSyntax = (ClassDeclarationSyntax)context.Node; | ||||
|         var classSymbol = context.SemanticModel.GetDeclaredSymbol(classSyntax) as INamedTypeSymbol; | ||||
|         if (classSymbol == null) | ||||
|             return null; | ||||
|  | ||||
|         if (classSymbol.IsAbstract) | ||||
|             return null; | ||||
|  | ||||
|         var generatorAttr = context.SemanticModel.Compilation.GetTypeByMetadataName(GeneratorVariableAttributeTypeName); | ||||
|         if (generatorAttr == null) | ||||
|             return null; | ||||
|  | ||||
|         if (HasAttribute(classSymbol, generatorAttr)) | ||||
|             return classSymbol; | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 判断 symbol 是否声明了指定 Attribute | ||||
|     /// </summary> | ||||
|     public static bool HasAttribute(INamedTypeSymbol symbol, INamedTypeSymbol attributeSymbol) | ||||
|     { | ||||
|         foreach (var attr in symbol.GetAttributes()) | ||||
|         { | ||||
|             if (SymbolEqualityComparer.Default.Equals(attr.AttributeClass, attributeSymbol)) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -1,116 +0,0 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://thingsgateway.cn/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 | ||||
| //  CSDN博客:https://blog.csdn.net/qq_40374647 | ||||
| //  哔哩哔哩视频:https://space.bilibili.com/94253567 | ||||
| //  Gitee源代码仓库:https://gitee.com/RRQM_Home | ||||
| //  Github源代码仓库:https://github.com/RRQM | ||||
| //  API首页:http://rrqm_home.gitee.io/touchsocket/ | ||||
| //  交流QQ群:234762506 | ||||
| //  感谢您的下载和使用 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| #if !NET45_OR_GREATER | ||||
|  | ||||
| using Microsoft.CodeAnalysis; | ||||
| using Microsoft.CodeAnalysis.CSharp; | ||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
|  | ||||
| namespace ThingsGateway.Foundation; | ||||
|  | ||||
| internal sealed class VariableSyntaxReceiver : ISyntaxReceiver | ||||
| { | ||||
|     public const string GeneratorVariableAttributeTypeName = "ThingsGateway.Foundation.GeneratorVariableAttribute"; | ||||
|     public const string VariableRuntimeAttributeTypeName = "ThingsGateway.Foundation.VariableRuntimeAttribute"; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 接口列表 | ||||
|     /// </summary> | ||||
|     private readonly List<ClassDeclarationSyntax> m_classSyntaxList = new List<ClassDeclarationSyntax>(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 访问语法树 | ||||
|     /// </summary> | ||||
|     /// <param name="syntaxNode"></param> | ||||
|     void ISyntaxReceiver.OnVisitSyntaxNode(SyntaxNode syntaxNode) | ||||
|     { | ||||
|         if (syntaxNode is ClassDeclarationSyntax syntax) | ||||
|         { | ||||
|             m_classSyntaxList.Add(syntax); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public INamedTypeSymbol GeneratorVariableAttributeAttribute { get; private set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取所有插件符号 | ||||
|     /// </summary> | ||||
|     /// <param name="compilation"></param> | ||||
|     /// <returns></returns> | ||||
|     public IEnumerable<INamedTypeSymbol> GetVariableObjectTypes(Compilation compilation) | ||||
|     { | ||||
|         GeneratorVariableAttributeAttribute = compilation.GetTypeByMetadataName(GeneratorVariableAttributeTypeName)!; | ||||
|         if (GeneratorVariableAttributeAttribute == null) | ||||
|         { | ||||
|             yield break; | ||||
|         } | ||||
|         foreach (var classSyntax in m_classSyntaxList) | ||||
|         { | ||||
|             var @class = compilation.GetSemanticModel(classSyntax.SyntaxTree).GetDeclaredSymbol(classSyntax); | ||||
|             if (@class != null && IsVariableObject(@class)) | ||||
|             { | ||||
|                 yield return @class; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 是否为变量类 | ||||
|     /// </summary> | ||||
|     /// <param name="class"></param> | ||||
|     /// <returns></returns> | ||||
|     public bool IsVariableObject(INamedTypeSymbol @class) | ||||
|     { | ||||
|         if (GeneratorVariableAttributeAttribute is null) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (@class.IsAbstract) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         return HasAttribute(@class, GeneratorVariableAttributeAttribute); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 返回是否声明指定的特性 | ||||
|     /// </summary> | ||||
|     /// <param name="symbol"></param> | ||||
|     /// <param name="attribute"></param> | ||||
|     /// <returns></returns> | ||||
|     public static bool HasAttribute(ISymbol symbol, INamedTypeSymbol attribute) | ||||
|     { | ||||
|         foreach (var attr in symbol.GetAttributes()) | ||||
|         { | ||||
|             var attrClass = attr.AttributeClass; | ||||
|             if (attrClass != null && (attrClass.AllInterfaces.Contains(attribute) || SymbolEqualityComparer.Default.Equals(attrClass, attribute))) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #endif | ||||
| @@ -8,6 +8,6 @@ | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" /> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" /> | ||||
| 	</ItemGroup> | ||||
| </Project> | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| @@ -153,7 +151,7 @@ public class ControlController : ControllerBase | ||||
|     [DisplayName("保存通道")] | ||||
|     public Task<bool> BatchSaveChannelAsync([FromBody] List<ChannelInput> channels, ItemChangedType type, bool restart) | ||||
|     { | ||||
|         return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.Adapt<List<Channel>>(), type, restart); | ||||
|         return GlobalData.ChannelRuntimeService.BatchSaveChannelAsync(channels.AdaptListChannel(), type, restart); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -163,7 +161,7 @@ public class ControlController : ControllerBase | ||||
|     [DisplayName("保存设备")] | ||||
|     public Task<bool> BatchSaveDeviceAsync([FromBody] List<DeviceInput> devices, ItemChangedType type, bool restart) | ||||
|     { | ||||
|         return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.Adapt<List<Device>>(), type, restart); | ||||
|         return GlobalData.DeviceRuntimeService.BatchSaveDeviceAsync(devices.AdaptListDevice(), type, restart); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -173,7 +171,7 @@ public class ControlController : ControllerBase | ||||
|     [DisplayName("保存变量")] | ||||
|     public Task<bool> BatchSaveVariableAsync([FromBody] List<VariableInput> variables, ItemChangedType type, bool restart) | ||||
|     { | ||||
|         return GlobalData.VariableRuntimeService.BatchSaveVariableAsync(variables.Adapt<List<Variable>>(), type, restart, default); | ||||
|         return GlobalData.VariableRuntimeService.BatchSaveVariableAsync(variables.AdaptListVariable(), type, restart, default); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
| @@ -79,12 +77,12 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel | ||||
|         CollectDevices?.ForEach(a => | ||||
|         { | ||||
|             if (a.Value.DeviceStatus == DeviceStatusEnum.OnLine && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                 DeviceStatusChange(a.Value, a.Value.Adapt<DeviceBasicData>()); | ||||
|                 DeviceStatusChange(a.Value, a.Value.AdaptDeviceBasicData()); | ||||
|         }); | ||||
|         IdVariableRuntimes.ForEach(a => | ||||
|         { | ||||
|             if (a.Value.IsOnline && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                 VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                 VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -153,7 +151,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel | ||||
|                     LogMessage?.LogDebug($"Interval {typeof(VarModel).Name} data, count {IdVariableRuntimes.Count}"); | ||||
|                 // 间隔推送全部变量 | ||||
|                 var variableRuntimes = IdVariableRuntimes.Select(a => a.Value); | ||||
|                 VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>()); | ||||
|                 VariableTimeInterval(variableRuntimes, variableRuntimes.AdaptIEnumerableVariableBasicData()); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
| @@ -169,7 +167,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel | ||||
|                     // 间隔推送全部设备 | ||||
|                     foreach (var deviceRuntime in CollectDevices.Select(a => a.Value)) | ||||
|                     { | ||||
|                         DeviceTimeInterval(deviceRuntime, deviceRuntime.Adapt<DeviceBasicData>()); | ||||
|                         DeviceTimeInterval(deviceRuntime, deviceRuntime.AdaptDeviceBasicData()); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -202,7 +200,7 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel | ||||
|     /// </summary> | ||||
|     /// <param name="variableRuntimes">变量运行时信息</param> | ||||
|     /// <param name="variables">变量数据</param> | ||||
|     protected virtual void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected virtual void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         // 在变量状态变化时执行的自定义逻辑 | ||||
|     } | ||||
| @@ -237,12 +235,12 @@ public abstract class BusinessBaseWithCacheIntervalAlarmModel<VarModel, DevModel | ||||
|                 CollectDevices?.ForEach(a => | ||||
|                 { | ||||
|                     if (a.Value.DeviceStatus == DeviceStatusEnum.OnLine && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                         DeviceStatusChange(a.Value, a.Value.Adapt<DeviceBasicData>()); | ||||
|                         DeviceStatusChange(a.Value, a.Value.AdaptDeviceBasicData()); | ||||
|                 }); | ||||
|                 IdVariableRuntimes.ForEach(a => | ||||
|                 { | ||||
|                     if (a.Value.IsOnline && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                         VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                         VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
| @@ -69,12 +67,12 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode | ||||
|         CollectDevices?.ForEach(a => | ||||
|         { | ||||
|             if (a.Value.DeviceStatus == DeviceStatusEnum.OnLine && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                 DeviceStatusChange(a.Value, a.Value.Adapt<DeviceBasicData>()); | ||||
|                 DeviceStatusChange(a.Value, a.Value.AdaptDeviceBasicData()); | ||||
|         }); | ||||
|         IdVariableRuntimes.ForEach(a => | ||||
|         { | ||||
|             if (a.Value.IsOnline && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                 VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                 VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -133,7 +131,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode | ||||
|                     LogMessage?.LogDebug($"Interval  {typeof(VarModel).Name}  data, count {IdVariableRuntimes.Count}"); | ||||
|                 // 上传所有变量信息 | ||||
|                 var variableRuntimes = IdVariableRuntimes.Select(a => a.Value); | ||||
|                 VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>()); | ||||
|                 VariableTimeInterval(variableRuntimes, variableRuntimes.AdaptIEnumerableVariableBasicData()); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
| @@ -148,7 +146,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode | ||||
|                     // 上传所有设备信息 | ||||
|                     foreach (var deviceRuntime in CollectDevices.Select(a => a.Value)) | ||||
|                     { | ||||
|                         DeviceTimeInterval(deviceRuntime, deviceRuntime.Adapt<DeviceBasicData>()); | ||||
|                         DeviceTimeInterval(deviceRuntime, deviceRuntime.AdaptDeviceBasicData()); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -179,7 +177,7 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode | ||||
|     /// </summary> | ||||
|     /// <param name="variableRuntimes">变量运行时信息</param> | ||||
|     /// <param name="variables">变量数据</param> | ||||
|     protected virtual void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected virtual void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         // 在变量状态变化时执行的自定义逻辑 | ||||
|     } | ||||
| @@ -234,12 +232,12 @@ public abstract class BusinessBaseWithCacheIntervalDeviceModel<VarModel, DevMode | ||||
|                 CollectDevices?.ForEach(a => | ||||
|                 { | ||||
|                     if (a.Value.DeviceStatus == DeviceStatusEnum.OnLine && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                         DeviceStatusChange(a.Value, a.Value.Adapt<DeviceBasicData>()); | ||||
|                         DeviceStatusChange(a.Value, a.Value.AdaptDeviceBasicData()); | ||||
|                 }); | ||||
|                 IdVariableRuntimes.ForEach(a => | ||||
|                 { | ||||
|                     if (a.Value.IsOnline && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                         VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                         VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
| @@ -65,7 +63,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus | ||||
|         IdVariableRuntimes.ForEach(a => | ||||
|         { | ||||
|             if (a.Value.IsOnline && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                 VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                 VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -100,7 +98,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus | ||||
|                     LogMessage?.LogDebug($"Interval  {typeof(VarModel).Name}  data, count {IdVariableRuntimes.Count}"); | ||||
|                 // 上传所有变量信息 | ||||
|                 var variableRuntimes = IdVariableRuntimes.Select(a => a.Value); | ||||
|                 VariableTimeInterval(variableRuntimes, variableRuntimes.Adapt<List<VariableBasicData>>()); | ||||
|                 VariableTimeInterval(variableRuntimes, variableRuntimes.AdaptIEnumerableVariableBasicData()); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
| @@ -131,7 +129,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus | ||||
|     /// </summary> | ||||
|     /// <param name="variableRuntimes">变量运行时信息</param> | ||||
|     /// <param name="variables">变量数据</param> | ||||
|     protected virtual void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected virtual void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         // 在变量状态变化时执行的自定义逻辑 | ||||
|     } | ||||
| @@ -162,7 +160,7 @@ public abstract class BusinessBaseWithCacheIntervalVariableModel<VarModel> : Bus | ||||
|                 IdVariableRuntimes.ForEach(a => | ||||
|                 { | ||||
|                     if (a.Value.IsOnline && _businessPropertyWithCacheInterval.BusinessUpdateEnum != BusinessUpdateEnum.Interval) | ||||
|                         VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                         VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| using System.Reflection; | ||||
|  | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
| @@ -127,23 +125,7 @@ public abstract class CollectBase : DriverBase, IRpcDriver | ||||
|             LogMessage?.LogWarning(ex, string.Format(AppResource.GetMethodError, ex.Message)); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         if (VariableTasks.Count > 0) | ||||
|         { | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 item.Stop(); | ||||
|                 TaskSchedulerLoop.Remove(item); | ||||
|             } | ||||
|  | ||||
|             VariableTasks = AddVariableTask(cancellationToken); | ||||
|  | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 TaskSchedulerLoop.Add(item); | ||||
|                 item.Start(); | ||||
|             } | ||||
|         } | ||||
|         RefreshVariableTasks(cancellationToken); | ||||
|  | ||||
|         // 根据标签获取方法信息的局部函数 | ||||
|         List<VariableMethod> GetMethod(IEnumerable<VariableRuntime> tag) | ||||
| @@ -169,6 +151,26 @@ public abstract class CollectBase : DriverBase, IRpcDriver | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected void RefreshVariableTasks(CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (VariableTasks.Count > 0) | ||||
|         { | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 item.Stop(); | ||||
|                 TaskSchedulerLoop.Remove(item); | ||||
|             } | ||||
|  | ||||
|             VariableTasks = AddVariableTask(cancellationToken); | ||||
|  | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 TaskSchedulerLoop.Add(item); | ||||
|                 item.Start(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     internal override void ProtectedInitDevice(DeviceRuntime device) | ||||
|     { | ||||
|         // 调用基类的初始化方法 | ||||
| @@ -664,7 +666,20 @@ public abstract class CollectBase : DriverBase, IRpcDriver | ||||
|             { | ||||
|                 // 调用方法并获取结果 | ||||
|                 var data = await variableMethod.InvokeMethodAsync(this, value, cancellationToken).ConfigureAwait(false); | ||||
|                 result = data.Adapt<OperResult<object>>(); | ||||
|                 result = new(data); | ||||
|                 var operResultType = typeof(IOperResult<>); | ||||
|                 var interfaceType = data.GetType().GetInterfaces() | ||||
|                     .FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == operResultType); | ||||
|  | ||||
|                 if (interfaceType != null) | ||||
|                 { | ||||
|                     var contentProperty = interfaceType.GetProperty("Content"); | ||||
|                     if (contentProperty != null) | ||||
|                     { | ||||
|                         result.Content = contentProperty.GetValue(data); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 // 如果方法有返回值,并且是读取操作 | ||||
|                 if (method.HasReturn && isRead) | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using System.ComponentModel.DataAnnotations; | ||||
|  | ||||
| @@ -183,7 +183,7 @@ public class Device : BaseDataEntity, IValidatableObject | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     public ModelValueValidateForm? ModelValueValidateForm; | ||||
|     public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) | ||||
|     { | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
| using System.ComponentModel.DataAnnotations; | ||||
| @@ -107,7 +107,7 @@ public class Variable : BaseDataEntity, IValidatableObject | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     public ConcurrentDictionary<long, ModelValueValidateForm>? VariablePropertyModels; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
| @@ -498,7 +496,7 @@ public static class GlobalData | ||||
|  | ||||
|  | ||||
|         // 触发设备状态变化事件,并将设备运行时对象转换为设备数据对象进行传递 | ||||
|         DeviceStatusChangeEvent?.Invoke(deviceRuntime, deviceRuntime.Adapt<DeviceBasicData>()); | ||||
|         DeviceStatusChangeEvent?.Invoke(deviceRuntime, deviceRuntime.AdaptDeviceBasicData()); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -511,7 +509,7 @@ public static class GlobalData | ||||
|  | ||||
|  | ||||
|         // 触发变量值变化事件,并将变量运行时对象转换为变量数据对象进行传递 | ||||
|         VariableValueChangeEvent?.Invoke(variableRuntime, variableRuntime.Adapt<VariableBasicData>()); | ||||
|         VariableValueChangeEvent?.Invoke(variableRuntime, variableRuntime.AdaptVariableBasicData()); | ||||
|  | ||||
|     } | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -0,0 +1,62 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://thingsgateway.cn/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using ThingsGateway.Management; | ||||
|  | ||||
| namespace ThingsGateway.Gateway.Application; | ||||
| [Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)] | ||||
| public static partial class GatewayMapper | ||||
| { | ||||
|     public static partial AlarmVariable AdaptAlarmVariable(this VariableRuntime src); | ||||
|     public static partial DeviceBasicData AdaptDeviceBasicData(this DeviceRuntime src); | ||||
|     public static partial IEnumerable<DeviceBasicData> AdaptIEnumerableDeviceBasicData(this IEnumerable<DeviceRuntime> src); | ||||
|     public static partial List<DeviceBasicData> AdaptListDeviceBasicData(this IEnumerable<DeviceRuntime> src); | ||||
|     public static partial VariableBasicData AdaptVariableBasicData(this VariableRuntime src); | ||||
|     public static partial IEnumerable<VariableBasicData> AdaptIEnumerableVariableBasicData(this IEnumerable<VariableRuntime> src); | ||||
|     public static partial List<VariableBasicData> AdaptListVariableBasicData(this IEnumerable<VariableRuntime> src); | ||||
|  | ||||
|     public static partial Variable AdaptVariable(this VariableRuntime src); | ||||
|  | ||||
|     [MapProperty(nameof(Variable.InitValue), nameof(VariableRuntime.Value))] | ||||
|     public static partial VariableRuntime AdaptVariableRuntime(this Variable src); | ||||
|  | ||||
|     public static partial List<Variable> AdaptListVariable(this IEnumerable<Variable> src); | ||||
|  | ||||
|     public static partial DeviceRuntime AdaptDeviceRuntime(this Device src); | ||||
|  | ||||
|     public static partial ChannelRuntime AdaptChannelRuntime(this Channel src); | ||||
|  | ||||
|     public static partial List<VariableRuntime> AdaptListVariableRuntime(this IEnumerable<Variable> src); | ||||
|     public static partial List<DeviceRuntime> AdaptListDeviceRuntime(this IEnumerable<Device> src); | ||||
|     public static partial List<Device> AdaptListDevice(this IEnumerable<Device> src); | ||||
|  | ||||
|     public static partial List<ChannelRuntime> AdaptListChannelRuntime(this IEnumerable<Channel> src); | ||||
|     public static partial List<Channel> AdaptListChannel(this IEnumerable<Channel> src); | ||||
|  | ||||
|     public static partial List<Variable> AdaptListVariable(this IEnumerable<VariableRuntime> src); | ||||
|  | ||||
|     public static partial List<DeviceDataWithValue> AdaptDeviceDataWithValue(this IEnumerable<DeviceRuntime> src); | ||||
|  | ||||
|     public static partial RedundancyOptions AdaptRedundancyOptions(this RedundancyOptions src); | ||||
|  | ||||
|     public static partial List<DeviceDataWithValue> AdaptListDeviceDataWithValue(this IEnumerable<DeviceRuntime> src); | ||||
|     public static partial List<Channel> AdaptListChannel(this List<ChannelInput> src); | ||||
|     public static partial List<Device> AdaptListDevice(this List<DeviceInput> src); | ||||
|     public static partial List<Variable> AdaptListVariable(this List<VariableInput> src); | ||||
|     public static partial Channel AdaptChannel(this Channel src); | ||||
|     public static partial Device AdaptDevice(this Device src); | ||||
|     public static partial Variable AdaptVariable(this Variable src); | ||||
|     public static partial List<PluginInfo> AdaptListPluginInfo(this List<PluginInfo> src); | ||||
|     public static partial List<VariableBasicData> AdaptIEnumerableVariableBasicData(this IGrouping<string, VariableBasicData> src); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
|  | ||||
| @@ -30,7 +30,7 @@ public class ChannelRuntime : Channel, IChannelOptions, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public PluginInfo? PluginInfo { get; set; } | ||||
|  | ||||
| @@ -47,7 +47,7 @@ public class ChannelRuntime : Channel, IChannelOptions, IDisposable | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public WaitLock WaitLock { get; private set; } = new WaitLock(); | ||||
|  | ||||
| @@ -79,13 +79,13 @@ public class ChannelRuntime : Channel, IChannelOptions, IDisposable | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public TouchSocketConfig Config { get; set; } = new(); | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public IReadOnlyDictionary<long, DeviceRuntime>? ReadDeviceRuntimes => DeviceRuntimes; | ||||
|  | ||||
| @@ -94,7 +94,7 @@ public class ChannelRuntime : Channel, IChannelOptions, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     internal ConcurrentDictionary<long, DeviceRuntime>? DeviceRuntimes { get; } = new(Environment.ProcessorCount, 1000); | ||||
|  | ||||
| @@ -107,7 +107,7 @@ public class ChannelRuntime : Channel, IChannelOptions, IDisposable | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public IDeviceThreadManage? DeviceThreadManage { get; internal set; } | ||||
|  | ||||
|   | ||||
| @@ -19,15 +19,12 @@ namespace ThingsGateway.Gateway.Application; | ||||
| /// </summary> | ||||
| public class DeviceBasicData | ||||
| { | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     public DeviceRuntime DeviceRuntime { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="PrimaryIdEntity.Id"/> | ||||
|     public long Id { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Name"/> | ||||
|     public string Name => DeviceRuntime?.Name; | ||||
|     public string Name { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="DeviceRuntime.ActiveTime"/> | ||||
|     public DateTime ActiveTime { get; set; } | ||||
| @@ -41,37 +38,37 @@ public class DeviceBasicData | ||||
|     public string LastErrorMessage { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="DeviceRuntime.PluginName"/> | ||||
|     public string PluginName => DeviceRuntime?.PluginName; | ||||
|     public string PluginName { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Description"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string? Description => DeviceRuntime?.Description; | ||||
|     public string? Description { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark1"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark1 => DeviceRuntime?.Remark1; | ||||
|     public string Remark1 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark2"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark2 => DeviceRuntime?.Remark2; | ||||
|     public string Remark2 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark3"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark3 => DeviceRuntime?.Remark3; | ||||
|     public string Remark3 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark4"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark4 => DeviceRuntime?.Remark4; | ||||
|     public string Remark4 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark5"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark5 => DeviceRuntime?.Remark5; | ||||
|     public string Remark5 { get; set; } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -81,31 +78,28 @@ public class DeviceBasicData | ||||
| /// </summary> | ||||
| public class VariableBasicData | ||||
| { | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     public VariableRuntime VariableRuntime { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="PrimaryIdEntity.Id"/> | ||||
|     public long Id => VariableRuntime.Id; | ||||
|     public long Id { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.Name"/> | ||||
|     public string Name => VariableRuntime.Name; | ||||
|     public string Name { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.CollectGroup"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string CollectGroup => VariableRuntime.CollectGroup; | ||||
|     public string CollectGroup { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.BusinessGroup"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string BusinessGroup => VariableRuntime.BusinessGroup; | ||||
|     public string BusinessGroup { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.BusinessGroupUpdateTrigger"/> | ||||
|     public bool BusinessGroupUpdateTrigger => VariableRuntime.BusinessGroupUpdateTrigger; | ||||
|     public bool BusinessGroupUpdateTrigger { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VariableRuntime.DeviceName"/> | ||||
|     public string DeviceName => VariableRuntime.DeviceName; | ||||
|     public string DeviceName { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="VariableRuntime.RuntimeType"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
| @@ -144,48 +138,48 @@ public class VariableBasicData | ||||
|     /// <inheritdoc cref="Variable.RegisterAddress"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string? RegisterAddress => VariableRuntime.RegisterAddress; | ||||
|     public string? RegisterAddress { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.Unit"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string? Unit => VariableRuntime.Unit; | ||||
|     public string? Unit { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.Description"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string? Description => VariableRuntime.Description; | ||||
|     public string? Description { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.ProtectType"/> | ||||
|     public ProtectTypeEnum ProtectType => VariableRuntime.ProtectType; | ||||
|     public ProtectTypeEnum ProtectType { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Variable.DataType"/> | ||||
|     public DataTypeEnum DataType => VariableRuntime.DataType; | ||||
|     public DataTypeEnum DataType { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark1"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark1 => VariableRuntime.Remark1; | ||||
|     public string Remark1 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark2"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark2 => VariableRuntime.Remark2; | ||||
|     public string Remark2 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark3"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark3 => VariableRuntime.Remark3; | ||||
|     public string Remark3 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark4"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark4 => VariableRuntime.Remark4; | ||||
|     public string Remark4 { get; set; } | ||||
|  | ||||
|     /// <inheritdoc cref="Device.Remark5"/> | ||||
|     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)] | ||||
|     public string Remark5 => VariableRuntime.Remark5; | ||||
|     public string Remark5 { get; set; } | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
|  | ||||
| @@ -56,7 +56,7 @@ public class DeviceRuntime : Device, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public ChannelRuntime? ChannelRuntime { get; set; } | ||||
|  | ||||
| @@ -69,7 +69,7 @@ public class DeviceRuntime : Device, IDisposable | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     public DateTime DeviceStatusChangeTime = DateTime.UnixEpoch.ToLocalTime(); | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -154,7 +154,7 @@ public class DeviceRuntime : Device, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     internal ConcurrentDictionary<string, VariableRuntime>? VariableRuntimes { get; } = new(Environment.ProcessorCount, 1000); | ||||
|  | ||||
| @@ -168,7 +168,7 @@ public class DeviceRuntime : Device, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public List<VariableMethod>? ReadVariableMethods { get; set; } | ||||
|  | ||||
| @@ -182,7 +182,7 @@ public class DeviceRuntime : Device, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public List<VariableSourceRead>? VariableSourceReads { get; set; } | ||||
|  | ||||
| @@ -191,7 +191,7 @@ public class DeviceRuntime : Device, IDisposable | ||||
|     /// </summary> | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public List<VariableScriptRead>? VariableScriptReads { get; set; } | ||||
|  | ||||
| @@ -227,13 +227,13 @@ public class DeviceRuntime : Device, IDisposable | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public IDriver? Driver { get; internal set; } | ||||
|  | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public IRpcDriver? RpcDriver { get; set; } | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using System.Reflection; | ||||
|  | ||||
| @@ -48,6 +48,6 @@ public class DriverMethodInfo | ||||
|     [SugarColumn(IsIgnore = true)] | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     public MethodInfo? MethodInfo { get; set; } | ||||
| } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
|  | ||||
| using ThingsGateway.Gateway.Application.Extensions; | ||||
| @@ -185,7 +183,7 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable | ||||
|         { | ||||
|             oldAlarm.EventType = EventTypeEnum.Finish; | ||||
|             oldAlarm.EventTime = DateTime.Now; | ||||
|             GlobalData.AlarmChange(this.Adapt<AlarmVariable>()); | ||||
|             GlobalData.AlarmChange(this.AdaptAlarmVariable()); | ||||
|         } | ||||
|  | ||||
|  | ||||
| @@ -215,7 +213,7 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable | ||||
|         { | ||||
|             oldAlarm.EventType = EventTypeEnum.Finish; | ||||
|             oldAlarm.EventTime = DateTime.Now; | ||||
|             GlobalData.AlarmChange(this.Adapt<AlarmVariable>()); | ||||
|             GlobalData.AlarmChange(this.AdaptAlarmVariable()); | ||||
|         } | ||||
|  | ||||
|         GC.SuppressFinalize(this); | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
|  | ||||
| using ThingsGateway.SqlSugar; | ||||
|  | ||||
| @@ -123,7 +123,7 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable | ||||
|     /// </summary> | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public IVariableSource VariableSource { get => variableSource; set => variableSource = value; } | ||||
|  | ||||
| @@ -132,7 +132,7 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable | ||||
|     /// </summary> | ||||
|     [Newtonsoft.Json.JsonIgnore] | ||||
|     [System.Text.Json.Serialization.JsonIgnore] | ||||
|     [AdaptIgnore] | ||||
|     [MapperIgnore] | ||||
|     [AutoGenerateColumn(Ignore = true)] | ||||
|     public VariableMethod VariableMethod { get => variableMethod; set => variableMethod = value; } | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| @@ -204,10 +202,10 @@ public class ChannelRuntimeService : IChannelRuntimeService | ||||
|             await WaitLock.WaitAsync().ConfigureAwait(false); | ||||
|  | ||||
|             //网关启动时,获取所有通道 | ||||
|             var newChannelRuntimes = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).Where(a => ids.Contains(a.Id) || !GlobalData.Channels.ContainsKey(a.Id)).Adapt<List<ChannelRuntime>>(); | ||||
|             var newChannelRuntimes = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).Where(a => ids.Contains(a.Id) || !GlobalData.Channels.ContainsKey(a.Id)).AdaptListChannelRuntime(); | ||||
|  | ||||
|             var chanelIds = newChannelRuntimes.Select(a => a.Id).ToHashSet(); | ||||
|             var newDeviceRuntimes = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).Where(a => chanelIds.Contains(a.ChannelId)).Adapt<List<DeviceRuntime>>(); | ||||
|             var newDeviceRuntimes = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).Where(a => chanelIds.Contains(a.ChannelId)).AdaptListDeviceRuntime(); | ||||
|  | ||||
|             await RuntimeServiceHelper.InitAsync(newChannelRuntimes, newDeviceRuntimes, _logger).ConfigureAwait(false); | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using MiniExcelLibs; | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using MiniExcelLibs; | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| @@ -363,16 +361,16 @@ internal sealed class AlarmHostedService : BackgroundService, IAlarmHostedServic | ||||
|                 //lock (GlobalData. RealAlarmVariables) | ||||
|                 { | ||||
|                     // 从实时报警列表中移除旧的报警信息,并添加新的报警信息 | ||||
|                     GlobalData.RealAlarmIdVariables.AddOrUpdate(item.Id, a => item.Adapt<AlarmVariable>(), (a, b) => item.Adapt<AlarmVariable>()); | ||||
|                     GlobalData.RealAlarmIdVariables.AddOrUpdate(item.Id, a => item.AdaptAlarmVariable(), (a, b) => item.AdaptAlarmVariable()); | ||||
|                 } | ||||
|             } | ||||
|             else if (item.EventType == EventTypeEnum.Finish) | ||||
|             { | ||||
|                 // 如果是需恢复报警事件,则从实时报警列表中移除该变量 | ||||
|                 GlobalData.RealAlarmIdVariables.TryRemove(item.Id, out _); | ||||
|                 //GlobalData.RealAlarmIdVariables.AddOrUpdate(item.Id, a => item.Adapt<AlarmVariable>(), (a, b) => item.Adapt<AlarmVariable>()); | ||||
|                 //GlobalData.RealAlarmIdVariables.AddOrUpdate(item.Id, a => item.AdaptAlarmVariable(), (a, b) => item.AdaptAlarmVariable()); | ||||
|             } | ||||
|             GlobalData.AlarmChange(item.Adapt<AlarmVariable>()); | ||||
|             GlobalData.AlarmChange(item.AdaptAlarmVariable()); | ||||
|         } | ||||
|  | ||||
|     } | ||||
| @@ -380,11 +378,14 @@ internal sealed class AlarmHostedService : BackgroundService, IAlarmHostedServic | ||||
|     public void ConfirmAlarm(long variableId) | ||||
|     { | ||||
|         // 如果是确认报警事件 | ||||
|         if (GlobalData.RealAlarmIdVariables.TryGetValue(variableId, out var variableRuntime)) | ||||
|         if (GlobalData.AlarmEnableIdVariables.TryGetValue(variableId, out var variableRuntime)) | ||||
|         { | ||||
|             variableRuntime.EventType = EventTypeEnum.Confirm; | ||||
|             variableRuntime.EventTime = DateTime.Now; | ||||
|             GlobalData.AlarmChange(variableRuntime.Adapt<AlarmVariable>()); | ||||
|             var data = variableRuntime.AdaptAlarmVariable(); | ||||
|             GlobalData.RealAlarmIdVariables.AddOrUpdate(variableId, a => data, (a, b) => data); | ||||
|  | ||||
|             GlobalData.AlarmChange(data); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Hosting; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
| @@ -445,7 +443,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage | ||||
|                     var saveVariables = new List<Variable>(); | ||||
|                     foreach (var item in saveVariableRuntimes) | ||||
|                     { | ||||
|                         var data = item.Adapt<Variable>(); | ||||
|                         var data = item.AdaptVariable(); | ||||
|                         data.InitValue = item.Value; | ||||
|                         saveVariables.Add(data); | ||||
|                     } | ||||
| @@ -599,7 +597,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         newDeviceRuntime = newDev.Adapt<DeviceRuntime>(); | ||||
|                         newDeviceRuntime = newDev.AdaptDeviceRuntime(); | ||||
|                         SetRedundantDevice(deviceRuntime, newDeviceRuntime); | ||||
|                     } | ||||
|                 } | ||||
| @@ -620,7 +618,7 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         newDeviceRuntime = newDev.Adapt<DeviceRuntime>(); | ||||
|                         newDeviceRuntime = newDev.AdaptDeviceRuntime(); | ||||
|                         SetRedundantDevice(deviceRuntime, newDeviceRuntime); | ||||
|                     } | ||||
|                 } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Localization; | ||||
| using Microsoft.Extensions.Logging; | ||||
| @@ -42,9 +40,9 @@ internal sealed class GatewayMonitorHostedService : BackgroundService, IGatewayM | ||||
|         { | ||||
|  | ||||
|             //网关启动时,获取所有通道 | ||||
|             var channelRuntimes = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).Adapt<List<ChannelRuntime>>(); | ||||
|             var deviceRuntimes = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).Adapt<List<DeviceRuntime>>(); | ||||
|             var variableRuntimes = (await GlobalData.VariableService.GetAllAsync().ConfigureAwait(false)).Adapt<List<VariableRuntime>>(); | ||||
|             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(); | ||||
|             foreach (var channelRuntime in channelRuntimes) | ||||
|             { | ||||
|                 try | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Localization; | ||||
| using Microsoft.Extensions.Logging; | ||||
| @@ -158,7 +156,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo | ||||
|                 // 如果 online 为 true,表示设备在线 | ||||
|                 if (online) | ||||
|                 { | ||||
|                     var deviceRunTimes = GlobalData.ReadOnlyIdDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).Adapt<List<DeviceDataWithValue>>(); | ||||
|                     var deviceRunTimes = GlobalData.ReadOnlyIdDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).AdaptListDeviceDataWithValue(); | ||||
|  | ||||
|                     foreach (var item in TcpDmtpService.Clients) | ||||
|                     { | ||||
| @@ -370,7 +368,7 @@ internal sealed class RedundancyHostedService : BackgroundService, IRedundancyHo | ||||
|  | ||||
|     private async Task BeforeStartAsync() | ||||
|     { | ||||
|         RedundancyOptions = (await _redundancyService.GetRedundancyAsync().ConfigureAwait(false)).Adapt<RedundancyOptions>(); | ||||
|         RedundancyOptions = (await _redundancyService.GetRedundancyAsync().ConfigureAwait(false)).AdaptRedundancyOptions(); | ||||
|  | ||||
|         if (RedundancyOptions?.Enable == true) | ||||
|         { | ||||
|   | ||||
| @@ -11,8 +11,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
| @@ -38,7 +36,7 @@ internal static class RuntimeServiceHelper | ||||
|                 { | ||||
|                     newDeviceRuntime.Init(newChannelRuntime); | ||||
|  | ||||
|                     var newVariableRuntimes = (await GlobalData.VariableService.GetAllAsync(newDeviceRuntime.Id).ConfigureAwait(false)).Adapt<List<VariableRuntime>>(); | ||||
|                     var newVariableRuntimes = (await GlobalData.VariableService.GetAllAsync(newDeviceRuntime.Id).ConfigureAwait(false)).AdaptListVariableRuntime(); | ||||
|  | ||||
|                     newVariableRuntimes.ParallelForEach(item => | ||||
|                     { | ||||
| @@ -91,7 +89,7 @@ internal static class RuntimeServiceHelper | ||||
|                 { | ||||
|                     newDeviceRuntime.Init(newChannelRuntime); | ||||
|  | ||||
|                     var newVariableRuntimes = (await GlobalData.VariableService.GetAllAsync(newDeviceRuntime.Id).ConfigureAwait(false)).Adapt<List<VariableRuntime>>(); | ||||
|                     var newVariableRuntimes = (await GlobalData.VariableService.GetAllAsync(newDeviceRuntime.Id).ConfigureAwait(false)).AdaptListVariableRuntime(); | ||||
|  | ||||
|                     newVariableRuntimes.ParallelForEach(item => | ||||
|                     { | ||||
| @@ -169,13 +167,13 @@ internal static class RuntimeServiceHelper | ||||
|  | ||||
|     public static async Task<List<ChannelRuntime>> GetNewChannelRuntimesAsync(HashSet<long> ids) | ||||
|     { | ||||
|         var newChannelRuntimes = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).Where(a => ids.Contains(a.Id)).Adapt<List<ChannelRuntime>>(); | ||||
|         var newChannelRuntimes = (await GlobalData.ChannelService.GetAllAsync().ConfigureAwait(false)).Where(a => ids.Contains(a.Id)).AdaptListChannelRuntime(); | ||||
|         return newChannelRuntimes; | ||||
|     } | ||||
|  | ||||
|     public static async Task<List<DeviceRuntime>> GetNewDeviceRuntimesAsync(HashSet<long> deviceids) | ||||
|     { | ||||
|         var newDeviceRuntimes = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).Where(a => deviceids.Contains(a.Id)).Adapt<List<DeviceRuntime>>(); | ||||
|         var newDeviceRuntimes = (await GlobalData.DeviceService.GetAllAsync().ConfigureAwait(false)).Where(a => deviceids.Contains(a.Id)).AdaptListDeviceRuntime(); | ||||
|         return newDeviceRuntimes; | ||||
|     } | ||||
|  | ||||
| @@ -269,10 +267,10 @@ internal static class RuntimeServiceHelper | ||||
|     public static async Task RemoveDeviceAsync(HashSet<long> newDeciceIds) | ||||
|     { | ||||
|         //先找出线程管理器,停止 | ||||
|         var deviceRuntimes = GlobalData.IdDevices.Where(a => newDeciceIds.Contains(a.Key)).Select(a => a.Value).ToList(); | ||||
|         var deviceRuntimes = GlobalData.IdDevices.Where(a => newDeciceIds.Contains(a.Key)).Select(a => a.Value); | ||||
|         await RemoveDeviceAsync(deviceRuntimes).ConfigureAwait(false); | ||||
|     } | ||||
|     public static async Task RemoveDeviceAsync(List<DeviceRuntime> deviceRuntimes) | ||||
|     public static async Task RemoveDeviceAsync(IEnumerable<DeviceRuntime> deviceRuntimes) | ||||
|     { | ||||
|         var groups = GlobalData.GetDeviceThreadManages(deviceRuntimes); | ||||
|         foreach (var group in groups) | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| @@ -38,7 +36,7 @@ public class VariableRuntimeService : IVariableRuntimeService | ||||
|  | ||||
|             var result = await GlobalData.VariableService.BatchSaveVariableAsync(input.Where(a => !a.DynamicVariable).ToList(), type).ConfigureAwait(false); | ||||
|  | ||||
|             var newVariableRuntimes = input.Adapt<List<VariableRuntime>>(); | ||||
|             var newVariableRuntimes = input.AdaptListVariableRuntime(); | ||||
|             var variableIds = newVariableRuntimes.Select(a => a.Id).ToHashSet(); | ||||
|             //获取变量,先找到原插件线程,然后修改插件线程内的字典,再改动全局字典,最后刷新插件 | ||||
|  | ||||
| @@ -73,7 +71,7 @@ public class VariableRuntimeService : IVariableRuntimeService | ||||
|             using var db = DbContext.GetDB<Variable>(); | ||||
|             var ids = models.Select(a => a.Id).ToHashSet(); | ||||
|  | ||||
|             var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => ids.Contains(a.Id)).ToListAsync(cancellationToken).ConfigureAwait(false)).Adapt<List<VariableRuntime>>(); | ||||
|             var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => ids.Contains(a.Id)).ToListAsync(cancellationToken).ConfigureAwait(false)).AdaptListVariableRuntime(); | ||||
|  | ||||
|             var variableIds = newVariableRuntimes.Select(a => a.Id).ToHashSet(); | ||||
|  | ||||
| @@ -140,7 +138,7 @@ public class VariableRuntimeService : IVariableRuntimeService | ||||
|  | ||||
|  | ||||
|             using var db = DbContext.GetDB<Variable>(); | ||||
|             var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => result.Contains(a.Id)).ToListAsync(cancellationToken).ConfigureAwait(false)).Adapt<List<VariableRuntime>>(); | ||||
|             var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => result.Contains(a.Id)).ToListAsync(cancellationToken).ConfigureAwait(false)).AdaptListVariableRuntime(); | ||||
|  | ||||
|             var variableIds = newVariableRuntimes.Select(a => a.Id).ToHashSet(); | ||||
|  | ||||
| @@ -176,20 +174,20 @@ public class VariableRuntimeService : IVariableRuntimeService | ||||
|             var datas = await GlobalData.VariableService.InsertTestDataAsync(testVariableCount, testDeviceCount, slaveUrl, businessEnable).ConfigureAwait(false); | ||||
|  | ||||
|             { | ||||
|                 var newChannelRuntimes = datas.Item1.Adapt<List<ChannelRuntime>>(); | ||||
|                 var newChannelRuntimes = datas.Item1.AdaptListChannelRuntime(); | ||||
|  | ||||
|                 //批量修改之后,需要重新加载通道 | ||||
|                 RuntimeServiceHelper.Init(newChannelRuntimes); | ||||
|  | ||||
|                 { | ||||
|  | ||||
|                     var newDeviceRuntimes = datas.Item2.Adapt<List<DeviceRuntime>>(); | ||||
|                     var newDeviceRuntimes = datas.Item2.AdaptListDeviceRuntime(); | ||||
|  | ||||
|                     RuntimeServiceHelper.Init(newDeviceRuntimes); | ||||
|  | ||||
|                 } | ||||
|                 { | ||||
|                     var newVariableRuntimes = datas.Item3.Adapt<List<VariableRuntime>>(); | ||||
|                     var newVariableRuntimes = datas.Item3.AdaptListVariableRuntime(); | ||||
|                     RuntimeServiceHelper.Init(newVariableRuntimes); | ||||
|  | ||||
|                 } | ||||
| @@ -230,7 +228,7 @@ public class VariableRuntimeService : IVariableRuntimeService | ||||
|  | ||||
|  | ||||
|             using var db = DbContext.GetDB<Variable>(); | ||||
|             var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => a.Id == input.Id).ToListAsync(cancellationToken).ConfigureAwait(false)).Adapt<List<VariableRuntime>>(); | ||||
|             var newVariableRuntimes = (await db.Queryable<Variable>().Where(a => a.Id == input.Id).ToListAsync(cancellationToken).ConfigureAwait(false)).AdaptListVariableRuntime(); | ||||
|  | ||||
|             var variableIds = newVariableRuntimes.Select(a => a.Id).ToHashSet(); | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using MiniExcelLibs; | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| @@ -54,11 +52,6 @@ public class Startup : AppStartup | ||||
|         //底层多语言配置 | ||||
|         Foundation.LocalizerUtil.SetLocalizerFactory((a) => App.CreateLocalizerByType(a)); | ||||
|  | ||||
|         TypeAdapterConfig.GlobalSettings.Scan(App.Assemblies.ToArray()); | ||||
|         // 配置默认全局映射(支持覆盖) | ||||
|         TypeAdapterConfig.GlobalSettings.Default | ||||
|               .PreserveReference(true); | ||||
|  | ||||
|         //运行日志写入数据库配置 | ||||
|         services.AddDatabaseLogging<BackendLogDatabaseLoggingWriter>(options => | ||||
|         { | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| 	</PropertyGroup> | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" /> | ||||
| 		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" /> | ||||
| 		<PackageReference Include="Rougamo.Fody" Version="5.0.1" /> | ||||
| 		<PackageReference Include="TouchSocket.Dmtp" Version="3.1.11" /> | ||||
| 		<PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.11" /> | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| using ThingsGateway.Foundation; | ||||
| using ThingsGateway.NewLife.Json.Extension; | ||||
| @@ -50,7 +48,7 @@ public partial class TcpServiceComponent : IDriverUIBase | ||||
|         if (TcpServiceChannel != null) | ||||
|         { | ||||
|             var clients = TcpServiceChannel.Clients.ToList(); | ||||
|             var data = clients.Adapt<List<TcpSessionClientDto>>(); | ||||
|             var data = clients.AdaptListTcpSessionClientDto(); | ||||
|             for (int i = 0; i < clients.Count; i++) | ||||
|             { | ||||
|                 var client = clients[i]; | ||||
|   | ||||
| @@ -8,26 +8,15 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| 
 | ||||
| using Mapster; | ||||
| using Riok.Mapperly.Abstractions; | ||||
| 
 | ||||
| namespace ThingsGateway.Gateway.Application; | ||||
| using ThingsGateway.Foundation; | ||||
| 
 | ||||
| public class VariableMapper : IRegister | ||||
| namespace ThingsGateway.Gateway.Razor; | ||||
| [Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)] | ||||
| public static partial class GatewayMapper | ||||
| { | ||||
|     /// <inheritdoc/> | ||||
|     public void Register(TypeAdapterConfig config) | ||||
|     { | ||||
|         config.ForType<Variable, VariableRuntime>() | ||||
|         .Map(dest => dest.Value, src => src.InitValue); | ||||
| 
 | ||||
|         config.ForType<VariableRuntime, VariableRuntime>() | ||||
| .Ignore(dest => dest.DeviceRuntime); | ||||
| 
 | ||||
|         config.ForType<VariableRuntime, VariableBasicData>() | ||||
|             .BeforeMapping((a, b) => b.VariableRuntime = a); | ||||
|         config.ForType<DeviceRuntime, DeviceBasicData>() | ||||
|             .BeforeMapping((a, b) => b.DeviceRuntime = a); | ||||
| 
 | ||||
|     public static partial List<TcpSessionClientDto> AdaptListTcpSessionClientDto(this List<TcpSessionClientChannel> src); | ||||
| 
 | ||||
| } | ||||
| } | ||||
| 
 | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
|  | ||||
| namespace ThingsGateway.Gateway.Razor; | ||||
| @@ -51,14 +49,14 @@ public partial class ChannelCopyComponent | ||||
|             Dictionary<Device, List<Variable>> devices = new(); | ||||
|             for (int i = 0; i < CopyCount; i++) | ||||
|             { | ||||
|                 Channel channel = Model.Adapt<Channel>(); | ||||
|                 Channel channel = Model.AdaptChannel(); | ||||
|                 channel.Id = CommonUtils.GetSingleId(); | ||||
|                 channel.Name = $"{CopyChannelNamePrefix}{CopyChannelNameSuffixNumber + i}"; | ||||
|  | ||||
|                 int index = 0; | ||||
|                 foreach (var item in Devices) | ||||
|                 { | ||||
|                     Device device = item.Key.Adapt<Device>(); | ||||
|                     Device device = item.Key.AdaptDevice(); | ||||
|                     device.Id = CommonUtils.GetSingleId(); | ||||
|                     device.Name = $"{channel.Name}_{CopyDeviceNamePrefix}{CopyDeviceNameSuffixNumber + (index++)}"; | ||||
|                     device.ChannelId = channel.Id; | ||||
| @@ -66,7 +64,7 @@ public partial class ChannelCopyComponent | ||||
|  | ||||
|                     foreach (var variable in item.Value) | ||||
|                     { | ||||
|                         Variable v = variable.Adapt<Variable>(); | ||||
|                         Variable v = variable.AdaptVariable(); | ||||
|                         v.Id = CommonUtils.GetSingleId(); | ||||
|                         v.DeviceId = device.Id; | ||||
|                         variables.Add(v); | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| @@ -22,7 +20,7 @@ public partial class ChannelTable : IDisposable | ||||
| { | ||||
|     private static void BeforeShowEditDialogCallback(ITableEditDialogOption<ChannelRuntime> tableEditDialogOption) | ||||
|     { | ||||
|         tableEditDialogOption.Model = tableEditDialogOption.Model.Adapt<ChannelRuntime>(); | ||||
|         tableEditDialogOption.Model = tableEditDialogOption.Model.AdaptChannelRuntime(); | ||||
|     } | ||||
|  | ||||
|     public bool Disposed { get; set; } | ||||
| @@ -113,10 +111,10 @@ public partial class ChannelTable : IDisposable | ||||
|         Channel oneModel = null; | ||||
|         Dictionary<Device, List<Variable>> deviceDict = new(); | ||||
|         var channelRuntime = channels.FirstOrDefault(); | ||||
|         oneModel = channelRuntime.Adapt<Channel>(); | ||||
|         oneModel = channelRuntime.AdaptChannel(); | ||||
|         oneModel.Id = 0; | ||||
|  | ||||
|         deviceDict = channelRuntime.ReadDeviceRuntimes.ToDictionary(a => a.Value.Adapt<Device>(), a => a.Value.ReadOnlyVariableRuntimes.Select(a => a.Value).Adapt<List<Variable>>()); | ||||
|         deviceDict = channelRuntime.ReadDeviceRuntimes.ToDictionary(a => a.Value.AdaptDevice(), a => a.Value.ReadOnlyVariableRuntimes.Select(a => a.Value).AdaptListVariable()); | ||||
|  | ||||
|  | ||||
|         var op = new DialogOption() | ||||
| @@ -157,9 +155,9 @@ public partial class ChannelTable : IDisposable | ||||
|             await ToastService.Warning(null, RazorLocalizer["PleaseSelect"]); | ||||
|             return; | ||||
|         } | ||||
|         changedModels = changedModels.Adapt<List<Channel>>(); | ||||
|         oldModel = oldModel.Adapt<Channel>(); | ||||
|         var oneModel = oldModel.Adapt<Channel>();//默认值显示第一个 | ||||
|         changedModels = changedModels.AdaptListChannel(); | ||||
|         oldModel = oldModel.AdaptChannel(); | ||||
|         var oneModel = oldModel.AdaptChannel();//默认值显示第一个 | ||||
|  | ||||
|         var op = new DialogOption() | ||||
|         { | ||||
| @@ -215,7 +213,7 @@ public partial class ChannelTable : IDisposable | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             channel = channel.Adapt<Channel>(); | ||||
|             channel = channel.AdaptChannel(); | ||||
|             return await Task.Run(() => GlobalData.ChannelRuntimeService.SaveChannelAsync(channel, itemChangedType, AutoRestartThread)); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -229,7 +227,7 @@ public partial class ChannelTable : IDisposable | ||||
|  | ||||
|     private Task<ChannelRuntime> OnAdd() | ||||
|     { | ||||
|         return Task.FromResult(ChannelDeviceHelpers.GetChannelModel(ItemChangedType.Add, SelectModel).Adapt<ChannelRuntime>()); | ||||
|         return Task.FromResult(ChannelDeviceHelpers.GetChannelModel(ItemChangedType.Add, SelectModel).AdaptChannelRuntime()); | ||||
|     } | ||||
|  | ||||
|     #region 导出 | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| using Mapster; | ||||
| //------------------------------------------------------------------------------ | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| @@ -19,7 +18,7 @@ namespace ThingsGateway.Gateway.Razor | ||||
|             Channel oneModel = null; | ||||
|             if (channelDeviceTreeItem.TryGetChannelRuntime(out var channelRuntime)) | ||||
|             { | ||||
|                 oneModel = channelRuntime.Adapt<Channel>(); | ||||
|                 oneModel = channelRuntime.AdaptChannel(); | ||||
|                 if (itemChangedType == ItemChangedType.Add) | ||||
|                 { | ||||
|                     oneModel.Id = 0; | ||||
| @@ -28,7 +27,7 @@ namespace ThingsGateway.Gateway.Razor | ||||
|             } | ||||
|             else if (channelDeviceTreeItem.TryGetDeviceRuntime(out var deviceRuntime)) | ||||
|             { | ||||
|                 oneModel = deviceRuntime.ChannelRuntime?.Adapt<Channel>() ?? new(); | ||||
|                 oneModel = deviceRuntime.ChannelRuntime?.AdaptChannel() ?? new(); | ||||
|                 if (itemChangedType == ItemChangedType.Add) | ||||
|                 { | ||||
|                     oneModel.Id = 0; | ||||
| @@ -51,7 +50,7 @@ namespace ThingsGateway.Gateway.Razor | ||||
|             Device oneModel = null; | ||||
|             if (channelDeviceTreeItem.TryGetDeviceRuntime(out var deviceRuntime)) | ||||
|             { | ||||
|                 oneModel = deviceRuntime.Adapt<Device>(); | ||||
|                 oneModel = deviceRuntime.AdaptDevice(); | ||||
|                 if (itemChangedType == ItemChangedType.Add) | ||||
|                 { | ||||
|                     oneModel.Id = 0; | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.AspNetCore.Components.Web; | ||||
|  | ||||
| @@ -145,10 +143,10 @@ public partial class ChannelDeviceTree | ||||
|  | ||||
|         if (channelDeviceTreeItem.TryGetChannelRuntime(out var channelRuntime)) | ||||
|         { | ||||
|             oneModel = channelRuntime.Adapt<Channel>(); | ||||
|             oneModel = channelRuntime.AdaptChannel(); | ||||
|             oneModel.Id = 0; | ||||
|  | ||||
|             deviceDict = channelRuntime.ReadDeviceRuntimes.ToDictionary(a => a.Value.Adapt<Device>(), a => a.Value.ReadOnlyVariableRuntimes.Select(a => a.Value).Adapt<List<Variable>>()); | ||||
|             deviceDict = channelRuntime.ReadDeviceRuntimes.ToDictionary(a => a.Value.AdaptDevice(), a => a.Value.ReadOnlyVariableRuntimes.Select(a => a.Value).AdaptListVariable()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @@ -210,7 +208,7 @@ public partial class ChannelDeviceTree | ||||
|             models = data.Where(a => a.PluginName == pluginName); | ||||
|             oldModel = models.FirstOrDefault(); | ||||
|             changedModels = models; | ||||
|             oneModel = oldModel.Adapt<Channel>(); | ||||
|             oneModel = oldModel.AdaptChannel(); | ||||
|  | ||||
|         } | ||||
|         else if (channelDeviceTreeItem.TryGetPluginType(out var pluginType)) | ||||
| @@ -221,7 +219,7 @@ public partial class ChannelDeviceTree | ||||
|             models = data.Where(a => a.PluginType == pluginType); | ||||
|             oldModel = models.FirstOrDefault(); | ||||
|             changedModels = models; | ||||
|             oneModel = oldModel.Adapt<Channel>(); | ||||
|             oneModel = oldModel.AdaptChannel(); | ||||
|  | ||||
|  | ||||
|         } | ||||
| @@ -230,8 +228,8 @@ public partial class ChannelDeviceTree | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         changedModels = changedModels.Adapt<List<Channel>>(); | ||||
|         oldModel = oldModel.Adapt<Channel>(); | ||||
|         changedModels = changedModels.AdaptListChannel(); | ||||
|         oldModel = oldModel.AdaptChannel(); | ||||
|         var op = new DialogOption() | ||||
|         { | ||||
|             IsScrolling = false, | ||||
| @@ -628,10 +626,10 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|  | ||||
|         if (channelDeviceTreeItem.TryGetDeviceRuntime(out var deviceRuntime)) | ||||
|         { | ||||
|             oneModel = deviceRuntime.Adapt<Device>(); | ||||
|             oneModel = deviceRuntime.AdaptDevice(); | ||||
|             oneModel.Id = 0; | ||||
|  | ||||
|             variables = deviceRuntime.ReadOnlyVariableRuntimes.Select(a => a.Value).Adapt<List<Variable>>(); | ||||
|             variables = deviceRuntime.ReadOnlyVariableRuntimes.Select(a => a.Value).AdaptListVariable(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @@ -672,7 +670,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|  | ||||
|         if (channelDeviceTreeItem.TryGetDeviceRuntime(out var deviceRuntime)) | ||||
|         { | ||||
|             oneModel = deviceRuntime.Adapt<Device>(); | ||||
|             oneModel = deviceRuntime.AdaptDevice(); | ||||
|             if (itemChangedType == ItemChangedType.Add) | ||||
|             { | ||||
|                 oneModel.Id = 0; | ||||
| @@ -738,7 +736,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|             models = data.Where(a => a.ChannelId == channelRuntime.Id); | ||||
|             oldModel = models.FirstOrDefault(); | ||||
|             changedModels = models; | ||||
|             oneModel = oldModel.Adapt<Device>(); | ||||
|             oneModel = oldModel.AdaptDevice(); | ||||
|         } | ||||
|         //批量编辑只有分类和插件名称节点 | ||||
|         else if (channelDeviceTreeItem.TryGetPluginName(out var pluginName)) | ||||
| @@ -748,7 +746,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|             models = data.Where(a => a.PluginName == pluginName); ; | ||||
|             oldModel = models.FirstOrDefault(); | ||||
|             changedModels = models; | ||||
|             oneModel = oldModel.Adapt<Device>(); | ||||
|             oneModel = oldModel.AdaptDevice(); | ||||
|  | ||||
|         } | ||||
|         else if (channelDeviceTreeItem.TryGetPluginType(out var pluginType)) | ||||
| @@ -759,7 +757,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|             models = data.Where(a => a.PluginType == pluginType); ; | ||||
|             oldModel = models.FirstOrDefault(); | ||||
|             changedModels = models; | ||||
|             oneModel = oldModel.Adapt<Device>(); | ||||
|             oneModel = oldModel.AdaptDevice(); | ||||
|  | ||||
|  | ||||
|         } | ||||
| @@ -768,8 +766,8 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e => | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         changedModels = changedModels.Adapt<List<Device>>(); | ||||
|         oldModel = oldModel.Adapt<Device>(); | ||||
|         changedModels = changedModels.AdaptListDevice(); | ||||
|         oldModel = oldModel.AdaptDevice(); | ||||
|         op.Component = BootstrapDynamicComponent.CreateComponent<DeviceEditComponent>(new Dictionary<string, object?> | ||||
|         { | ||||
|              {nameof(DeviceEditComponent.OnValidSubmit), async () => | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
|  | ||||
| namespace ThingsGateway.Gateway.Razor; | ||||
| @@ -47,14 +45,14 @@ public partial class DeviceCopyComponent | ||||
|             Dictionary<Device, List<Variable>> devices = new(); | ||||
|             for (int i = 0; i < CopyCount; i++) | ||||
|             { | ||||
|                 Device device = Model.Adapt<Device>(); | ||||
|                 Device device = Model.AdaptDevice(); | ||||
|                 device.Id = CommonUtils.GetSingleId(); | ||||
|                 device.Name = $"{CopyDeviceNamePrefix}{CopyDeviceNameSuffixNumber + i}"; | ||||
|                 List<Variable> variables = new(); | ||||
|  | ||||
|                 foreach (var item in Variables) | ||||
|                 { | ||||
|                     Variable v = item.Adapt<Variable>(); | ||||
|                     Variable v = item.AdaptVariable(); | ||||
|                     v.Id = CommonUtils.GetSingleId(); | ||||
|                     v.DeviceId = device.Id; | ||||
|                     variables.Add(v); | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| @@ -22,7 +20,7 @@ public partial class DeviceTable : IDisposable | ||||
| { | ||||
|     private static void BeforeShowEditDialogCallback(ITableEditDialogOption<DeviceRuntime> tableEditDialogOption) | ||||
|     { | ||||
|         tableEditDialogOption.Model = tableEditDialogOption.Model.Adapt<DeviceRuntime>(); | ||||
|         tableEditDialogOption.Model = tableEditDialogOption.Model.AdaptDeviceRuntime(); | ||||
|     } | ||||
|  | ||||
|     public bool Disposed { get; set; } | ||||
| @@ -113,10 +111,10 @@ public partial class DeviceTable : IDisposable | ||||
|         Device oneModel = null; | ||||
|         List<Variable> variables = new(); | ||||
|         var deviceRuntime = devices.FirstOrDefault(); | ||||
|         oneModel = deviceRuntime.Adapt<Device>(); | ||||
|         oneModel = deviceRuntime.AdaptDevice(); | ||||
|         oneModel.Id = 0; | ||||
|  | ||||
|         variables = deviceRuntime.ReadOnlyVariableRuntimes.Select(a => a.Value).Adapt<List<Variable>>(); | ||||
|         variables = deviceRuntime.ReadOnlyVariableRuntimes.Select(a => a.Value).AdaptListVariable(); | ||||
|  | ||||
|  | ||||
|         var op = new DialogOption() | ||||
| @@ -156,9 +154,9 @@ public partial class DeviceTable : IDisposable | ||||
|             await ToastService.Warning(null, RazorLocalizer["PleaseSelect"]); | ||||
|             return; | ||||
|         } | ||||
|         changedModels = changedModels.Adapt<List<Device>>(); | ||||
|         oldModel = oldModel.Adapt<Device>(); | ||||
|         var oneModel = oldModel.Adapt<Device>();//默认值显示第一个 | ||||
|         changedModels = changedModels.AdaptListDevice(); | ||||
|         oldModel = oldModel.AdaptDevice(); | ||||
|         var oneModel = oldModel.AdaptDevice();//默认值显示第一个 | ||||
|  | ||||
|         var op = new DialogOption() | ||||
|         { | ||||
| @@ -215,7 +213,7 @@ public partial class DeviceTable : IDisposable | ||||
|         try | ||||
|         { | ||||
|             device.DevicePropertys = PluginServiceUtil.SetDict(device.ModelValueValidateForm.Value); | ||||
|             device = device.Adapt<Device>(); | ||||
|             device = device.AdaptDevice(); | ||||
|             return await Task.Run(() => GlobalData.DeviceRuntimeService.SaveDeviceAsync(device, itemChangedType, AutoRestartThread)); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -229,7 +227,7 @@ public partial class DeviceTable : IDisposable | ||||
|  | ||||
|     private Task<DeviceRuntime> OnAdd() | ||||
|     { | ||||
|         return Task.FromResult(ChannelDeviceHelpers.GetDeviceModel(ItemChangedType.Add, SelectModel).Adapt<DeviceRuntime>()); | ||||
|         return Task.FromResult(ChannelDeviceHelpers.GetDeviceModel(ItemChangedType.Add, SelectModel).AdaptDeviceRuntime()); | ||||
|     } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
|  | ||||
| namespace ThingsGateway.Gateway.Razor; | ||||
| @@ -42,7 +40,7 @@ public partial class VariableCopyComponent | ||||
|             List<Variable> variables = new(); | ||||
|             for (int i = 0; i < CopyCount; i++) | ||||
|             { | ||||
|                 var variable = Model.Adapt<List<Variable>>(); | ||||
|                 var variable = Model.AdaptListVariable(); | ||||
|                 foreach (var item in variable) | ||||
|                 { | ||||
|                     item.Id = CommonUtils.GetSingleId(); | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| @namespace ThingsGateway.Gateway.Razor | ||||
| @using System.Text.Json.Nodes | ||||
| @using Mapster | ||||
| @using Microsoft.Extensions.Hosting | ||||
| @using ThingsGateway.Admin.Application | ||||
| @using ThingsGateway.Admin.Razor | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.Extensions.Options; | ||||
|  | ||||
| @@ -25,7 +23,7 @@ public partial class VariableRuntimeInfo : IDisposable | ||||
|  | ||||
|     private static void BeforeShowEditDialogCallback(ITableEditDialogOption<VariableRuntime> tableEditDialogOption) | ||||
|     { | ||||
|         tableEditDialogOption.Model = tableEditDialogOption.Model.Adapt<VariableRuntime>(); | ||||
|         tableEditDialogOption.Model = tableEditDialogOption.Model.AdaptVariableRuntime(); | ||||
|     } | ||||
|  | ||||
|     [Inject] | ||||
| @@ -217,9 +215,9 @@ public partial class VariableRuntimeInfo : IDisposable | ||||
|             await ToastService.Warning(null, RazorLocalizer["PleaseSelect"]); | ||||
|             return; | ||||
|         } | ||||
|         variables = variables.Where(a => !a.DynamicVariable).Adapt<List<Variable>>(); | ||||
|         oldModel = oldModel.Adapt<Variable>(); | ||||
|         var model = oldModel.Adapt<Variable>();//默认值显示第一个 | ||||
|         variables = variables.Where(a => !a.DynamicVariable).AdaptListVariable(); | ||||
|         oldModel = oldModel.AdaptVariable(); | ||||
|         var model = oldModel.AdaptVariable();//默认值显示第一个 | ||||
|         op.Component = BootstrapDynamicComponent.CreateComponent<VariableEditComponent>(new Dictionary<string, object?> | ||||
|         { | ||||
|              {nameof(VariableEditComponent.OnValidSubmit), async () => | ||||
| @@ -272,7 +270,7 @@ public partial class VariableRuntimeInfo : IDisposable | ||||
|             } | ||||
|  | ||||
|             variable.VariablePropertys = PluginServiceUtil.SetDict(variable.VariablePropertyModels); | ||||
|             variable = variable.Adapt<Variable>(); | ||||
|             variable = variable.AdaptVariable(); | ||||
|             return await Task.Run(() => GlobalData.VariableRuntimeService.SaveVariableAsync(variable, itemChangedType, AutoRestartThread, default)); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|   | ||||
| @@ -9,8 +9,6 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| #pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.AspNetCore.Components.Web; | ||||
|  | ||||
| @@ -47,7 +45,7 @@ public partial class RedundancyOptionsPage | ||||
|     { | ||||
|         await base.OnInitializedAsync(); | ||||
|         HeaderText = GatewayLocalizer[nameof(HeaderText)]; | ||||
|         Model = (await RedundancyService.GetRedundancyAsync()).Adapt<RedundancyOptions>(); | ||||
|         Model = (await RedundancyService.GetRedundancyAsync()).AdaptRedundancyOptions(); | ||||
|     } | ||||
|  | ||||
|     [Inject] | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| @page "/gateway/plugindebug" | ||||
| @namespace ThingsGateway.Gateway.Razor | ||||
| @using System.Linq.Expressions; | ||||
| @using Mapster; | ||||
| @using System.IO; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
|  | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.NewLife.Extension; | ||||
|  | ||||
| namespace ThingsGateway.Gateway.Razor; | ||||
| @@ -28,7 +26,7 @@ public partial class PluginDebugPage | ||||
|     /// <inheritdoc/> | ||||
|     protected override void OnParametersSet() | ||||
|     { | ||||
|         var pluginInfos = PluginService.GetList().Adapt<List<PluginInfo>>(); | ||||
|         var pluginInfos = PluginService.GetList().AdaptListPluginInfo(); | ||||
|  | ||||
|         foreach (var pluginInfo in pluginInfos.ToList()) | ||||
|         { | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| 		<ProjectReference Include="..\ThingsGateway.Blazor.Diagrams\ThingsGateway.Blazor.Diagrams.csproj" /> | ||||
| 		<ProjectReference Include="..\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" /> | ||||
| 		<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" /> | ||||
| 		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" /> | ||||
| 		<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" /> | ||||
| 		<PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.1" /> | ||||
| 		<ProjectReference Include="..\..\Admin\ThingsGateway.Admin.Razor\ThingsGateway.Admin.Razor.csproj" /> | ||||
|   | ||||
| @@ -274,7 +274,24 @@ public class OpcUaMaster : IDisposable | ||||
|         } | ||||
|  | ||||
|         m_session.AddSubscription(m_subscription); | ||||
|         try | ||||
|         { | ||||
|             await m_subscription.CreateAsync(cancellationToken).ConfigureAwait(false); | ||||
|             await Task.Delay(100, cancellationToken).ConfigureAwait(false); // allow for subscription to be finished on server? | ||||
|         } | ||||
|         catch (Exception) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 await m_subscription.CreateAsync(cancellationToken).ConfigureAwait(false); | ||||
|                 await Task.Delay(100, cancellationToken).ConfigureAwait(false); // allow for subscription to be finished on server? | ||||
|             } | ||||
|             catch (Exception) | ||||
|             { | ||||
|                 m_session.RemoveSubscription(m_subscription); | ||||
|                 throw; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         m_subscription.AddItems(monitoredItems); | ||||
|         foreach (var item in m_subscription.MonitoredItems.Where(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode))) | ||||
|   | ||||
							
								
								
									
										274
									
								
								src/Plugin/ThingsGateway.Plugin.DB/Common/Helper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								src/Plugin/ThingsGateway.Plugin.DB/Common/Helper.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,274 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://thingsgateway.cn/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
|  | ||||
| using ThingsGateway.NewLife.Extension; | ||||
| using ThingsGateway.Plugin.QuestDB; | ||||
| using ThingsGateway.Plugin.SqlDB; | ||||
|  | ||||
| namespace ThingsGateway.Plugin.DB; | ||||
|  | ||||
| internal static class Helper | ||||
| { | ||||
|     #region | ||||
|     public static SQLHistoryValue AdaptSQLHistoryValue(this VariableRuntime src) | ||||
|     { | ||||
|         var dest = new SQLHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = GetValue(src.Value); | ||||
|         dest.CreateTime = DateTime.Now; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<SQLHistoryValue> AdaptListSQLHistoryValue(this IEnumerable<VariableRuntime> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptSQLHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static SQLHistoryValue AdaptSQLHistoryValue(this VariableBasicData src) | ||||
|     { | ||||
|  | ||||
|  | ||||
|         var dest = new SQLHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = GetValue(src.Value); | ||||
|         dest.CreateTime = DateTime.Now; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<SQLHistoryValue> AdaptListSQLHistoryValue(this IEnumerable<VariableBasicData> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptSQLHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static SQLNumberHistoryValue AdaptSQLNumberHistoryValue(this VariableRuntime src) | ||||
|     { | ||||
|         var dest = new SQLNumberHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = src.Value.GetType() == typeof(bool) ? ConvertUtility.Convert.ToBoolean(src.Value, false) ? 1 : 0 : ConvertUtility.Convert.ToDecimal(src.Value, 0); | ||||
|         dest.CreateTime = DateTime.Now; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<SQLNumberHistoryValue> AdaptListSQLNumberHistoryValue(this IEnumerable<VariableRuntime> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptSQLNumberHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static SQLNumberHistoryValue AdaptSQLNumberHistoryValue(this VariableBasicData src) | ||||
|     { | ||||
|  | ||||
|  | ||||
|         var dest = new SQLNumberHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = src.Value.GetType() == typeof(bool) ? ConvertUtility.Convert.ToBoolean(src.Value, false) ? 1 : 0 : ConvertUtility.Convert.ToDecimal(src.Value, 0); | ||||
|         dest.CreateTime = DateTime.Now; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<SQLNumberHistoryValue> AdaptListSQLNumberHistoryValue(this IEnumerable<VariableBasicData> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptSQLNumberHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     public static SQLRealValue AdaptSQLRealValue(this VariableBasicData src) | ||||
|     { | ||||
|         var dest = new SQLRealValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = GetValue(src.Value); | ||||
|         dest.CollectTime = src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|  | ||||
|     public static List<SQLRealValue> AdaptListSQLRealValue(this IEnumerable<VariableBasicData> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptSQLRealValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     public static SQLRealValue AdaptSQLRealValue(this VariableRuntime src) | ||||
|     { | ||||
|         var dest = new SQLRealValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = GetValue(src.Value); | ||||
|         dest.CollectTime = src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|  | ||||
|     public static List<SQLRealValue> AdaptListSQLRealValue(this IEnumerable<VariableRuntime> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptSQLRealValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region | ||||
|     public static QuestDBHistoryValue AdaptQuestDBHistoryValue(this VariableRuntime src) | ||||
|     { | ||||
|         var dest = new QuestDBHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = GetValue(src.Value); | ||||
|         dest.CreateTime = DateTime.UtcNow; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<QuestDBHistoryValue> AdaptListQuestDBHistoryValue(this IEnumerable<VariableRuntime> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptQuestDBHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static QuestDBHistoryValue AdaptQuestDBHistoryValue(this VariableBasicData src) | ||||
|     { | ||||
|  | ||||
|  | ||||
|         var dest = new QuestDBHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = GetValue(src.Value); | ||||
|         dest.CreateTime = DateTime.UtcNow; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<QuestDBHistoryValue> AdaptListQuestDBHistoryValue(this IEnumerable<VariableBasicData> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptQuestDBHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static QuestDBNumberHistoryValue AdaptQuestDBNumberHistoryValue(this VariableRuntime src) | ||||
|     { | ||||
|         var dest = new QuestDBNumberHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = src.Value.GetType() == typeof(bool) ? ConvertUtility.Convert.ToBoolean(src.Value, false) ? 1 : 0 : ConvertUtility.Convert.ToDecimal(src.Value, 0); | ||||
|         dest.CreateTime = DateTime.UtcNow; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<QuestDBNumberHistoryValue> AdaptListQuestDBNumberHistoryValue(this IEnumerable<VariableRuntime> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptQuestDBNumberHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static QuestDBNumberHistoryValue AdaptQuestDBNumberHistoryValue(this VariableBasicData src) | ||||
|     { | ||||
|  | ||||
|  | ||||
|         var dest = new QuestDBNumberHistoryValue(); | ||||
|         dest.Id = src.Id; | ||||
|         dest.Value = src.Value.GetType() == typeof(bool) ? ConvertUtility.Convert.ToBoolean(src.Value, false) ? 1 : 0 : ConvertUtility.Convert.ToDecimal(src.Value, 0); | ||||
|         dest.CreateTime = DateTime.UtcNow; | ||||
|  | ||||
|         dest.CollectTime = src.CollectTime < DateTime.MinValue ? UtcTime1970 : src.CollectTime; | ||||
|         dest.DeviceName = src.DeviceName; | ||||
|         dest.IsOnline = src.IsOnline; | ||||
|         dest.Name = src.Name; | ||||
|         return dest; | ||||
|     } | ||||
|     public static List<QuestDBNumberHistoryValue> AdaptListQuestDBNumberHistoryValue(this IEnumerable<VariableBasicData> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptQuestDBNumberHistoryValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     static DateTime UtcTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||||
|  | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     private static string GetValue(object src) | ||||
|     { | ||||
|         if (src != null) | ||||
|         { | ||||
|             if (src is string strValue) | ||||
|             { | ||||
|                 return strValue; | ||||
|             } | ||||
|             else if (src is bool boolValue) | ||||
|             { | ||||
|                 return boolValue ? "1" : "0"; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return JToken.FromObject(src).ToString(); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return string.Empty; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| using ThingsGateway.Debug; | ||||
| using ThingsGateway.Foundation; | ||||
| @@ -70,39 +68,6 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode | ||||
|     protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken) | ||||
|     { | ||||
|         _db = BusinessDatabaseUtil.GetDb(_driverPropertys.DbType, _driverPropertys.BigTextConnectStr); | ||||
|         _config = new TypeAdapterConfig(); | ||||
|         DateTime utcTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||||
|         _config.ForType<VariableRuntime, QuestDBHistoryValue>() | ||||
|             //.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) | ||||
|             .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|             .Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty) | ||||
|             .Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? utcTime : src.CollectTime)//注意sqlsugar插入时无时区,直接utc时间 | ||||
|             .Map(dest => dest.CreateTime, (src) => DateTime.UtcNow) | ||||
|             ;//注意sqlsugar插入时无时区,直接utc时间 | ||||
|         _config.ForType<VariableBasicData, QuestDBHistoryValue>() | ||||
|     //.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) | ||||
|     .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|     .Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty) | ||||
|     .Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? utcTime : src.CollectTime)//注意sqlsugar插入时无时区,直接utc时间 | ||||
|     .Map(dest => dest.CreateTime, (src) => DateTime.UtcNow) | ||||
|     ;//注意sqlsugar插入时无时区,直接utc时间 | ||||
|  | ||||
|  | ||||
|  | ||||
|         _config.ForType<VariableRuntime, QuestDBNumberHistoryValue>() | ||||
|           //.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) | ||||
|           .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|           .Map(dest => dest.Value, src => ConvertUtility.Convert.ToDecimal(src.Value, 0)) | ||||
|           .Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? utcTime : src.CollectTime)//注意sqlsugar插入时无时区,直接utc时间 | ||||
|           .Map(dest => dest.CreateTime, (src) => DateTime.UtcNow) | ||||
|           ;//注意sqlsugar插入时无时区,直接utc时间 | ||||
|         _config.ForType<VariableBasicData, QuestDBNumberHistoryValue>() | ||||
|     //.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) | ||||
|     .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|     .Map(dest => dest.Value, src => ConvertUtility.Convert.ToDecimal(src.Value, 0)) | ||||
|     .Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? utcTime : src.CollectTime)//注意sqlsugar插入时无时区,直接utc时间 | ||||
|     .Map(dest => dest.CreateTime, (src) => DateTime.UtcNow) | ||||
|     ;//注意sqlsugar插入时无时区,直接utc时间 | ||||
|  | ||||
|         await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false); | ||||
|     } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.Diagnostics; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
| @@ -25,13 +23,12 @@ namespace ThingsGateway.Plugin.QuestDB; | ||||
| /// </summary> | ||||
| public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableModel<VariableBasicData> | ||||
| { | ||||
|     private TypeAdapterConfig _config; | ||||
|  | ||||
|     protected override ValueTask<OperResult> UpdateVarModel(IEnumerable<CacheDBItem<VariableBasicData>> item, CancellationToken cancellationToken) | ||||
|     { | ||||
|         return UpdateVarModel(item.Select(a => a.Value).OrderBy(a => a.Id), cancellationToken); | ||||
|     } | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -47,7 +44,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (_driverPropertys.GroupUpdate) | ||||
|         { | ||||
| @@ -78,7 +75,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode | ||||
|         if (_driverPropertys.GroupUpdate && variable.BusinessGroupUpdateTrigger && !variable.BusinessGroup.IsNullOrEmpty() && VariableRuntimeGroups.TryGetValue(variable.BusinessGroup, out var variableRuntimeGroup)) | ||||
|         { | ||||
|  | ||||
|             AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>(_config))); | ||||
|             AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|         } | ||||
|         else | ||||
| @@ -120,10 +117,12 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode | ||||
|                 var stringData = dbInserts.Where(a => (!a.IsNumber && a.Value is not bool)); | ||||
|                 var numberData = dbInserts.Where(a => (a.IsNumber || a.Value is bool)); | ||||
|  | ||||
|                 if (numberData.Any()) | ||||
|                 { | ||||
|  | ||||
|                     Stopwatch stopwatch = new(); | ||||
|                     stopwatch.Start(); | ||||
|                 var data = numberData.Adapt<List<QuestDBNumberHistoryValue>>(_config); | ||||
|                     var data = numberData.AdaptListQuestDBNumberHistoryValue(); | ||||
|                     var result = await _db.Insertable(data).AS(_driverPropertys.NumberTableName).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);//不要加分表 | ||||
|                     stopwatch.Stop(); | ||||
|  | ||||
| @@ -132,12 +131,15 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode | ||||
|                     { | ||||
|                         LogMessage?.Trace($"TableName:{_driverPropertys.NumberTableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|  | ||||
|  | ||||
|                 stopwatch.Restart(); | ||||
|                 var strdata = stringData.Adapt<List<QuestDBHistoryValue>>(_config); | ||||
|                 result = await _db.Insertable(strdata).AS(_driverPropertys.StringTableName).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);//不要加分表 | ||||
|                 if (stringData.Any()) | ||||
|                 { | ||||
|                     Stopwatch stopwatch = new(); | ||||
|                     stopwatch.Start(); | ||||
|                     var data = stringData.AdaptListQuestDBHistoryValue(); | ||||
|                     var result = await _db.Insertable(data).AS(_driverPropertys.StringTableName).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);//不要加分表 | ||||
|                     stopwatch.Stop(); | ||||
|  | ||||
|                     //var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync().ConfigureAwait(false); | ||||
| @@ -146,6 +148,7 @@ public partial class QuestDBProducer : BusinessBaseWithCacheIntervalVariableMode | ||||
|                         LogMessage?.Trace($"TableName:{_driverPropertys.StringTableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|  | ||||
|             return OperResult.Success; | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
|  | ||||
| using System.ComponentModel.DataAnnotations; | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| using ThingsGateway.Debug; | ||||
| using ThingsGateway.Foundation; | ||||
| @@ -159,31 +157,6 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|     { | ||||
|         _db = SqlDBBusinessDatabaseUtil.GetDb(_driverPropertys); | ||||
|  | ||||
|         _config = new TypeAdapterConfig(); | ||||
|         _config.ForType<VariableRuntime, SQLHistoryValue>() | ||||
|             //.Map(dest => dest.Id, (src) =>CommonUtils.GetSingleId()) | ||||
|             .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|             .Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty) | ||||
|             .Map(dest => dest.CreateTime, (src) => DateTime.Now); | ||||
|  | ||||
|         _config.ForType<VariableBasicData, SQLHistoryValue>() | ||||
|     //.Map(dest => dest.Id, (src) =>CommonUtils.GetSingleId()) | ||||
|     .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|     .Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty) | ||||
|     .Map(dest => dest.CreateTime, (src) => DateTime.Now); | ||||
|  | ||||
|         _config.ForType<VariableRuntime, SQLNumberHistoryValue>() | ||||
|            //.Map(dest => dest.Id, (src) =>CommonUtils.GetSingleId()) | ||||
|            .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|            .Map(dest => dest.Value, src => ConvertUtility.Convert.ToDecimal(src.Value, 0)) | ||||
|            .Map(dest => dest.CreateTime, (src) => DateTime.Now); | ||||
|  | ||||
|         _config.ForType<VariableBasicData, SQLNumberHistoryValue>() | ||||
|     //.Map(dest => dest.Id, (src) =>CommonUtils.GetSingleId()) | ||||
|     .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|     .Map(dest => dest.Value, src => ConvertUtility.Convert.ToDecimal(src.Value, 0)) | ||||
|     .Map(dest => dest.CreateTime, (src) => DateTime.Now); | ||||
|  | ||||
|         if (_businessPropertyWithCacheInterval.BusinessUpdateEnum == BusinessUpdateEnum.Interval && _driverPropertys.IsReadDB) | ||||
|         { | ||||
|             GlobalData.VariableValueChangeEvent += VariableValueChange; | ||||
| @@ -193,6 +166,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public override Task AfterVariablesChangedAsync(CancellationToken cancellationToken) | ||||
|     { | ||||
|         RealTimeVariables.Clear(); | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
| using System.Diagnostics; | ||||
|  | ||||
| @@ -26,7 +24,6 @@ namespace ThingsGateway.Plugin.SqlDB; | ||||
| /// </summary> | ||||
| public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel<VariableBasicData> | ||||
| { | ||||
|     private TypeAdapterConfig _config; | ||||
|     private volatile bool _initRealData; | ||||
|     private ConcurrentDictionary<long, VariableBasicData> RealTimeVariables { get; } = new ConcurrentDictionary<long, VariableBasicData>(); | ||||
|  | ||||
| @@ -34,7 +31,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|     { | ||||
|         return UpdateVarModel(item.Select(a => a.Value).OrderBy(a => a.Id), cancellationToken); | ||||
|     } | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (_driverPropertys.IsHistoryDB) | ||||
|         { | ||||
| @@ -53,7 +50,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|         return UpdateVarModel(item, cancellationToken); | ||||
|     } | ||||
|  | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (_driverPropertys.GroupUpdate) | ||||
|         { | ||||
| @@ -85,7 +82,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|             if (_driverPropertys.GroupUpdate && variable.BusinessGroupUpdateTrigger && !variable.BusinessGroup.IsNullOrEmpty() && VariableRuntimeGroups.TryGetValue(variable.BusinessGroup, out var variableRuntimeGroup)) | ||||
|             { | ||||
|  | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>(_config))); | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|             } | ||||
|             else | ||||
| @@ -136,10 +133,11 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|                 var stringData = dbInserts.Where(a => (!a.IsNumber && a.Value is not bool)); | ||||
|                 var numberData = dbInserts.Where(a => (a.IsNumber || a.Value is bool)); | ||||
|  | ||||
|  | ||||
|                 if (numberData.Any()) | ||||
|                 { | ||||
|                     Stopwatch stopwatch = new(); | ||||
|                     stopwatch.Start(); | ||||
|                 var data = numberData.Adapt<List<SQLNumberHistoryValue>>(_config); | ||||
|                     var data = numberData.AdaptListSQLNumberHistoryValue(); | ||||
|                     var result = await _db.Fastest<SQLNumberHistoryValue>().PageSize(50000).SplitTable().BulkCopyAsync(data).ConfigureAwait(false); | ||||
|                     stopwatch.Stop(); | ||||
|  | ||||
| @@ -149,11 +147,14 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|                         LogMessage?.Trace($"TableName:{_driverPropertys.NumberTableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 stopwatch.Restart(); | ||||
|                 var strdata = stringData.Adapt<List<SQLHistoryValue>>(_config); | ||||
|                 result = await _db.Fastest<SQLHistoryValue>().PageSize(50000).SplitTable().BulkCopyAsync(strdata).ConfigureAwait(false); | ||||
|                 if (stringData.Any()) | ||||
|                 { | ||||
|                     Stopwatch stopwatch = new(); | ||||
|                     stopwatch.Start(); | ||||
|                     var data = stringData.AdaptListSQLHistoryValue(); | ||||
|                     var result = await _db.Fastest<SQLHistoryValue>().PageSize(50000).SplitTable().BulkCopyAsync(data).ConfigureAwait(false); | ||||
|                     stopwatch.Stop(); | ||||
|  | ||||
|                     //var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync().ConfigureAwait(false); | ||||
| @@ -161,6 +162,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|                     { | ||||
|                         LogMessage?.Trace($"TableName:{_driverPropertys.StringTableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             } | ||||
| @@ -197,7 +199,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|                     Stopwatch stopwatch = new(); | ||||
|                     stopwatch.Start(); | ||||
|                     var ids = (await _db.Queryable<SQLRealValue>().AS(_driverPropertys.ReadDBTableName).Select(a => a.Id).ToListAsync(cancellationToken).ConfigureAwait(false)).ToHashSet(); | ||||
|                     var InsertData = IdVariableRuntimes.Where(a => !ids.Contains(a.Key)).Select(a => a.Value).Adapt<List<SQLRealValue>>(); | ||||
|                     var InsertData = IdVariableRuntimes.Where(a => !ids.Contains(a.Key)).Select(a => a.Value).AdaptListSQLRealValue(); | ||||
|                     var result = await _db.Fastest<SQLRealValue>().AS(_driverPropertys.ReadDBTableName).PageSize(100000).BulkCopyAsync(InsertData).ConfigureAwait(false); | ||||
|                     _initRealData = true; | ||||
|                     stopwatch.Stop(); | ||||
| @@ -212,7 +214,7 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariableModel< | ||||
|                         Stopwatch stopwatch = new(); | ||||
|                         stopwatch.Start(); | ||||
|  | ||||
|                         var data = datas.Adapt<List<SQLRealValue>>(_config); | ||||
|                         var data = datas.AdaptListSQLRealValue(); | ||||
|                         var result = await _db.Fastest<SQLRealValue>().AS(_driverPropertys.ReadDBTableName).PageSize(100000).BulkUpdateAsync(data).ConfigureAwait(false); | ||||
|  | ||||
|                         stopwatch.Stop(); | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| using ThingsGateway.Extension.Generic; | ||||
| using ThingsGateway.Foundation; | ||||
| @@ -29,7 +27,6 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheVariableModel<Histor | ||||
| { | ||||
|     internal readonly SqlHistoryAlarmProperty _driverPropertys = new(); | ||||
|     private readonly SqlHistoryAlarmVariableProperty _variablePropertys = new(); | ||||
|     private TypeAdapterConfig _config = new(); | ||||
|     public override Type DriverUIType => typeof(HistoryAlarmPage); | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
| @@ -40,12 +37,39 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheVariableModel<Histor | ||||
|  | ||||
|     private SqlSugarClient _db; | ||||
|  | ||||
|     public static HistoryAlarm AdaptHistoryAlarm(AlarmVariable src) | ||||
|     { | ||||
|         var target = new HistoryAlarm(); | ||||
|         target.Name = src.Name; | ||||
|         target.Description = src.Description; | ||||
|         target.CreateOrgId = src.CreateOrgId; | ||||
|         target.CreateUserId = src.CreateUserId; | ||||
|         target.DeviceId = src.DeviceId; | ||||
|         target.DeviceName = src.DeviceName; | ||||
|         target.RegisterAddress = src.RegisterAddress; | ||||
|         target.DataType = src.DataType; | ||||
|         target.AlarmCode = src.AlarmCode; | ||||
|         target.AlarmLimit = src.AlarmLimit; | ||||
|         target.AlarmText = src.AlarmText; | ||||
|         target.RecoveryCode = src.RecoveryCode; | ||||
|         target.AlarmTime = src.AlarmTime; | ||||
|         target.EventTime = src.EventTime; | ||||
|         target.AlarmType = src.AlarmType; | ||||
|         target.EventType = src.EventType; | ||||
|         target.Remark1 = src.Remark1; | ||||
|         target.Remark2 = src.Remark2; | ||||
|         target.Remark3 = src.Remark3; | ||||
|         target.Remark4 = src.Remark4; | ||||
|         target.Remark5 = src.Remark5; | ||||
|         target.Id = CommonUtils.GetSingleId(); | ||||
|         return target; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     protected override async Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken) | ||||
|     { | ||||
|         _db = BusinessDatabaseUtil.GetDb((DbType)_driverPropertys.DbType, _driverPropertys.BigTextConnectStr); | ||||
|  | ||||
|         _config.ForType<AlarmVariable, HistoryAlarm>().Map(dest => dest.Id, (src) => CommonUtils.GetSingleId()); | ||||
|         GlobalData.AlarmChangedEvent -= AlarmWorker_OnAlarmChanged; | ||||
|         GlobalData.ReadOnlyRealAlarmIdVariables?.ForEach(a => | ||||
|         { | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.Diagnostics; | ||||
|  | ||||
| using ThingsGateway.Foundation; | ||||
| @@ -38,7 +36,7 @@ public partial class SqlHistoryAlarm : BusinessBaseWithCacheVariableModel<Histor | ||||
|     { | ||||
|         if (CurrentDevice.Pause) | ||||
|             return; | ||||
|         AddQueueVarModel(new CacheDBItem<HistoryAlarm>(alarmVariable.Adapt<HistoryAlarm>(_config))); | ||||
|         AddQueueVarModel(new CacheDBItem<HistoryAlarm>(AdaptHistoryAlarm(alarmVariable))); | ||||
|     } | ||||
|     public override void PauseThread(bool pause) | ||||
|     { | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.Reflection; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| @@ -86,17 +84,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM | ||||
|         assemblies.Add(typeof(TDengineProvider).Assembly); | ||||
|         InstanceFactory.CustomAssemblies = assemblies.ToArray(); | ||||
|  | ||||
|         _config = new TypeAdapterConfig(); | ||||
|         _config.ForType<VariableRuntime, TDengineDBNumberHistoryValue>() | ||||
|             .Map(dest => dest.Value, src => ConvertUtility.Convert.ToDecimal(src.Value, 0)) | ||||
|             //.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) | ||||
|             .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|             ;//注意sqlsugar插入时无时区,直接utc时间 | ||||
|         _config.ForType<VariableBasicData, TDengineDBNumberHistoryValue>() | ||||
|     .Map(dest => dest.Value, src => ConvertUtility.Convert.ToDecimal(src.Value, 0)) | ||||
|     //.Map(dest => dest.Id, src => CommonUtils.GetSingleId()) | ||||
|     .Map(dest => dest.Id, src => src.Id)//Id更改为变量Id | ||||
|     ;//注意sqlsugar插入时无时区,直接utc时间 | ||||
|  | ||||
|         await base.InitChannelAsync(channel, cancellationToken).ConfigureAwait(false); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
|  | ||||
| using System.Diagnostics; | ||||
| @@ -30,14 +28,13 @@ namespace ThingsGateway.Plugin.TDengineDB; | ||||
| /// </summary> | ||||
| public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableModel<VariableBasicData> | ||||
| { | ||||
|     private TypeAdapterConfig _config; | ||||
|  | ||||
|     protected override ValueTask<OperResult> UpdateVarModel(IEnumerable<CacheDBItem<VariableBasicData>> item, CancellationToken cancellationToken) | ||||
|     { | ||||
|         return UpdateVarModel(item.Select(a => a.Value).OrderBy(a => a.Id), cancellationToken); | ||||
|     } | ||||
|  | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -52,7 +49,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM | ||||
|     { | ||||
|         return UpdateVarModel(item, cancellationToken); | ||||
|     } | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (_driverPropertys.GroupUpdate) | ||||
|         { | ||||
| @@ -82,7 +79,7 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM | ||||
|         if (_driverPropertys.GroupUpdate && variable.BusinessGroupUpdateTrigger && !variable.BusinessGroup.IsNullOrEmpty() && VariableRuntimeGroups.TryGetValue(variable.BusinessGroup, out var variableRuntimeGroup)) | ||||
|         { | ||||
|  | ||||
|             AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>(_config))); | ||||
|             AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|         } | ||||
|         else | ||||
| @@ -123,34 +120,10 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM | ||||
|                 var stringData = dbInserts.Where(a => (!a.IsNumber && a.Value is not bool)); | ||||
|                 var numberData = dbInserts.Where(a => (a.IsNumber || a.Value is bool)); | ||||
|  | ||||
|                 Stopwatch stopwatch = new(); | ||||
|                 stopwatch.Start(); | ||||
|                 //var result = await db.Insertable(dbInserts).SetTDengineChildTableName((stableName, it) => $"{stableName}_{it.DeviceName}_{it.Name}").ExecuteCommandAsync().ConfigureAwait(false);//不要加分表 | ||||
|  | ||||
|                 await InserableAsync(numberData, _driverPropertys.NumberTableNameLow, cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|                 stopwatch.Stop(); | ||||
|                 //var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync().ConfigureAwait(false); | ||||
|                 //if (result > 0) | ||||
|                 { | ||||
|                     LogMessage?.Trace($"TableName:{_driverPropertys.NumberTableNameLow},Count:{dbInserts.Count},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 stopwatch.Restart(); | ||||
|                 //var result = await db.Insertable(dbInserts).SetTDengineChildTableName((stableName, it) => $"{stableName}_{it.DeviceName}_{it.Name}").ExecuteCommandAsync().ConfigureAwait(false);//不要加分表 | ||||
|  | ||||
|                 await InserableAsync(stringData, _driverPropertys.StringTableNameLow, cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|                 stopwatch.Stop(); | ||||
|                 //var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync().ConfigureAwait(false); | ||||
|                 //if (result > 0) | ||||
|                 { | ||||
|                     LogMessage?.Trace($"TableName:{_driverPropertys.StringTableNameLow},Count:{dbInserts.Count},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|  | ||||
|             } | ||||
|             return OperResult.Success; | ||||
|         } | ||||
| @@ -162,6 +135,13 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM | ||||
|  | ||||
|     private async Task InserableAsync(IEnumerable<VariableBasicData> dbInserts, string tableName, CancellationToken cancellationToken) | ||||
|     { | ||||
|         if (!dbInserts.Any()) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         Stopwatch stopwatch = new(); | ||||
|         stopwatch.Start(); | ||||
|  | ||||
|         StringBuilder stringBuilder = new(); | ||||
|         stringBuilder.Append($"INSERT INTO"); | ||||
|         //(`id`,`createtime`,`collecttime`,`isonline`,`value`)  | ||||
| @@ -188,7 +168,15 @@ public partial class TDengineDBProducer : BusinessBaseWithCacheIntervalVariableM | ||||
|         stringBuilder.Append(';'); | ||||
|         stringBuilder.AppendLine(); | ||||
|  | ||||
|         await _db.Ado.ExecuteCommandAsync(stringBuilder.ToString(), default, cancellationToken: cancellationToken).ConfigureAwait(false); | ||||
|         var result = await _db.Ado.ExecuteCommandAsync(stringBuilder.ToString(), default, cancellationToken: cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
|  | ||||
|         stopwatch.Stop(); | ||||
|         //if (result > 0) | ||||
|         { | ||||
|             LogMessage?.Trace($"TableName:{tableName},Count:{result},watchTime:  {stopwatch.ElapsedMilliseconds} ms"); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private string GetValue(VariableBasicData src) | ||||
|     { | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
| using ThingsGateway.Foundation; | ||||
|  | ||||
| @@ -74,7 +72,7 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic | ||||
|         return UpdateVarModel(item, cancellationToken); | ||||
|     } | ||||
|  | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -85,7 +83,7 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic | ||||
|         base.VariableChange(variableRuntime, variable); | ||||
|     } | ||||
|  | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (!_businessPropertyWithCacheIntervalScript.VariableTopic.IsNullOrWhiteSpace()) | ||||
|         { | ||||
| @@ -121,7 +119,7 @@ public partial class Webhook : BusinessBaseWithCacheIntervalScript<VariableBasic | ||||
|             if (_driverPropertys.GroupUpdate && variable.BusinessGroupUpdateTrigger && !variable.BusinessGroup.IsNullOrEmpty() && VariableRuntimeGroups.TryGetValue(variable.BusinessGroup, out var variableRuntimeGroup)) | ||||
|             { | ||||
|  | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>())); | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|             } | ||||
|             else | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using Confluent.Kafka; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
| using ThingsGateway.Foundation; | ||||
| using ThingsGateway.Foundation.Extension.Generic; | ||||
| @@ -70,7 +68,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl | ||||
|         return UpdateVarModel(item, cancellationToken); | ||||
|     } | ||||
|  | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -80,7 +78,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl | ||||
|         UpdateVariable(variableRuntime, variable); | ||||
|         base.VariableChange(variableRuntime, variable); | ||||
|     } | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (!_businessPropertyWithCacheIntervalScript.VariableTopic.IsNullOrWhiteSpace()) | ||||
|         { | ||||
| @@ -91,7 +89,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl | ||||
|  | ||||
|                 foreach (var group in varGroup) | ||||
|                 { | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.Adapt<List<VariableBasicData>>())); | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.AdaptIEnumerableVariableBasicData())); | ||||
|                 } | ||||
|                 foreach (var variable in varList) | ||||
|                 { | ||||
| @@ -115,7 +113,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl | ||||
|             if (_driverPropertys.GroupUpdate && variable.BusinessGroupUpdateTrigger && !variable.BusinessGroup.IsNullOrEmpty() && VariableRuntimeGroups.TryGetValue(variable.BusinessGroup, out var variableRuntimeGroup)) | ||||
|             { | ||||
|  | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>())); | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|             } | ||||
|             else | ||||
| @@ -175,9 +173,9 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl | ||||
|     { | ||||
|         //保留消息 | ||||
|         //分解List,避免超出字节大小限制 | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).Adapt<List<VariableBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).Adapt<List<DeviceBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).AdaptIEnumerableVariableBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).AdaptListDeviceBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).ChunkBetter(_driverPropertys.SplitSize); | ||||
|         foreach (var item in varData) | ||||
|         { | ||||
|             if (!success) | ||||
|   | ||||
| @@ -12,8 +12,6 @@ using BootstrapBlazor.Components; | ||||
|  | ||||
| using CSScripting; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using MQTTnet; | ||||
|  | ||||
|  | ||||
| @@ -128,7 +126,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|     } | ||||
|  | ||||
|  | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -138,7 +136,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|         UpdateVariable(variableRuntime, variable); | ||||
|         base.VariableChange(variableRuntime, variable); | ||||
|     } | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (!_businessPropertyWithCacheIntervalScript.VariableTopic.IsNullOrWhiteSpace()) | ||||
|         { | ||||
| @@ -149,7 +147,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|  | ||||
|                 foreach (var group in varGroup) | ||||
|                 { | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.Adapt<List<VariableBasicData>>())); | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.AdaptIEnumerableVariableBasicData())); | ||||
|                 } | ||||
|                 foreach (var variable in varList) | ||||
|                 { | ||||
| @@ -173,7 +171,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|             if (_driverPropertys.GroupUpdate && variable.BusinessGroupUpdateTrigger && !variable.BusinessGroup.IsNullOrEmpty() && VariableRuntimeGroups.TryGetValue(variable.BusinessGroup, out var variableRuntimeGroup)) | ||||
|             { | ||||
|                 //获取组内全部变量 | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>())); | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| @@ -255,9 +253,9 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|     { | ||||
|         //保留消息 | ||||
|         //分解List,避免超出mqtt字节大小限制 | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).Adapt<List<VariableBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).Adapt<List<DeviceBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).AdaptIEnumerableVariableBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).AdaptListDeviceBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).ChunkBetter(_driverPropertys.SplitSize); | ||||
|         foreach (var item in varData) | ||||
|         { | ||||
|             if (!success) | ||||
|   | ||||
| @@ -10,8 +10,6 @@ | ||||
|  | ||||
| using CSScripting; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Hosting; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
|  | ||||
| @@ -84,7 +82,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|     { | ||||
|         return UpdateVarModel(item, cancellationToken); | ||||
|     } | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -94,7 +92,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|         UpdateVariable(variableRuntime, variable); | ||||
|         base.VariableChange(variableRuntime, variable); | ||||
|     } | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (!_businessPropertyWithCacheIntervalScript.VariableTopic.IsNullOrWhiteSpace()) | ||||
|         { | ||||
| @@ -105,7 +103,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|  | ||||
|                 foreach (var group in varGroup) | ||||
|                 { | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.Adapt<List<VariableBasicData>>())); | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.AdaptIEnumerableVariableBasicData())); | ||||
|                 } | ||||
|                 foreach (var variable in varList) | ||||
|                 { | ||||
| @@ -131,7 +129,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|  | ||||
|  | ||||
|                 //获取组内全部变量 | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>())); | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|             } | ||||
|             else | ||||
| @@ -253,9 +251,9 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableBa | ||||
|     { | ||||
|         //首次连接时的保留消息 | ||||
|         //分解List,避免超出mqtt字节大小限制 | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).Adapt<List<VariableBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).Adapt<List<DeviceBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).AdaptIEnumerableVariableBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).AdaptListDeviceBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).ChunkBetter(_driverPropertys.SplitSize); | ||||
|         List<MqttApplicationMessage> Messages = new(); | ||||
|  | ||||
|         if (!_businessPropertyWithCacheIntervalScript.VariableTopic.IsNullOrEmpty()) | ||||
|   | ||||
| @@ -206,22 +206,8 @@ public class OpcDaMaster : CollectBase | ||||
|         { | ||||
|             LogMessage?.LogWarning(ex); | ||||
|         } | ||||
|         if (VariableTasks.Count > 0) | ||||
|         { | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 item.Stop(); | ||||
|                 TaskSchedulerLoop.Remove(item); | ||||
|             } | ||||
|  | ||||
|             VariableTasks = AddVariableTask(cancellationToken); | ||||
|  | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 TaskSchedulerLoop.Add(item); | ||||
|                 item.Start(); | ||||
|             } | ||||
|         } | ||||
|         RefreshVariableTasks(cancellationToken); | ||||
|     } | ||||
|  | ||||
|     private Dictionary<string, List<VariableRuntime>> VariableAddresDicts { get; set; } = new(); | ||||
|   | ||||
| @@ -177,6 +177,9 @@ public class OpcUaMaster : CollectBase | ||||
|                                         LogMessage?.LogInformation($"AddSubscription index  {CurrentDevice.VariableSourceReads.IndexOf(variableSourceRead)}  done"); | ||||
|  | ||||
|                                     } | ||||
|  | ||||
|                                     await Task.Delay(100, cancellationToken).ConfigureAwait(false); // allow for subscription to be finished on server? | ||||
|  | ||||
|                                 } | ||||
|                                 LogMessage?.LogInformation("AddSubscriptions done"); | ||||
|                                 checkLog = true; | ||||
| @@ -184,7 +187,7 @@ public class OpcUaMaster : CollectBase | ||||
|                             catch (Exception ex) | ||||
|                             { | ||||
|                                 if (!checkLog) | ||||
|                                     LogMessage?.LogWarning(ex, "AddSubscriptions"); | ||||
|                                     LogMessage?.LogWarning(ex, "AddSubscriptions error"); | ||||
|                                 checkLog = false; | ||||
|                             } | ||||
|                             finally | ||||
| @@ -341,22 +344,8 @@ public class OpcUaMaster : CollectBase | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (VariableTasks.Count > 0) | ||||
|         { | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 item.Stop(); | ||||
|                 TaskSchedulerLoop.Remove(item); | ||||
|             } | ||||
|         RefreshVariableTasks(cancellationToken); | ||||
|  | ||||
|             VariableTasks = AddVariableTask(cancellationToken); | ||||
|  | ||||
|             foreach (var item in VariableTasks) | ||||
|             { | ||||
|                 TaskSchedulerLoop.Add(item); | ||||
|                 item.Start(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Dictionary<string, List<VariableRuntime>> VariableAddresDicts { get; set; } = new(); | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
|  | ||||
| using Opc.Ua; | ||||
| @@ -32,7 +30,6 @@ public class ThingsGatewayNodeManager : CustomNodeManager2 | ||||
| { | ||||
|     private const string ReferenceServer = "https://thingsgateway.cn/"; | ||||
|  | ||||
|     private readonly TypeAdapterConfig _config; | ||||
|     /// <summary> | ||||
|     /// OPC和网关对应表 | ||||
|     /// </summary> | ||||
| @@ -45,14 +42,25 @@ public class ThingsGatewayNodeManager : CustomNodeManager2 | ||||
|     public ThingsGatewayNodeManager(BusinessBase businessBase, IServerInternal server, ApplicationConfiguration configuration) : base(server, configuration, ReferenceServer) | ||||
|     { | ||||
|         _businessBase = businessBase; | ||||
|         _config = new TypeAdapterConfig(); | ||||
|         _config.ForType<IDBHistoryValue, DataValue>() | ||||
|         .Map(dest => dest.WrappedValue, (src) => new Variant(src.Value)) | ||||
|         .Map(dest => dest.SourceTimestamp, src => DateTime.SpecifyKind(src.CollectTime, DateTimeKind.Local)) | ||||
|         .Map(dest => dest.ServerTimestamp, src => DateTime.SpecifyKind(src.CreateTime, DateTimeKind.Local)) | ||||
|         .Map(dest => dest.StatusCode, (src) => | ||||
|         src.IsOnline ? StatusCodes.Good : StatusCodes.Bad); | ||||
|     } | ||||
|  | ||||
|     public DataValue AdaptDataValue(IDBHistoryValue src) | ||||
|     { | ||||
|         var dest = new DataValue(); | ||||
|         dest.WrappedValue = new Variant(src.Value); | ||||
|         dest.SourceTimestamp = DateTime.SpecifyKind(src.CollectTime, DateTimeKind.Local); | ||||
|         dest.ServerTimestamp = DateTime.SpecifyKind(src.CreateTime, DateTimeKind.Local); | ||||
|         dest.StatusCode = src.IsOnline ? StatusCodes.Good : StatusCodes.Bad; | ||||
|         dest.Value = src.Value; | ||||
|         return dest; | ||||
|     } | ||||
|     public List<DataValue> AdaptListDataValue(IEnumerable<IDBHistoryValue> src) | ||||
|     { | ||||
|         return Enumerable.ToList( | ||||
|                 Enumerable.Select(src, x => AdaptDataValue(x)) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     ConcurrentList<IDriver>? dbDrivers; | ||||
|     internal FolderState rootFolder; | ||||
|  | ||||
| @@ -182,7 +190,7 @@ public class ThingsGatewayNodeManager : CustomNodeManager2 | ||||
|  | ||||
|                 if (data.Count > 0) | ||||
|                 { | ||||
|                     var hisDataValue = data.Adapt<List<DataValue>>(_config); | ||||
|                     var hisDataValue = AdaptListDataValue(data); | ||||
|                     HistoryData hisData = new(); | ||||
|                     hisData.DataValues.AddRange(hisDataValue); | ||||
|                     errors[i] = StatusCodes.Good; | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Localization; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| @@ -82,7 +80,7 @@ public partial class OpcUaServer : BusinessBase | ||||
|  | ||||
|         IdVariableRuntimes.ForEach(a => | ||||
|         { | ||||
|             VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|             VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|         }); | ||||
|  | ||||
|  | ||||
| @@ -166,7 +164,7 @@ public partial class OpcUaServer : BusinessBase | ||||
|                     connect_success = true; | ||||
|                     IdVariableRuntimes.ForEach(a => | ||||
|                     { | ||||
|                         VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                         VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|                     }); | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
| @@ -428,7 +426,7 @@ public partial class OpcUaServer : BusinessBase | ||||
|             { | ||||
|                 IdVariableRuntimes.ForEach(a => | ||||
|                 { | ||||
|                     VariableValueChange(a.Value, a.Value.Adapt<VariableBasicData>()); | ||||
|                     VariableValueChange(a.Value, a.Value.AdaptVariableBasicData()); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using RabbitMQ.Client; | ||||
|  | ||||
| using ThingsGateway.Extension.Generic; | ||||
| @@ -71,7 +69,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari | ||||
|         return UpdateVarModel(item, cancellationToken); | ||||
|     } | ||||
|  | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, List<VariableBasicData> variables) | ||||
|     protected override void VariableTimeInterval(IEnumerable<VariableRuntime> variableRuntimes, IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         TimeIntervalUpdateVariable(variables); | ||||
|         base.VariableTimeInterval(variableRuntimes, variables); | ||||
| @@ -81,7 +79,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari | ||||
|         UpdateVariable(variableRuntime, variable); | ||||
|         base.VariableChange(variableRuntime, variable); | ||||
|     } | ||||
|     private void TimeIntervalUpdateVariable(List<VariableBasicData> variables) | ||||
|     private void TimeIntervalUpdateVariable(IEnumerable<VariableBasicData> variables) | ||||
|     { | ||||
|         if (!_businessPropertyWithCacheIntervalScript.VariableTopic.IsNullOrWhiteSpace()) | ||||
|         { | ||||
| @@ -92,7 +90,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari | ||||
|  | ||||
|                 foreach (var group in varGroup) | ||||
|                 { | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.Adapt<List<VariableBasicData>>())); | ||||
|                     AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(group.AdaptIEnumerableVariableBasicData())); | ||||
|                 } | ||||
|                 foreach (var variable in varList) | ||||
|                 { | ||||
| @@ -117,7 +115,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari | ||||
|  | ||||
|             { | ||||
|                 //获取组内全部变量 | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.Adapt<List<VariableBasicData>>())); | ||||
|                 AddQueueVarModel(new CacheDBItem<List<VariableBasicData>>(variableRuntimeGroup.AdaptListVariableBasicData())); | ||||
|  | ||||
|             } | ||||
|             else | ||||
| @@ -177,9 +175,9 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari | ||||
|     { | ||||
|         //保留消息 | ||||
|         //分解List,避免超出字节大小限制 | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).Adapt<List<VariableBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).Adapt<List<DeviceBasicData>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var varData = IdVariableRuntimes.Select(a => a.Value).AdaptIEnumerableVariableBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var devData = CollectDevices?.Select(a => a.Value).AdaptListDeviceBasicData().ChunkBetter(_driverPropertys.SplitSize); | ||||
|         var alramData = GlobalData.ReadOnlyRealAlarmIdVariables.Select(a => a.Value).ChunkBetter(_driverPropertys.SplitSize); | ||||
|         foreach (var item in varData) | ||||
|         { | ||||
|             if (!success) | ||||
|   | ||||
| @@ -8,8 +8,6 @@ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
|  | ||||
| using ThingsGateway.Admin.Application; | ||||
| @@ -92,7 +90,7 @@ public partial class Synchronization : BusinessBase, IRpcDriver | ||||
|                     // 如果 online 为 true,表示设备在线 | ||||
|                     if (online) | ||||
|                     { | ||||
|                         var deviceRunTimes = CollectDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).Adapt<List<DeviceDataWithValue>>(); | ||||
|                         var deviceRunTimes = CollectDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).AdaptDeviceDataWithValue(); | ||||
|  | ||||
|                         foreach (var item in _tcpDmtpService.Clients) | ||||
|                         { | ||||
| @@ -129,7 +127,7 @@ public partial class Synchronization : BusinessBase, IRpcDriver | ||||
|                     // 如果 online 为 true,表示设备在线 | ||||
|                     if (online) | ||||
|                     { | ||||
|                         var deviceRunTimes = CollectDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).Adapt<List<DeviceDataWithValue>>(); | ||||
|                         var deviceRunTimes = CollectDevices.Where(a => a.Value.IsCollect == true).Select(a => a.Value).AdaptDeviceDataWithValue(); | ||||
|  | ||||
|                         // 将 GlobalData.CollectDevices 和 GlobalData.Variables 同步到从站 | ||||
|                         await _tcpDmtpClient.GetDmtpRpcActor().InvokeAsync( | ||||
|   | ||||
| @@ -67,9 +67,7 @@ | ||||
| 		<!--<PlatformTarget>x86</PlatformTarget>--> | ||||
| 	</PropertyGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<!--安装服务守护--> | ||||
| 	<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' "> | ||||
|  | ||||
|   | ||||
| @@ -63,9 +63,7 @@ | ||||
| 		<FrameworkReference Include="Microsoft.AspNetCore.App" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Microsoft.Data.Sqlite" Version="$(NET9Version)" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<Content Include="..\ThingsGateway.Server\Index\GatewayIndex.razor" Link="Index\GatewayIndex.razor" /> | ||||
|   | ||||
| @@ -11,8 +11,6 @@ | ||||
| #pragma warning disable CA2007 // 考虑对等待的任务调用 ConfigureAwait | ||||
| using BootstrapBlazor.Components; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.Extensions.Localization; | ||||
| @@ -95,7 +93,7 @@ public partial class Login | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             var model = loginModel.Adapt<LoginInput>(); | ||||
|             var model = loginModel.AdaptLoginInput(); | ||||
|             model.Password = DESEncryption.Encrypt(model.Password); | ||||
|  | ||||
|             try | ||||
|   | ||||
| @@ -39,7 +39,6 @@ public class Startup : AppStartup | ||||
| { | ||||
|     public void ConfigBlazorServer(IServiceCollection services) | ||||
|     { | ||||
|  | ||||
|         // 增加中文编码支持网页源码显示汉字 | ||||
|         services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All)); | ||||
|         //并发启动/停止host | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user