Compare commits
	
		
			68 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 8dc1c898a3 | ||
|   | 1ed35726b0 | ||
|   | 27fae9ebaa | ||
|   | b103f25c94 | ||
|   | abff450274 | ||
|   | c260736a11 | ||
|   | 166ac2307a | ||
|   | b21a4e1a4d | ||
|   | f7dc943fa3 | ||
|   | bfbd2693ec | ||
|   | 819e71c993 | ||
|   | 9fd0b489a2 | ||
|   | f5fe9f8dae | ||
|   | f9ffc18145 | ||
|   | 08db5b983a | ||
|   | 5b3b4c8c50 | ||
|   | 73f914ffc4 | ||
|   | d6bdd73ed6 | ||
|   | 7370ee7349 | ||
|   | 4574596bac | ||
|   | 4d16855e36 | ||
|   | 13a0d4d282 | ||
|   | b9cd06b829 | ||
|   | 5b460e8fa2 | ||
|   | 41087edf17 | ||
|   | 2afcc38e38 | ||
|   | e59ccce25f | ||
|   | d7425890e8 | ||
|   | a989a837fb | ||
|   | db1221da50 | ||
|   | cf794569ed | ||
|   | 51e5bbab0d | ||
|   | 2c197ed2b2 | ||
|   | d8fc6665b3 | ||
|   | c671a79822 | ||
|   | 9d93ce4c41 | ||
|   | a6d99fe227 | ||
|   | 923b8bca31 | ||
|   | e2c30d1c88 | ||
|   | b6d9f2a04e | ||
|   | 57306ea664 | ||
|   | cd7f3fd02f | ||
|   | 0482e077a8 | ||
|   | 5f986a45ca | ||
|   | ca7b49c0d5 | ||
|   | 52dd555e6c | ||
|   | 579b1a59f9 | ||
|   | 5299c5c4be | ||
|   | f7756bccef | ||
|   | a6b874d160 | ||
|   | 3e5fb3ddcf | ||
|   | 5e6bcb12d3 | ||
|   | 14303f1429 | ||
|   | 96711ba022 | ||
|   | cbfc0fdbdc | ||
|   | 6e81886c0e | ||
|   | 2d976bc132 | ||
|   | 57f6a476af | ||
|   | 8491ed296e | ||
|   | cd1288afdc | ||
|   | ec6c830cb0 | ||
|   | 2f86ccc4bf | ||
|   | 8ca445aec0 | ||
|   | 1e1f27c8a5 | ||
|   | 2b84bde367 | ||
|   | b52e58551d | ||
|   | 9aceed00bf | ||
|   | 58814f7f74 | 
| @@ -1,7 +1,7 @@ | ||||
| <Project> | ||||
| 	<PropertyGroup> | ||||
| 		<TargetFrameworks>net6.0;net7.0</TargetFrameworks> | ||||
| 		<Version>2.1.0.1</Version> | ||||
| 		<Version>2.1.0.14</Version> | ||||
| 		<Authors>Diego</Authors> | ||||
| 		<Product>ThingsGateway</Product> | ||||
| 		<Copyright>© 2023-present Diego</Copyright> | ||||
|   | ||||
| @@ -51,7 +51,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadOperateLogAsync([FromQuery] OperateLogInput input) | ||||
|     { | ||||
|         var memoryStream = await _operateLogService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"operateLog{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
| @@ -66,7 +65,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadVisitLogAsync([FromQuery] VisitLogInput input) | ||||
|     { | ||||
|         var memoryStream = await _visitLogService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"operateLog{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
|   | ||||
| @@ -88,8 +88,7 @@ public class AuthService : IAuthService | ||||
|         } | ||||
|  | ||||
|         var password = DESCEncryption.Decrypt(input.Password, DESCKeyConst.DESCKey);  // 解密 | ||||
|         var userInfo = await _userService.GetUserByAccountAsync(input.Account);//获取用户信息 | ||||
|         if (userInfo == null) throw Oops.Bah("用户不存在");//用户不存在 | ||||
|         var userInfo = await _userService.GetUserByAccountAsync(input.Account) ?? throw Oops.Bah("用户不存在");//获取用户信息 | ||||
|         if (userInfo.Password != password) throw Oops.Bah("账号密码错误");//账号密码错误 | ||||
|         return await LoginAsync(userInfo, input.Device); | ||||
|     } | ||||
|   | ||||
| @@ -66,6 +66,7 @@ public class OperateLogService : DbRepository<SysOperateLog>, IOperateLogService | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -92,6 +92,7 @@ public class VisitLogService : DbRepository<SysVisitLog>, IVisitLogService | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -30,7 +30,9 @@ public class BaseComponentBase : ComponentBase, IDisposable | ||||
|     /// </summary> | ||||
|     public virtual void Dispose() | ||||
|     { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// InvokeAsync(StateHasChanged) | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| <MSheet> | ||||
|     <MCard Flat Href=@CONFIG_COPYRIGHT_URL Target="_blank"> | ||||
|         <MLabel Style="background-color:inherit;" Class="text-subtltie-2">@CONFIG_COPYRIGHT</MLabel> | ||||
|         <MLabel Style="background-color:inherit;" Class="text-subtltie-2 ml-4">@Version</MLabel> | ||||
|         <MLabel Style="background-color:inherit;white-space: pre;" Class="text-subtltie-2 ml-4">@Version</MLabel> | ||||
|     </MCard> | ||||
| </MSheet> | ||||
|  | ||||
|   | ||||
| @@ -14,6 +14,8 @@ using Microsoft.AspNetCore.Components; | ||||
|  | ||||
| using System.Reflection; | ||||
|  | ||||
| using ThingsGateway.Admin.Core; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Blazor.Core; | ||||
| /// <summary> | ||||
| /// Foter | ||||
| @@ -40,7 +42,12 @@ public partial class Foter | ||||
|     /// <inheritdoc/> | ||||
|     protected override async Task OnParametersSetAsync() | ||||
|     { | ||||
|         Version = "v" + Assembly.GetExecutingAssembly().GetName().Version.ToString(); | ||||
|         var assembly = Assembly.GetEntryAssembly(); | ||||
|         if (assembly != null) | ||||
|         { | ||||
|             Version = $"v{assembly.GetName().Version}"; | ||||
|         } | ||||
|  | ||||
|         await base.OnParametersSetAsync(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -14,8 +14,8 @@ | ||||
| 	 | ||||
| 	<ItemGroup> | ||||
|  | ||||
| 		<PackageReference Include="Masa.Blazor" Version="1.0.2" /> | ||||
| 		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.10" /> | ||||
| 		<PackageReference Include="Masa.Blazor" Version="1.0.4" /> | ||||
| 		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.11" /> | ||||
|  | ||||
| 	</ItemGroup> | ||||
| 	 | ||||
|   | ||||
| @@ -282,6 +282,7 @@ public partial class AppDataTable<TItem, SearchItem, AddItem, EditItem> : IAppDa | ||||
|             { | ||||
|                 SearchModel.Size = PageItems.Total; | ||||
|             } | ||||
|             selectedItem = new List<TItem>(); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|   | ||||
| @@ -14,8 +14,7 @@ | ||||
| @using System.Linq.Expressions; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
|  | ||||
| @inject IConfigService ConfigService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -41,26 +41,26 @@ public partial class Config | ||||
|     MainLayout MainLayout { get; set; } | ||||
|     private Task AddCallAsync(ConfigAddInput input) | ||||
|     { | ||||
|         return ConfigService.AddAsync(input); | ||||
|         return App.GetService<ConfigService>().AddAsync(input); | ||||
|     } | ||||
|  | ||||
|     private Task DeleteCallAsync(IEnumerable<SysConfig> sysConfigs) | ||||
|     { | ||||
|         return ConfigService.DeleteAsync(sysConfigs.Select(a => a.Id).ToArray()); | ||||
|         return App.GetService<ConfigService>().DeleteAsync(sysConfigs.Select(a => a.Id).ToArray()); | ||||
|     } | ||||
|     private Task EditCallAsync(ConfigEditInput sysConfigs) | ||||
|     { | ||||
|         return ConfigService.EditAsync(sysConfigs); | ||||
|         return App.GetService<ConfigService>().EditAsync(sysConfigs); | ||||
|     } | ||||
|  | ||||
|     private async Task OnSaveAsync() | ||||
|     { | ||||
|         await ConfigService.EditBatchAsync(_sysConfig); | ||||
|         await App.GetService<ConfigService>().EditBatchAsync(_sysConfig); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|     private Task<SqlSugarPagedList<SysConfig>> QueryCallAsync(ConfigPageInput input) | ||||
|     { | ||||
|         return ConfigService.PageAsync(input); | ||||
|         return App.GetService<ConfigService>().PageAsync(input); | ||||
|     } | ||||
| } | ||||
| @@ -16,7 +16,7 @@ | ||||
| @using Masa.Blazor.Presets; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
| @inject IMenuService MenuService | ||||
|  | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inherits BaseComponentBase | ||||
|   | ||||
| @@ -29,14 +29,11 @@ public partial class Menu | ||||
|     long buttonParentId; | ||||
|     bool IsShowButtonList; | ||||
|     List<SysResource> MenuCatalog = new(); | ||||
|     [Inject] | ||||
|     IButtonService ButtonService { get; set; } | ||||
|  | ||||
|  | ||||
|     [CascadingParameter] | ||||
|     MainLayout MainLayout { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     IResourceService ResourceService { get; set; } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
| @@ -52,23 +49,23 @@ public partial class Menu | ||||
|     private async Task AddCallAsync(MenuAddInput input) | ||||
|     { | ||||
|         input.ParentId = search.ParentId; | ||||
|         await MenuService.AddAsync(input); | ||||
|         await App.GetService<MenuService>().AddAsync(input); | ||||
|         await NavChangeAsync(); | ||||
|     } | ||||
|     private async Task ButtonAddCallAsync(ButtonAddInput input) | ||||
|     { | ||||
|         input.ParentId = buttonParentId; | ||||
|         await ButtonService.AddAsync(input); | ||||
|         await App.GetService<ButtonService>().AddAsync(input); | ||||
|     } | ||||
|  | ||||
|     private Task ButtonDeleteCallAsync(IEnumerable<SysResource> input) | ||||
|     { | ||||
|         return ButtonService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         return App.GetService<ButtonService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|     } | ||||
|  | ||||
|     private Task ButtonEditCallAsync(ButtonEditInput input) | ||||
|     { | ||||
|         return ButtonService.EditAsync(input); | ||||
|         return App.GetService<ButtonService>().EditAsync(input); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -92,7 +89,7 @@ public partial class Menu | ||||
|     private async Task<SqlSugarPagedList<SysResource>> ButtonQueryCallAsync(ButtonPageInput input) | ||||
|     { | ||||
|         input.ParentId = buttonParentId; | ||||
|         var data = await ButtonService.PageAsync(input); | ||||
|         var data = await App.GetService<ButtonService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
|  | ||||
| @@ -103,13 +100,13 @@ public partial class Menu | ||||
|  | ||||
|     private async Task DeleteCallAsync(IEnumerable<SysResource> input) | ||||
|     { | ||||
|         await MenuService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<MenuService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         await NavChangeAsync(); | ||||
|  | ||||
|     } | ||||
|     private async Task EditCallAsync(MenuEditInput input) | ||||
|     { | ||||
|         await MenuService.EditAsync(input); | ||||
|         await App.GetService<MenuService>().EditAsync(input); | ||||
|         await NavChangeAsync(); | ||||
|  | ||||
|     } | ||||
| @@ -117,9 +114,9 @@ public partial class Menu | ||||
|     private async Task<List<SysResource>> GetMenuCatalogAsync() | ||||
|     { | ||||
|         //获取所有菜单 | ||||
|         List<SysResource> sysResources = await ResourceService.GetListByCategoryAsync(ResourceCategoryEnum.MENU); | ||||
|         List<SysResource> sysResources = await App.GetService<ResourceService>().GetListByCategoryAsync(ResourceCategoryEnum.MENU); | ||||
|         sysResources = sysResources.Where(it => it.TargetType == TargetTypeEnum.None).ToList(); | ||||
|         MenuCatalog = ResourceService.ResourceListToTree(sysResources); | ||||
|         MenuCatalog = App.GetService<ResourceService>().ResourceListToTree(sysResources); | ||||
|         return MenuCatalog; | ||||
|     } | ||||
|  | ||||
| @@ -130,7 +127,7 @@ public partial class Menu | ||||
|     } | ||||
|     private async Task<SqlSugarPagedList<SysResource>> QueryCallAsync(MenuPageInput input) | ||||
|     { | ||||
|         var data = await MenuService.TreeAsync(input); | ||||
|         var data = await App.GetService<MenuService>().TreeAsync(input); | ||||
|         return data.ToPagedList(input); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| @using Masa.Blazor.Presets; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
| @inject IOpenApiSessionService SessionService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -33,13 +33,13 @@ public partial class OpenApiSession | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("警告", "确定 ?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await SessionService.ExitSessionAsync(id); | ||||
|             await App.GetService<OpenApiSessionService>().ExitSessionAsync(id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Task<SqlSugarPagedList<OpenApiSessionOutput>> SessionQueryCallAsync(OpenApiSessionPageInput input) | ||||
|     { | ||||
|         return SessionService.PageAsync(input); | ||||
|         return App.GetService<OpenApiSessionService>().PageAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task ShowVerificatListAsync(List<VerificatInfo> verificatInfos) | ||||
| @@ -57,7 +57,7 @@ public partial class OpenApiSession | ||||
|             VerificatIds = verificats.Select(it => it.Id).ToList(), | ||||
|             Id = verificats.First().UserId | ||||
|         }; | ||||
|         await SessionService.ExitVerificatAsync(send); | ||||
|         await App.GetService<OpenApiSessionService>().ExitVerificatAsync(send); | ||||
|         _verificatInfos.RemoveWhere(it => send.VerificatIds.Contains(it.Id)); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
| @using Masa.Blazor.Presets; | ||||
| @inject IOpenApiUserService OpenApiUserService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -31,21 +31,20 @@ public partial class OpenApiUserR | ||||
|     bool IsShowRoles; | ||||
|     List<OpenApiPermissionTreeSelector> RolesChoice = new(); | ||||
|     string SearchName; | ||||
|     [Inject] | ||||
|     IRoleService SysRoleService { get; set; } | ||||
|  | ||||
|     private Task AddCallAsync(OpenApiUserAddInput input) | ||||
|     { | ||||
|         return OpenApiUserService.AddAsync(input); | ||||
|         return App.GetService<OpenApiUserService>().AddAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task DeleteCallAsync(IEnumerable<OpenApiUser> users) | ||||
|     { | ||||
|         await OpenApiUserService.DeleteAsync(users.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<OpenApiUserService>().DeleteAsync(users.Select(a => a.Id).ToArray()); | ||||
|     } | ||||
|  | ||||
|     private Task EditCallAsync(OpenApiUserEditInput users) | ||||
|     { | ||||
|         return OpenApiUserService.EditAsync(users); | ||||
|         return App.GetService<OpenApiUserService>().EditAsync(users); | ||||
|     } | ||||
|  | ||||
|     private List<OpenApiPermissionTreeSelector> GetRouters() | ||||
| @@ -61,7 +60,7 @@ public partial class OpenApiUserR | ||||
|             OpenApiUserGrantPermissionInput userGrantRoleInput = new(); | ||||
|             userGrantRoleInput.Id = ChoiceUserId; | ||||
|             userGrantRoleInput.PermissionList = RolesChoice.Select(it => it.ApiRoute).ToList(); | ||||
|             await OpenApiUserService.GrantRoleAsync(userGrantRoleInput); | ||||
|             await App.GetService<OpenApiUserService>().GrantRoleAsync(userGrantRoleInput); | ||||
|             IsShowRoles = false; | ||||
|             await _datatable?.QueryClickAsync(); | ||||
|         } | ||||
| @@ -73,7 +72,7 @@ public partial class OpenApiUserR | ||||
|     } | ||||
|     private Task<SqlSugarPagedList<OpenApiUser>> QueryCallAsync(OpenApiUserPageInput input) | ||||
|     { | ||||
|         return OpenApiUserService.PageAsync(input); | ||||
|         return App.GetService<OpenApiUserService>().PageAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task UserStatusChangeAsync(OpenApiUser context, bool enable) | ||||
| @@ -81,9 +80,9 @@ public partial class OpenApiUserR | ||||
|         try | ||||
|         { | ||||
|             if (enable) | ||||
|                 await OpenApiUserService.EnableUserAsync(context.Id); | ||||
|                 await App.GetService<OpenApiUserService>().EnableUserAsync(context.Id); | ||||
|             else | ||||
|                 await OpenApiUserService.DisableUserAsync(context.Id); | ||||
|                 await App.GetService<OpenApiUserService>().DisableUserAsync(context.Id); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
| @using System.Linq.Expressions; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
| @inject IOperateLogService OperateLogService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -44,7 +44,7 @@ public partial class Oplog | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("删除", "确定 ?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await OperateLogService.DeleteAsync(CategoryFilters.Select(it => it.Value).ToArray()); | ||||
|             await App.GetService<OperateLogService>().DeleteAsync(CategoryFilters.Select(it => it.Value).ToArray()); | ||||
|             await _datatable?.QueryClickAsync(); | ||||
|         } | ||||
|     } | ||||
| @@ -54,7 +54,7 @@ public partial class Oplog | ||||
|         input.Account = search.Account; | ||||
|         input.Category = search.Category; | ||||
|         input.ExeStatus = search.ExeStatus; | ||||
|         return OperateLogService.PageAsync(input); | ||||
|         return App.GetService<OperateLogService>().PageAsync(input); | ||||
|     } | ||||
|     [Inject] | ||||
|     AjaxService AjaxService { get; set; } | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| @using Masa.Blazor.Presets; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
| @inject IRoleService SysRoleService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -38,27 +38,23 @@ public partial class Role | ||||
|     [CascadingParameter] | ||||
|     MainLayout MainLayout { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     IResourceService ResourceService { get; set; } | ||||
|  | ||||
|  | ||||
|     private string SearchKey { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     ISysUserService SysUserService { get; set; } | ||||
|  | ||||
|     private Task AddCallAsync(RoleAddInput input) | ||||
|     { | ||||
|         return SysRoleService.AddAsync(input); | ||||
|         return App.GetService<RoleService>().AddAsync(input); | ||||
|     } | ||||
|     private async Task DeleteCallAsync(IEnumerable<SysRole> sysRoles) | ||||
|     { | ||||
|         await SysRoleService.DeleteAsync(sysRoles.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<RoleService>().DeleteAsync(sysRoles.Select(a => a.Id).ToArray()); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     private async Task EditCallAsync(RoleEditInput input) | ||||
|     { | ||||
|         await SysRoleService.EditAsync(input); | ||||
|         await App.GetService<RoleService>().EditAsync(input); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|     private async Task OnRoleHasResuorcesSaveAsync(ModalActionEventArgs args) | ||||
| @@ -69,7 +65,7 @@ public partial class Role | ||||
|             var data = new List<SysResource>(); | ||||
|             userGrantRoleInput.Id = ChoiceRoleId; | ||||
|             userGrantRoleInput.GrantInfoList = RoleHasResuorces; | ||||
|             await SysRoleService.GrantResourceAsync(userGrantRoleInput); | ||||
|             await App.GetService<RoleService>().GrantResourceAsync(userGrantRoleInput); | ||||
|             IsShowResuorces = false; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -86,7 +82,7 @@ public partial class Role | ||||
|             GrantUserInput userGrantRoleInput = new(); | ||||
|             userGrantRoleInput.Id = ChoiceRoleId; | ||||
|             userGrantRoleInput.GrantInfoList = UsersChoice.Select(it => it.Id).ToList(); | ||||
|             await SysRoleService.GrantUserAsync(userGrantRoleInput); | ||||
|             await App.GetService<RoleService>().GrantUserAsync(userGrantRoleInput); | ||||
|             IsShowUsers = false; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -99,19 +95,19 @@ public partial class Role | ||||
|  | ||||
|     private Task<SqlSugarPagedList<SysRole>> QueryCallAsync(RolePageInput input) | ||||
|     { | ||||
|         return SysRoleService.PageAsync(input); | ||||
|         return App.GetService<RoleService>().PageAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task ResuorceInitAsync() | ||||
|     { | ||||
|         ResTreeSelectors = (await ResourceService.GetRoleGrantResourceMenusAsync()); | ||||
|         RoleHasResuorces = (await SysRoleService.OwnResourceAsync(ChoiceRoleId))?.GrantInfoList; | ||||
|         ResTreeSelectors = (await App.GetService<ResourceService>().GetRoleGrantResourceMenusAsync()); | ||||
|         RoleHasResuorces = (await App.GetService<RoleService>().OwnResourceAsync(ChoiceRoleId))?.GrantInfoList; | ||||
|     } | ||||
|  | ||||
|     private async Task<List<UserSelectorOutput>> UserInitAsync() | ||||
|     { | ||||
|         AllUsers = await SysUserService.UserSelectorAsync(SearchKey); | ||||
|         var data = await SysRoleService.OwnUserAsync(ChoiceRoleId); | ||||
|         AllUsers = await App.GetService<SysUserService>().UserSelectorAsync(SearchKey); | ||||
|         var data = await App.GetService<RoleService>().OwnUserAsync(ChoiceRoleId); | ||||
|         UsersChoice = AllUsers.Where(a => data.Contains(a.Id)).ToList(); | ||||
|         return AllUsers; | ||||
|     } | ||||
|   | ||||
| @@ -15,8 +15,7 @@ | ||||
| @using Masa.Blazor.Presets; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
|  | ||||
| @inject ISessionService SessionService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -33,14 +33,14 @@ public partial class Session | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("警告", "确定 ?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await SessionService.ExitSessionAsync(id); | ||||
|             await App.GetService<SessionService>().ExitSessionAsync(id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private Task<SqlSugarPagedList<SessionOutput>> SessionQueryCallAsync(SessionPageInput input) | ||||
|     { | ||||
|         return SessionService.PageAsync(input); | ||||
|         return App.GetService<SessionService>().PageAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task ShowVerificatListAsync(List<VerificatInfo> verificatInfos) | ||||
| @@ -58,7 +58,7 @@ public partial class Session | ||||
|             VerificatIds = verificats.Select(it => it.Id).ToList(), | ||||
|             Id = verificats.First().UserId | ||||
|         }; | ||||
|         await SessionService.ExitVerificatAsync(send); | ||||
|         await App.GetService<SessionService>().ExitVerificatAsync(send); | ||||
|         _verificatInfos.RemoveWhere(it => send.VerificatIds.Contains(it.Id)); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| @using Masa.Blazor.Presets; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
| @inject ISpaService SpaService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inherits BaseComponentBase | ||||
|   | ||||
| @@ -27,23 +27,23 @@ public partial class Spa | ||||
|  | ||||
|     private async Task AddCallAsync(SpaAddInput input) | ||||
|     { | ||||
|         await SpaService.AddAsync(input); | ||||
|         await App.GetService<SpaService>().AddAsync(input); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|     private async Task DeleteCallAsync(IEnumerable<SysResource> input) | ||||
|     { | ||||
|         await SpaService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<SpaService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     private async Task EditCallAsync(SpaEditInput input) | ||||
|     { | ||||
|         await SpaService.EditAsync(input); | ||||
|         await App.GetService<SpaService>().EditAsync(input); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     private Task<SqlSugarPagedList<SysResource>> QueryCallAsync(SpaPageInput input) | ||||
|     { | ||||
|         return SpaService.PageAsync(input); | ||||
|         return App.GetService<SpaService>().PageAsync(input); | ||||
|     } | ||||
| } | ||||
| @@ -11,7 +11,7 @@ | ||||
| *@ | ||||
|  | ||||
| @page "/admin/user" | ||||
| @inject ISysUserService SysUserService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @using Masa.Blazor.Presets; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
|   | ||||
| @@ -34,21 +34,20 @@ public partial class User | ||||
|     [CascadingParameter] | ||||
|     MainLayout MainLayout { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     IRoleService SysRoleService { get; set; } | ||||
|  | ||||
|     private Task AddCallAsync(UserAddInput input) | ||||
|     { | ||||
|         return SysUserService.AddAsync(input); | ||||
|         return App.GetService<SysUserService>().AddAsync(input); | ||||
|     } | ||||
|     private async Task DeleteCallAsync(IEnumerable<SysUser> users) | ||||
|     { | ||||
|         await SysUserService.DeleteAsync(users.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<SysUserService>().DeleteAsync(users.Select(a => a.Id).ToArray()); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     private async Task EditCallAsync(UserEditInput users) | ||||
|     { | ||||
|         await SysUserService.EditAsync(users); | ||||
|         await App.GetService<SysUserService>().EditAsync(users); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
| @@ -59,7 +58,7 @@ public partial class User | ||||
|             UserGrantRoleInput userGrantRoleInput = new(); | ||||
|             userGrantRoleInput.Id = ChoiceUserId; | ||||
|             userGrantRoleInput.RoleIdList = RolesChoice.Select(it => it.Id).ToList(); | ||||
|             await SysUserService.GrantRoleAsync(userGrantRoleInput); | ||||
|             await App.GetService<SysUserService>().GrantRoleAsync(userGrantRoleInput); | ||||
|             IsShowRoles = false; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
| @@ -71,20 +70,20 @@ public partial class User | ||||
|     } | ||||
|     private Task<SqlSugarPagedList<SysUser>> QueryCallAsync(UserPageInput input) | ||||
|     { | ||||
|         return SysUserService.PageAsync(input); | ||||
|         return App.GetService<SysUserService>().PageAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task ResetPasswordAsync(SysUser sysUser) | ||||
|     { | ||||
|         await SysUserService.ResetPasswordAsync(sysUser.Id); | ||||
|         await App.GetService<SysUserService>().ResetPasswordAsync(sysUser.Id); | ||||
|         await PopupService.EnqueueSnackbarAsync(new("成功", AlertTypes.Success)); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     private async Task RoleInitAsync() | ||||
|     { | ||||
|         AllRoles = await SysRoleService.RoleSelectorAsync(); | ||||
|         var data = await SysRoleService.GetRoleIdListByUserIdAsync(ChoiceUserId); | ||||
|         AllRoles = await App.GetService<RoleService>().RoleSelectorAsync(); | ||||
|         var data = await App.GetService<RoleService>().GetRoleIdListByUserIdAsync(ChoiceUserId); | ||||
|         RolesChoice = AllRoles.Where(a => data.Contains(a.Id)).ToList(); | ||||
|     } | ||||
|     private async Task UserStatusChangeAsync(SysUser context, bool enable) | ||||
| @@ -92,9 +91,9 @@ public partial class User | ||||
|         try | ||||
|         { | ||||
|             if (enable) | ||||
|                 await SysUserService.EnableUserAsync(context.Id); | ||||
|                 await App.GetService<SysUserService>().EnableUserAsync(context.Id); | ||||
|             else | ||||
|                 await SysUserService.DisableUserAsync(context.Id); | ||||
|                 await App.GetService<SysUserService>().DisableUserAsync(context.Id); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|   | ||||
| @@ -33,8 +33,7 @@ public partial class UserCenter | ||||
|     [Inject] | ||||
|     NavigationManager NavigationManager { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     IUserCenterService UserCenterService { get; set; } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override async Task OnParametersSetAsync() | ||||
| @@ -48,14 +47,14 @@ public partial class UserCenter | ||||
|  | ||||
|     async Task OnDefaultRazorSaveAsync() | ||||
|     { | ||||
|         await UserCenterService.UpdateUserDefaultRazorAsync(UserManager.UserId, DefaultMenuId); | ||||
|         await App.GetService<UserCenterService>().UpdateUserDefaultRazorAsync(UserManager.UserId, DefaultMenuId); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|  | ||||
|     async Task OnShortcutSaveAsync() | ||||
|     { | ||||
|         await UserCenterService.UpdateWorkbenchAsync(_menusChoice); | ||||
|         await App.GetService<UserCenterService>().UpdateWorkbenchAsync(_menusChoice); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
| @@ -66,7 +65,7 @@ public partial class UserCenter | ||||
|         { | ||||
|             //验证成功,操作业务 | ||||
|             _passwordInfoInput.Id = UserResoures.CurrentUser.Id; | ||||
|             await UserCenterService.EditPasswordAsync(_passwordInfoInput); | ||||
|             await App.GetService<UserCenterService>().EditPasswordAsync(_passwordInfoInput); | ||||
|             await MainLayout.StateHasChangedAsync(); | ||||
|             await PopupService.EnqueueSnackbarAsync("成功,将重新登录", AlertTypes.Success); | ||||
|             await Task.Delay(2000); | ||||
| @@ -76,7 +75,7 @@ public partial class UserCenter | ||||
|  | ||||
|     async Task OnUpdateUserInfoAsync() | ||||
|     { | ||||
|         await UserCenterService.UpdateUserInfoAsync(_updateInfoInput); | ||||
|         await App.GetService<UserCenterService>().UpdateUserInfoAsync(_updateInfoInput); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|     } | ||||
|   | ||||
| @@ -14,8 +14,7 @@ | ||||
| @using System.Linq.Expressions; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Application; | ||||
|  | ||||
| @inject IVisitLogService VisitLogService | ||||
|   | ||||
| @namespace ThingsGateway.Admin.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -51,14 +51,14 @@ public partial class Vislog | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("删除", "确定 ?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await VisitLogService.DeleteAsync(CategoryFilters.Select(it => it.Value).ToArray()); | ||||
|             await App.GetService<VisitLogService>().DeleteAsync(CategoryFilters.Select(it => it.Value).ToArray()); | ||||
|             await _datatable?.QueryClickAsync(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<SysVisitLog>> QueryCallAsync(VisitLogPageInput input) | ||||
|     { | ||||
|         var data = await VisitLogService.PageAsync(input); | ||||
|         var data = await App.GetService<VisitLogService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
|     [Inject] | ||||
|   | ||||
| @@ -40,10 +40,6 @@ public partial class Login | ||||
|     AjaxService AjaxService { get; set; } | ||||
|  | ||||
|  | ||||
|     [Inject] | ||||
|     IAuthService AuthService { get; set; } | ||||
|  | ||||
|  | ||||
|  | ||||
|     string UserLogoUrl { get; set; } = BlazorResourceConst.ResourceUrl + "images/defaultUser.svg"; | ||||
|  | ||||
| @@ -65,12 +61,7 @@ public partial class Login | ||||
|         } | ||||
|     } | ||||
|     private PImageCaptcha captcha; | ||||
|     [Inject] | ||||
|     IUserCenterService UserCenterService { get; set; } | ||||
|     [Inject] | ||||
|     IResourceService ResourceService { get; set; } | ||||
|     [Inject] | ||||
|     ISysUserService SysUserService { get; set; } | ||||
|  | ||||
|     private async Task LoginAsync() | ||||
|     { | ||||
|         loginModel.ValidCodeReqNo = CaptchaInfo.ValidCodeReqNo; | ||||
| @@ -102,9 +93,9 @@ public partial class Login | ||||
|             { | ||||
|                 await PopupService.EnqueueSnackbarAsync(new("登录成功", AlertTypes.Success)); | ||||
|                 await Task.Delay(500); | ||||
|                 var userId = await SysUserService.GetIdByAccountAsync(loginModel.Account); | ||||
|                 var data = await UserCenterService.GetLoginDefaultRazorAsync(userId); | ||||
|                 var sameLevelMenus = await ResourceService.GetaMenuAndSpaListAsync(); | ||||
|                 var userId = await App.GetService<SysUserService>().GetIdByAccountAsync(loginModel.Account); | ||||
|                 var data = await App.GetService<UserCenterService>().GetLoginDefaultRazorAsync(userId); | ||||
|                 var sameLevelMenus = await App.GetService<ResourceService>().GetaMenuAndSpaListAsync(); | ||||
|                 if (NavigationManager.ToAbsoluteUri(NavigationManager.Uri).AbsolutePath == "/Login" || NavigationManager.ToAbsoluteUri(NavigationManager.Uri).AbsolutePath == "/") | ||||
|                     await AjaxService.GotoAsync(sameLevelMenus.FirstOrDefault(a => a.Id == data)?.Component ?? "index"); | ||||
|                 else | ||||
| @@ -141,12 +132,12 @@ public partial class Login | ||||
|  | ||||
|     private void GetCaptchaInfo() | ||||
|     { | ||||
|         CaptchaInfo = AuthService.GetCaptchaInfo(); | ||||
|         CaptchaInfo = App.GetService<AuthService>().GetCaptchaInfo(); | ||||
|     } | ||||
|  | ||||
|     private Task<string> RefreshCode() | ||||
|     { | ||||
|         CaptchaInfo = AuthService.GetCaptchaInfo(); | ||||
|         CaptchaInfo = App.GetService<AuthService>().GetCaptchaInfo(); | ||||
|         return Task.FromResult(CaptchaInfo.CodeValue); | ||||
|     } | ||||
| } | ||||
| @@ -86,7 +86,7 @@ public class OpenApiUser : BaseEntity | ||||
|     /// <summary> | ||||
|     /// 权限码集合 | ||||
|     /// </summary> | ||||
|     [SugarColumn(ColumnName = "PermissionCodeList", ColumnDescription = "权限json", IsJson = true, IsNullable = true)] | ||||
|     [SugarColumn(ColumnName = "PermissionCodeList", ColumnDescription = "权限json", ColumnDataType = StaticConfig.CodeFirst_BigString, IsJson = true, IsNullable = true)] | ||||
|     public List<string> PermissionCodeList { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -31,7 +31,7 @@ public class SysVerificat : PrimaryIdEntity | ||||
|     /// <summary> | ||||
|     /// 会话信息列表 | ||||
|     /// </summary> | ||||
|     [SugarColumn(IsJson = true)] | ||||
|     [SugarColumn(ColumnName = "VerificatInfos", ColumnDescription = "会话信息列表", ColumnDataType = StaticConfig.CodeFirst_BigString, IsJson = true, IsNullable = true)] | ||||
|     public List<VerificatInfo> VerificatInfos { get; set; } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -332,20 +332,51 @@ public static class ObjectExtensions | ||||
|     /// <returns></returns> | ||||
|     public static bool ToBoolean(this object value, bool defaultValue = false) => value?.ToString().ToUpper() switch | ||||
|     { | ||||
|         "0" or "FALSE" => false, | ||||
|         "1" or "TRUE" => true, | ||||
|         _ => defaultValue, | ||||
|     }; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ToLong | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static long ToLong(this object value, long defaultValue = 0) => value == null || value.ToString().IsNullOrEmpty() ? defaultValue : Int64.TryParse(value.ToString(), out var n) ? n : defaultValue; | ||||
|     public static long ToLong(this object value, long defaultValue = 0) | ||||
|     { | ||||
|         if (value == null || value.ToString().IsNullOrEmpty()) | ||||
|         { | ||||
|             return defaultValue; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (value is bool boolValue) | ||||
|             { | ||||
|                 return boolValue ? 1 : 0; | ||||
|             } | ||||
|             return Int64.TryParse(value.ToString(), out var n) ? n : defaultValue; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ToInt | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public static int ToInt(this object value, int defaultValue = 0) => value == null || value.ToString().IsNullOrEmpty() ? defaultValue : Int32.TryParse(value.ToString(), out var n) ? n : defaultValue; | ||||
|     public static int ToInt(this object value, int defaultValue = 0) | ||||
|     { | ||||
|         if (value == null || value.ToString().IsNullOrEmpty()) | ||||
|         { | ||||
|             return defaultValue; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (value is bool boolValue) | ||||
|             { | ||||
|                 return boolValue ? 1 : 0; | ||||
|             } | ||||
|             return int.TryParse(value.ToString(), out int n) ? n : defaultValue; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ToDecimal | ||||
|     /// </summary> | ||||
| @@ -357,7 +388,18 @@ public static class ObjectExtensions | ||||
|             return Double.IsNaN(d) ? defaultValue : (Decimal)d; | ||||
|         } | ||||
|         var str = value?.ToString(); | ||||
|         return str.IsNullOrEmpty() ? defaultValue : Decimal.TryParse(str, out var n) ? n : defaultValue; | ||||
|         if (str.IsNullOrEmpty()) | ||||
|         { | ||||
|             return defaultValue; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (value is bool boolValue) | ||||
|             { | ||||
|                 return boolValue ? 1 : 0; | ||||
|             } | ||||
|             return Decimal.TryParse(str, out var n) ? n : defaultValue; | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// ToDecimal | ||||
| @@ -370,7 +412,18 @@ public static class ObjectExtensions | ||||
|             return Double.IsNaN(d) ? defaultValue : (Double)d; | ||||
|         } | ||||
|         var str = value?.ToString(); | ||||
|         return str.IsNullOrEmpty() ? defaultValue : double.TryParse(str, out var n) ? n : defaultValue; | ||||
|         if (str.IsNullOrEmpty()) | ||||
|         { | ||||
|             return (double)defaultValue; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (value is bool boolValue) | ||||
|             { | ||||
|                 return boolValue ? 1 : 0; | ||||
|             } | ||||
|             return (double)(double.TryParse(str, out var n) ? n : defaultValue); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -12,6 +12,8 @@ | ||||
|  | ||||
| using SqlSugar; | ||||
|  | ||||
| using System.Linq.Expressions; | ||||
|  | ||||
| namespace ThingsGateway.Admin.Core; | ||||
|  | ||||
| /// <summary> | ||||
| @@ -55,12 +57,14 @@ public static class SqlSugarPageExtension | ||||
|     /// <param name="whereExpression"></param> | ||||
|     /// <returns></returns> | ||||
|     public static async Task<SqlSugarPagedList<TEntity>> ToPagedListAsync<TEntity>(this ISugarQueryable<TEntity> queryable, | ||||
|         int pageIndex, int pageSize, Func<TEntity, bool> whereExpression = null) | ||||
|         int pageIndex, int pageSize, Expression<Func<TEntity, bool>> whereExpression = null) | ||||
|     { | ||||
|  | ||||
|         RefAsync<int> totalCount = 0; | ||||
|         if (whereExpression != null) | ||||
|             queryable = queryable.Where(whereExpression); | ||||
|         var records = await queryable.ToPageListAsync(pageIndex, pageSize, totalCount); | ||||
|         records = whereExpression != null ? records.Where(whereExpression).ToList() : records; | ||||
|         //records = whereExpression != null ? records.Where(whereExpression).ToList() : records; | ||||
|         var totalPages = (int)Math.Ceiling(totalCount / (double)pageSize); | ||||
|         return new SqlSugarPagedList<TEntity> | ||||
|         { | ||||
|   | ||||
| @@ -9,10 +9,10 @@ | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 		<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="Furion.Pure" Version="4.8.8.41" /> | ||||
| 		<PackageReference Include="SqlSugarCore" Version="5.1.4.102" /> | ||||
| 		<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.8.43" /> | ||||
| 		<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.8.8.43" /> | ||||
| 		<PackageReference Include="Furion.Pure" Version="4.8.8.43" /> | ||||
| 		<PackageReference Include="SqlSugarCore" Version="5.1.4.105" /> | ||||
| 		<PackageReference Include="UAParser" Version="3.1.47" /> | ||||
| 		<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> | ||||
| 		<PackageReference Include="MiniExcel" Version="1.31.2" /> | ||||
|   | ||||
| @@ -1495,7 +1495,7 @@ | ||||
|             <param name="size"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SqlSugarPageExtension.ToPagedListAsync``1(SqlSugar.ISugarQueryable{``0},System.Int32,System.Int32,System.Func{``0,System.Boolean})"> | ||||
|         <member name="M:ThingsGateway.Admin.Core.SqlSugarPageExtension.ToPagedListAsync``1(SqlSugar.ISugarQueryable{``0},System.Int32,System.Int32,System.Linq.Expressions.Expression{System.Func{``0,System.Boolean}})"> | ||||
|             <summary> | ||||
|             SqlSugar分页扩展 | ||||
|             </summary> | ||||
|   | ||||
| @@ -61,7 +61,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadRpcLogAsync([FromQuery] RpcLogInput input) | ||||
|     { | ||||
|         var memoryStream = await _rpcLogService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"rpcLog{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
| @@ -76,7 +75,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadBackendLogAsync([FromQuery] BackendLogInput input) | ||||
|     { | ||||
|         var memoryStream = await _backendLogService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"backendLog{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
| @@ -93,7 +91,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadCollectDeviceAsync([FromQuery] CollectDeviceInput input) | ||||
|     { | ||||
|         var memoryStream = await _collectDeviceService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"collectDevice{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
| @@ -108,7 +105,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadUploadDeviceAsync([FromQuery] UploadDeviceInput input) | ||||
|     { | ||||
|         var memoryStream = await _uploadDeviceService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"uploadDevice{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
| @@ -123,7 +119,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadDeviceVariableAsync([FromQuery] DeviceVariableInput input) | ||||
|     { | ||||
|         var memoryStream = await _variableService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"deviceVariable{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
| @@ -138,7 +133,6 @@ public class FileController : IDynamicApiController | ||||
|     public async Task<IActionResult> DownloadMemoryVariableAsync([FromQuery] MemoryVariableInput input) | ||||
|     { | ||||
|         var memoryStream = await _variableService.ExportFileAsync(input); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         var data = new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") | ||||
|         { | ||||
|             FileDownloadName = $"memoryVariable{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx" | ||||
|   | ||||
| @@ -72,7 +72,7 @@ public class MemoryVariable : BaseEntity | ||||
|     /// <summary> | ||||
|     /// 变量额外属性Json,通常使用为上传设备,List属性 | ||||
|     /// </summary> | ||||
|     [SugarColumn(IsJson = true, ColumnName = "VariablePropertys", ColumnDescription = "变量属性Json", IsNullable = true)] | ||||
|     [SugarColumn(IsJson = true, ColumnName = "VariablePropertys", ColumnDataType = StaticConfig.CodeFirst_BigString, ColumnDescription = "变量属性Json", IsNullable = true)] | ||||
|     [IgnoreExcel] | ||||
|     public ConcurrentDictionary<long, List<DependencyProperty>> VariablePropertys { get; set; } = new(); | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -65,7 +65,7 @@ public class UploadDevice : BaseEntity | ||||
|     /// <summary> | ||||
|     /// 设备属性Json | ||||
|     /// </summary> | ||||
|     [SugarColumn(IsJson = true, ColumnName = "DevicePropertys", ColumnDescription = "设备属性Json", IsNullable = true)] | ||||
|     [SugarColumn(IsJson = true, ColumnName = "DevicePropertys", ColumnDataType = StaticConfig.CodeFirst_BigString, ColumnDescription = "设备属性Json", IsNullable = true)] | ||||
|     [IgnoreExcel] | ||||
|     public List<DependencyProperty> DevicePropertys { get; set; } | ||||
|  | ||||
|   | ||||
| @@ -22,29 +22,28 @@ namespace ThingsGateway.Application.Extensions; | ||||
| [System.Security.SecuritySafeCritical] | ||||
| public static class ExpressionEvaluatorExtensions | ||||
| { | ||||
|     private static readonly ExpressionEvaluator ExpressionEvaluator; | ||||
|     private static readonly GlobalDeviceData GlobalDeviceData; | ||||
|     static ExpressionEvaluatorExtensions() | ||||
|     { | ||||
|         ExpressionEvaluator = new(); | ||||
|         ExpressionEvaluator.PreEvaluateVariable += Evaluator_PreEvaluateVariable; | ||||
|  | ||||
|         GlobalDeviceData = ServiceHelper.Services.GetService<GlobalDeviceData>(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 计算表达式:例如:raw*100,raw为原始值 | ||||
|     /// </summary> | ||||
|     public static object GetExpressionsResult(this string expressions, object rawvalue) | ||||
|     public static object GetExpressionsResult(this string expressions, ExpressionEvaluator expressionEvaluator, object rawvalue) | ||||
|     { | ||||
|  | ||||
|         if (expressions.IsNullOrEmpty()) | ||||
|         { | ||||
|             return rawvalue; | ||||
|         } | ||||
|         ExpressionEvaluator.Variables = new Dictionary<string, object>() | ||||
|         expressionEvaluator.Variables = new Dictionary<string, object>() | ||||
|             { | ||||
|               { "Raw", rawvalue}, | ||||
|               { "raw", rawvalue}, | ||||
|             }; | ||||
|         var value = ExpressionEvaluator.Evaluate(expressions); | ||||
|         var value = expressionEvaluator.Evaluate(expressions); | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -97,11 +97,12 @@ public class HardwareInfoService : ISingleton | ||||
|        , TaskCreationOptions.LongRunning); | ||||
|  | ||||
|     } | ||||
|     private TGAPPInfo appInfo = new(); | ||||
|  | ||||
|     private APPInfo appInfo = new(); | ||||
|     /// <summary> | ||||
|     /// 运行信息获取 | ||||
|     /// </summary> | ||||
|     public TGAPPInfo APPInfo => appInfo; | ||||
|     public APPInfo APPInfo => appInfo; | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -113,8 +114,9 @@ public class HardwareInfoService : ISingleton | ||||
|         try | ||||
|         { | ||||
|             var url = "http://myip.ipip.net"; | ||||
|             var stream = await new HttpClient().GetStreamAsync(url); | ||||
|             var streamReader = new StreamReader(stream, Encoding.UTF8); | ||||
|             using var httpClient = new HttpClient(); | ||||
|             using var stream = await httpClient.GetStreamAsync(url); | ||||
|             using var streamReader = new StreamReader(stream, Encoding.UTF8); | ||||
|             var html = streamReader.ReadToEnd(); | ||||
|             return html.Replace("当前 IP:", "").Replace("来自于:", ""); | ||||
|         } | ||||
| @@ -127,7 +129,7 @@ public class HardwareInfoService : ISingleton | ||||
| } | ||||
|  | ||||
| /// <inheritdoc/> | ||||
| public class TGAPPInfo | ||||
| public class APPInfo | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 主机环境 | ||||
|   | ||||
| @@ -0,0 +1,197 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
|  | ||||
| using System.ComponentModel; | ||||
|  | ||||
| using ThingsGateway.Foundation; | ||||
|  | ||||
| namespace ThingsGateway.Application; | ||||
|  | ||||
| /// <summary> | ||||
| /// ManageGatewayConfig | ||||
| /// </summary> | ||||
| public class ManageGatewayConfig | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 启用 | ||||
|     /// </summary> | ||||
|     [Description("启用")] | ||||
|     public bool Enable { get; set; } | ||||
|     /// <summary> | ||||
|     /// MqttBrokerIP | ||||
|     /// </summary> | ||||
|     [Description("Mqtt-Tcp IP")] | ||||
|     public string MqttBrokerIP { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// MqttBrokerPort | ||||
|     /// </summary> | ||||
|     [Description("Mqtt-Tcp 端口")] | ||||
|     public int MqttBrokerPort { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// UserName | ||||
|     /// </summary> | ||||
|     [Description("Mqtt用户名")] | ||||
|     public string UserName { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Password | ||||
|     /// </summary> | ||||
|     [Description("Mqtt密码")] | ||||
|     public string Password { get; set; } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// WriteRpcTopic,Rpc返回为{WriteRpcTopic}/Return,只有这个topic才开放外部订阅权限 | ||||
|     /// </summary> | ||||
|     [Description("变量写入Rpc主题")] | ||||
|     public string WriteRpcTopic { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// DBDownTopic | ||||
|     /// </summary> | ||||
|     [Description("配置下发Rpc主题")] | ||||
|     public string DBDownTopic { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// DBUploadTopic | ||||
|     /// </summary> | ||||
|     [Description("配置上传Rpc主题")] | ||||
|     public string DBUploadTopic { get; set; } | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// <summary> | ||||
| /// ClientGatewayConfig | ||||
| /// </summary> | ||||
| public class ClientGatewayConfig : ManageGatewayConfig | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 标识 | ||||
|     /// </summary> | ||||
|     [Description("子网关标识ID")] | ||||
|     public string GatewayId { get; set; } | ||||
|  | ||||
| } | ||||
| /// <summary> | ||||
| /// 用于Mqtt Json传输,上传/下载配置信息 | ||||
| /// </summary> | ||||
| public class MqttDBUploadRpcResult | ||||
| { | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 采集设备 | ||||
|     /// </summary> | ||||
|     public List<CollectDevice> CollectDevices { get; set; } = new(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 上传设备 | ||||
|     /// </summary> | ||||
|     public List<UploadDevice> UploadDevices { get; set; } = new(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 变量 | ||||
|     /// </summary> | ||||
|     public List<DeviceVariable> DeviceVariables { get; set; } = new(); | ||||
|  | ||||
| } | ||||
| /// <summary> | ||||
| /// 用于Mqtt Json传输,上传/下载配置信息 | ||||
| /// </summary> | ||||
| public class MqttDBDownRpc | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 采集设备 | ||||
|     /// </summary> | ||||
|     public byte[] CollectDevices { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 上传设备 | ||||
|     /// </summary> | ||||
|     public byte[] UploadDevices { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 变量 | ||||
|     /// </summary> | ||||
|     public byte[] DeviceVariables { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// true=>删除全部后增加 | ||||
|     /// </summary> | ||||
|     [Description("是否删除原采集设备表")] | ||||
|     public bool IsCollectDevicesFullUp { get; set; } | ||||
|     /// <summary> | ||||
|     /// true=>删除全部后增加 | ||||
|     /// </summary> | ||||
|     [Description("是否删除原上传设备表")] | ||||
|     public bool IsUploadDevicesFullUp { get; set; } | ||||
|     /// <summary> | ||||
|     /// true=>删除全部后增加 | ||||
|     /// </summary> | ||||
|     [Description("是否删除原变量表")] | ||||
|     public bool IsDeviceVariablesFullUp { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 是否立即重启,使配置生效 | ||||
|     /// </summary> | ||||
|     [Description("是否重启子网关线程")] | ||||
|     public bool IsRestart { get; set; } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// <summary> | ||||
| /// MqttRpc传入 | ||||
| /// </summary> | ||||
| public class ManageMqttRpcFrom | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 标识 | ||||
|     /// </summary> | ||||
|     public string GatewayId { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 标识 | ||||
|     /// </summary> | ||||
|     public string RpcId { get; set; } | ||||
|     /// <summary> | ||||
|     /// "WriteInfos":{"test":"1"} | ||||
|     /// </summary> | ||||
|     public Dictionary<string, string> WriteInfos { get; set; } = new(); | ||||
| } | ||||
| /// <summary> | ||||
| /// MqttRpc输出 | ||||
| /// </summary> | ||||
| public class ManageMqttRpcResult | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 标识 | ||||
|     /// </summary> | ||||
|     public string GatewayId { get; set; } | ||||
|     /// <summary> | ||||
|     /// 标识 | ||||
|     /// </summary> | ||||
|     public string RpcId { get; set; } | ||||
|     /// <summary> | ||||
|     /// 消息 | ||||
|     /// </summary> | ||||
|     public Dictionary<string, OperResult> Message { get; set; } = new(); | ||||
|     /// <summary> | ||||
|     /// 是否成功 | ||||
|     /// </summary> | ||||
|     public bool Success { get; set; } | ||||
| } | ||||
| @@ -0,0 +1,838 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.Extensions.Hosting; | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using MQTTnet; | ||||
| using MQTTnet.Client; | ||||
| using MQTTnet.Internal; | ||||
| using MQTTnet.Protocol; | ||||
| using MQTTnet.Server; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
| using System.Net; | ||||
| using System.Text; | ||||
|  | ||||
| using ThingsGateway.Foundation; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
|  | ||||
| namespace ThingsGateway.Application; | ||||
|  | ||||
| /// <summary> | ||||
| /// ManageGatewayWorker | ||||
| /// </summary> | ||||
| public class ManageGatewayWorker : BackgroundService | ||||
| { | ||||
|     private readonly ILogger _clientLogger; | ||||
|     private readonly ILogger _logger; | ||||
|     private readonly ILogger _manageLogger; | ||||
|     /// <summary> | ||||
|     /// 全部重启锁 | ||||
|     /// </summary> | ||||
|     private readonly EasyLock restartLock = new(); | ||||
|  | ||||
|     private IMqttClient _mqttClient; | ||||
|  | ||||
|     private MqttServer _mqttServer; | ||||
|  | ||||
|     private MqttClientSubscribeOptions _mqttSubscribeOptions; | ||||
|  | ||||
|     /// <inheritdoc cref="ManageGatewayWorker"/> | ||||
|     public ManageGatewayWorker(ILoggerFactory loggerFactory) | ||||
|     { | ||||
|         _logger = loggerFactory.CreateLogger("ManageGatewayWorker"); | ||||
|         _manageLogger = loggerFactory.CreateLogger("管理网关(mqttBroker)"); | ||||
|         _clientLogger = loggerFactory.CreateLogger("子网关(mqttClient)"); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 服务状态 | ||||
|     /// </summary> | ||||
|     public OperResult ClientStatuString { get; set; } = new OperResult("初始化"); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 服务状态 | ||||
|     /// </summary> | ||||
|     public OperResult ManageStatuString { get; set; } = new OperResult("初始化"); | ||||
|     #region worker服务 | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task StartAsync(CancellationToken token) | ||||
|     { | ||||
|         _logger?.LogInformation("ManageGatewayWorker启动"); | ||||
|         await RestartAsync(); | ||||
|         await base.StartAsync(token); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override async Task StopAsync(CancellationToken token) | ||||
|     { | ||||
|         _logger?.LogInformation("ManageGatewayWorker停止"); | ||||
|         await StopAsync(); | ||||
|         await base.StopAsync(token); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     protected override async Task ExecuteAsync(CancellationToken stoppingToken) | ||||
|     { | ||||
|  | ||||
|         while (!stoppingToken.IsCancellationRequested) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 if (_mqttClient != null) | ||||
|                 { | ||||
|                     //持续重连 | ||||
|                     var result = await TryMqttClientAsync(stoppingToken); | ||||
|                     if (result.IsSuccess) | ||||
|                     { | ||||
|                         _clientLogger.LogDebug("连接正常:" + result.Message); | ||||
|                         ClientStatuString.ResultCode = ResultCode.Success; | ||||
|                         ClientStatuString.Message = "连接正常:" + result.Message; | ||||
|  | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         _clientLogger.LogWarning("连接错误:" + result.Message); | ||||
|                         ClientStatuString.ResultCode = ResultCode.Fail; | ||||
|                         ClientStatuString.Message = "连接错误:" + result.Message; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 await Task.Delay(10000, stoppingToken); | ||||
|  | ||||
|  | ||||
|                 //if (_mqttServer != null) | ||||
|                 //{ | ||||
|                 //    //TODO:test code | ||||
|                 //    var mqttClientStatuses = await _mqttServer.GetClientsAsync(); | ||||
|  | ||||
|                 //    if (mqttClientStatuses.FirstOrDefault() is MqttClientStatus mqttClientStatus) | ||||
|                 //    { | ||||
|                 //        //获取子网关信息 | ||||
|                 //        var getClientGatewayDBResult = await GetClientGatewayDBAsync(mqttClientStatus.Id); | ||||
|  | ||||
|                 //        //下发子网关配置 | ||||
|                 //        var mqttDBDownRpc = new MqttDBDownRpc | ||||
|                 //        { | ||||
|                 //            IsRestart = true | ||||
|                 //        }; | ||||
|                 //        var setClientGatewayDBResult = await SetClientGatewayDBAsync(mqttClientStatus.Id, mqttDBDownRpc); | ||||
|  | ||||
|                 //        //下发子网关配置 | ||||
|                 //        var manageMqttRpcFrom = new ManageMqttRpcFrom | ||||
|                 //        { | ||||
|                 //            WriteInfos = new Dictionary<string, string>() | ||||
|                 //            { | ||||
|                 //                { | ||||
|                 //                "test41","123" | ||||
|                 //                } | ||||
|                 //            }, | ||||
|                 //            GatewayId = "GatewayId", | ||||
|                 //            RpcId = "123456", | ||||
|                 //        }; | ||||
|  | ||||
|                 //        var WriteVariableResult = await WriteVariableAsync(manageMqttRpcFrom); | ||||
|  | ||||
|                 //    } | ||||
|  | ||||
|                 //} | ||||
|  | ||||
|  | ||||
|  | ||||
|             } | ||||
|             catch (TaskCanceledException) | ||||
|             { | ||||
|  | ||||
|             } | ||||
|             catch (ObjectDisposedException) | ||||
|             { | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 _logger.LogError(ex, ToString()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region public | ||||
|     /// <summary> | ||||
|     /// 获取子网关的配置信息 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult<MqttDBUploadRpcResult>> GetClientGatewayDBAsync(string gatewayId, int timeOut = 3000, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var buffer = Encoding.UTF8.GetBytes(string.Empty); | ||||
|             var response = await RpcDataExecuteAsync(gatewayId, ClientGatewayConfig.DBUploadTopic, buffer, timeOut, MqttQualityOfServiceLevel.AtMostOnce, token); | ||||
|             var data = Encoding.UTF8.GetString(response).FromJsonString<MqttDBUploadRpcResult>(); | ||||
|             return OperResult.CreateSuccessResult(data); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<MqttDBUploadRpcResult>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 重启 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task RestartAsync() | ||||
|     { | ||||
|         await StopAsync(); | ||||
|         await StartAsync(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 下载配置信息到子网关 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult> SetClientGatewayDBAsync(string gatewayId, MqttDBDownRpc mqttDBRpc, int timeOut = 3000, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var buffer = Encoding.UTF8.GetBytes(mqttDBRpc?.ToJsonString() ?? string.Empty); | ||||
|             var response = await RpcDataExecuteAsync(gatewayId, ClientGatewayConfig.DBDownTopic, buffer, timeOut, MqttQualityOfServiceLevel.AtMostOnce, token); | ||||
|             var data = Encoding.UTF8.GetString(response).FromJsonString<OperResult>(); | ||||
|             return data; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 写入变量到子网关 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult<ManageMqttRpcResult>> WriteVariableAsync(ManageMqttRpcFrom manageMqttRpcFrom, int timeOut = 3000, CancellationToken token = default) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             var payload = Encoding.UTF8.GetBytes(manageMqttRpcFrom?.ToJsonString() ?? string.Empty); | ||||
|             var requestTopic = ManageGatewayConfig.WriteRpcTopic; | ||||
|             var responseTopic = GetRpcReturnTopic(ManageGatewayConfig.WriteRpcTopic); | ||||
|             var key = GetRpcReturnIdTopic(manageMqttRpcFrom.GatewayId, requestTopic, manageMqttRpcFrom.RpcId); | ||||
|  | ||||
|             ManageMqttRpcResult result = await RpcWriteExecuteAsync(timeOut, payload, requestTopic, key, token); | ||||
|  | ||||
|             return OperResult.CreateSuccessResult(result); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             return new OperResult<ManageMqttRpcResult>(ex); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取子网关列表 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public async Task<List<MqttClientStatus>> GetClientGatewayAsync() | ||||
|     { | ||||
|         if (_mqttServer != null) | ||||
|         { | ||||
|             var data = await _mqttServer.GetClientsAsync(); | ||||
|             return data.ToList(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return new List<MqttClientStatus>(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|     #region RPC实现 | ||||
|  | ||||
|     readonly ConcurrentDictionary<string, WaitDataAsync<byte[]>> _waitingCalls = new(); | ||||
|     readonly ConcurrentDictionary<string, WaitDataAsync<ManageMqttRpcResult>> _writerRpcResultWaitingCalls = new(); | ||||
|     private readonly EasyLock clientLock = new(); | ||||
|  | ||||
|  | ||||
|     private async Task<ManageMqttRpcResult> RpcWriteExecuteAsync(int timeOut, byte[] payload, string requestTopic, string key, CancellationToken token) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             using WaitDataAsync<ManageMqttRpcResult> waitDataAsync = new(); | ||||
|             if (!_writerRpcResultWaitingCalls.TryAdd(key, waitDataAsync)) | ||||
|             { | ||||
|                 throw new InvalidOperationException(); | ||||
|             } | ||||
|             waitDataAsync.SetCancellationToken(token); | ||||
|  | ||||
|             //请求子网关的数据 | ||||
|             var message = new MqttApplicationMessageBuilder().WithTopic(requestTopic).WithPayload(payload).Build(); | ||||
|             await _mqttServer.InjectApplicationMessage(new InjectedMqttApplicationMessage(message), token); | ||||
|  | ||||
|             var result = await waitDataAsync.WaitAsync(timeOut); | ||||
|             switch (result) | ||||
|             { | ||||
|                 case WaitDataStatus.SetRunning: | ||||
|                     return waitDataAsync.WaitResult; | ||||
|                 case WaitDataStatus.Overtime: | ||||
|                     throw new TimeoutException(); | ||||
|                 case WaitDataStatus.Canceled: | ||||
|                     { | ||||
|                         throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。"); | ||||
|                     } | ||||
|                 case WaitDataStatus.Default: | ||||
|                 case WaitDataStatus.Disposed: | ||||
|                 default: | ||||
|                     throw new Exception(ThingsGatewayStatus.UnknownError.GetDescription()); | ||||
|             } | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             _writerRpcResultWaitingCalls.Remove(key); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// RPC请求子网关并返回,需要传入子网关ID,作为Topic参数一部分 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     private async Task<byte[]> RpcDataExecuteAsync(string gatewayId, string topic, byte[] payload, int timeOut, MqttQualityOfServiceLevel qualityOfServiceLevel, CancellationToken token = default) | ||||
|     { | ||||
|         var responseTopic = GetRpcReturnTopic(gatewayId, topic); | ||||
|         var requestTopic = GetRpcTopic(gatewayId, topic); | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             using WaitDataAsync<byte[]> waitDataAsync = new(); | ||||
|             if (!_waitingCalls.TryAdd(responseTopic, waitDataAsync)) | ||||
|             { | ||||
|                 throw new InvalidOperationException(); | ||||
|             } | ||||
|             waitDataAsync.SetCancellationToken(token); | ||||
|  | ||||
|             //请求子网关的数据 | ||||
|             var message = new MqttApplicationMessageBuilder().WithTopic(requestTopic).WithPayload(payload).Build(); | ||||
|             await _mqttServer.InjectApplicationMessage(new InjectedMqttApplicationMessage(message), token); | ||||
|  | ||||
|             var result = await waitDataAsync.WaitAsync(timeOut); | ||||
|             switch (result) | ||||
|             { | ||||
|                 case WaitDataStatus.SetRunning: | ||||
|                     return waitDataAsync.WaitResult; | ||||
|                 case WaitDataStatus.Overtime: | ||||
|                     throw new TimeoutException(); | ||||
|                 case WaitDataStatus.Canceled: | ||||
|                     { | ||||
|                         throw new Exception("等待已终止。可能是客户端已掉线,或者被注销。"); | ||||
|                     } | ||||
|                 case WaitDataStatus.Default: | ||||
|                 case WaitDataStatus.Disposed: | ||||
|                 default: | ||||
|                     throw new Exception(ThingsGatewayStatus.UnknownError.GetDescription()); | ||||
|             } | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             _waitingCalls.Remove(responseTopic); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region 核心实现 | ||||
|  | ||||
|     internal async Task StartAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             //重启操作在未完全之前直接取消 | ||||
|             if (restartLock.IsWaitting) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|             await restartLock.WaitAsync(); | ||||
|  | ||||
|             await InitAsync(); | ||||
|  | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _logger.LogError(ex, "启动错误"); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             restartLock.Release(); | ||||
|         } | ||||
|     } | ||||
|     internal async Task StopAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             //重启操作在未完全之前直接取消 | ||||
|             if (restartLock.IsWaitting) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|             await restartLock.WaitAsync(); | ||||
|             _mqttClient?.SafeDispose(); | ||||
|             _mqttServer?.SafeDispose(); | ||||
|             _mqttClient = null; | ||||
|             _mqttServer = null; | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _logger.LogError(ex, "停止错误"); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             restartLock.Release(); | ||||
|         } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 初始化 | ||||
|     /// </summary> | ||||
|     private async Task InitAsync() | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             ManageGatewayConfig = App.GetConfig<ManageGatewayConfig>("ManageGatewayConfig"); | ||||
|             if (ManageGatewayConfig?.Enable != true) | ||||
|             { | ||||
|                 ManageStatuString = new OperResult($"已退出:不启用管理功能"); | ||||
|                 _manageLogger.LogWarning("已退出:不启用管理功能"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var mqttFactory = new MqttFactory(new MqttNetLogger(_manageLogger)); | ||||
|                 var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder() | ||||
|                     .WithDefaultEndpointBoundIPAddress(string.IsNullOrEmpty(ManageGatewayConfig.MqttBrokerIP) ? null : IPAddress.Parse(ManageGatewayConfig.MqttBrokerIP)) | ||||
|                     .WithDefaultEndpointPort(ManageGatewayConfig.MqttBrokerPort) | ||||
|                     .WithDefaultEndpoint() | ||||
|                     .Build(); | ||||
|                 _mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions); | ||||
|                 if (_mqttServer != null) | ||||
|                 { | ||||
|                     _mqttServer.ValidatingConnectionAsync += MqttServer_ValidatingConnectionAsync;//认证 | ||||
|                     _mqttServer.InterceptingPublishAsync += MqttServer_InterceptingPublishAsync;//消息 | ||||
|  | ||||
|                     await _mqttServer.StartAsync(); | ||||
|                 } | ||||
|                 ManageStatuString = OperResult.CreateSuccessResult(); | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _manageLogger.LogError(ex, "初始化失败"); | ||||
|             ManageStatuString = new($"初始化失败-{ex.Message}"); | ||||
|         } | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             ClientGatewayConfig = App.GetConfig<ClientGatewayConfig>("ClientGatewayConfig"); | ||||
|             if (ClientGatewayConfig?.Enable != true) | ||||
|             { | ||||
|                 ClientStatuString = new OperResult($"已退出:不启用子网关功能"); | ||||
|                 _clientLogger.LogWarning("已退出:不启用子网关功能"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var mqttFactory = new MqttFactory(new MqttNetLogger(_clientLogger)); | ||||
|                 _mqttClientOptions = mqttFactory.CreateClientOptionsBuilder() | ||||
|                   .WithCredentials(ClientGatewayConfig.UserName, ClientGatewayConfig.Password)//账密 | ||||
|                   .WithTcpServer(ClientGatewayConfig.MqttBrokerIP, ClientGatewayConfig.MqttBrokerPort)//服务器 | ||||
|                   .WithClientId(ClientGatewayConfig.GatewayId) | ||||
|                   .WithCleanSession(true) | ||||
|                   .WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0)) | ||||
|                   .WithoutThrowOnNonSuccessfulConnectResponse() | ||||
|                   .Build(); | ||||
|                 _mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder() | ||||
|                     .WithTopicFilter( | ||||
|                         f => | ||||
|                         { | ||||
|                             f.WithTopic(ClientGatewayConfig.WriteRpcTopic); | ||||
|                             f.WithAtMostOnceQoS(); | ||||
|                         }) | ||||
|                       .WithTopicFilter( | ||||
|                         f => | ||||
|                         { | ||||
|                             f.WithTopic(GetRpcTopic(ClientGatewayConfig.GatewayId, ClientGatewayConfig.DBDownTopic)); | ||||
|                             f.WithAtMostOnceQoS(); | ||||
|                         }) | ||||
|                                         .WithTopicFilter( | ||||
|                         f => | ||||
|                         { | ||||
|                             f.WithTopic(GetRpcTopic(ClientGatewayConfig.GatewayId, ClientGatewayConfig.DBUploadTopic)); | ||||
|                             f.WithAtMostOnceQoS(); | ||||
|                         }) | ||||
|                     .Build(); | ||||
|                 _mqttClient = mqttFactory.CreateMqttClient(); | ||||
|                 _mqttClient.ConnectedAsync += MqttClient_ConnectedAsync; | ||||
|                 _mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync; | ||||
|                 await TryMqttClientAsync(CancellationToken.None); | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             _clientLogger.LogError(ex, "初始化失败"); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// ClientGatewayConfig | ||||
|     /// </summary> | ||||
|     public ClientGatewayConfig ClientGatewayConfig; | ||||
|     /// <summary> | ||||
|     /// ManageGatewayConfig | ||||
|     /// </summary> | ||||
|     public ManageGatewayConfig ManageGatewayConfig; | ||||
|     private MqttClientOptions _mqttClientOptions; | ||||
|     RpcSingletonService _rpcCore; | ||||
|  | ||||
|     private async Task DBDownTopicMethod(MqttApplicationMessageReceivedEventArgs args) | ||||
|     { | ||||
|         var mqttDBRpc = args.ApplicationMessage.PayloadSegment.Count > 0 ? Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment).FromJsonString<MqttDBDownRpc>() : null; | ||||
|         if (mqttDBRpc != null) | ||||
|         { | ||||
|             OperResult result = new(); | ||||
|             var collectDeviceService = App.GetService<CollectDeviceService>(); | ||||
|             var variableService = App.GetService<VariableService>(); | ||||
|             var uploadDeviceService = App.GetService<UploadDeviceService>(); | ||||
|  | ||||
|             collectDeviceService.Context = variableService.Context = uploadDeviceService.Context; | ||||
|             var itenant = collectDeviceService.Context.AsTenant(); | ||||
|             //事务 | ||||
|             var dbResult = await itenant.UseTranAsync(async () => | ||||
|             { | ||||
|  | ||||
|                 if (mqttDBRpc.IsCollectDevicesFullUp) | ||||
|                 { | ||||
|                     await collectDeviceService.AsDeleteable().ExecuteCommandAsync(); | ||||
|                 } | ||||
|                 var collectDevices = new List<CollectDevice>(); | ||||
|  | ||||
|  | ||||
|                 if (mqttDBRpc.CollectDevices != null && mqttDBRpc.CollectDevices.Length > 0) | ||||
|                 { | ||||
|                     using MemoryStream stream = new(mqttDBRpc.CollectDevices); | ||||
|                     var previewResult = await collectDeviceService.PreviewAsync(stream); | ||||
|                     if (previewResult.FirstOrDefault().Value.HasError) | ||||
|                     { | ||||
|                         throw new(previewResult.Select(a => a.Value.Results.Where(a => !a.isSuccess).ToList()).ToList().ToJsonString()); | ||||
|                     } | ||||
|                     foreach (var item in previewResult) | ||||
|                     { | ||||
|                         if (item.Key == ExportHelpers.CollectDeviceSheetName) | ||||
|                         { | ||||
|                             var collectDeviceImports = ((ImportPreviewOutput<CollectDevice>)item.Value).Data; | ||||
|                             collectDevices = collectDeviceImports.Values.Adapt<List<CollectDevice>>(); | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     await collectDeviceService.ImportAsync(previewResult); | ||||
|  | ||||
|                 } | ||||
|  | ||||
|                 if (mqttDBRpc.IsUploadDevicesFullUp) | ||||
|                 { | ||||
|                     await uploadDeviceService.AsDeleteable().ExecuteCommandAsync(); | ||||
|  | ||||
|                 } | ||||
|                 var uploadDevices = new List<UploadDevice>(); | ||||
|  | ||||
|                 if (mqttDBRpc.UploadDevices != null && mqttDBRpc.UploadDevices.Length > 0) | ||||
|                 { | ||||
|                     using MemoryStream stream1 = new(mqttDBRpc.UploadDevices); | ||||
|                     var previewResult1 = await uploadDeviceService.PreviewAsync(stream1); | ||||
|                     if (previewResult1.FirstOrDefault().Value.HasError) | ||||
|                     { | ||||
|                         throw new(previewResult1.Select(a => a.Value.Results.Where(a => !a.isSuccess).ToList()).ToList().ToJsonString()); | ||||
|                     } | ||||
|                     foreach (var item in previewResult1) | ||||
|                     { | ||||
|                         if (item.Key == ExportHelpers.UploadDeviceSheetName) | ||||
|                         { | ||||
|                             var uploadDeviceImports = ((ImportPreviewOutput<UploadDevice>)item.Value).Data; | ||||
|                             uploadDevices = uploadDeviceImports.Values.Adapt<List<UploadDevice>>(); | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     await uploadDeviceService.ImportAsync(previewResult1); | ||||
|  | ||||
|                 } | ||||
|  | ||||
|                 if (mqttDBRpc.IsDeviceVariablesFullUp) | ||||
|                 { | ||||
|                     await variableService.AsDeleteable().ExecuteCommandAsync(); | ||||
|  | ||||
|                 } | ||||
|                 if (mqttDBRpc.DeviceVariables != null && mqttDBRpc.DeviceVariables.Length > 0) | ||||
|                 { | ||||
|                     using MemoryStream stream2 = new(mqttDBRpc.DeviceVariables); | ||||
|                     var previewResult2 = await variableService.PreviewAsync(stream2, collectDevices, uploadDevices); | ||||
|                     if (previewResult2.FirstOrDefault().Value.HasError) | ||||
|                     { | ||||
|                         throw new(previewResult2.Select(a => a.Value.Results.Where(a => !a.isSuccess).ToList()).ToList().ToJsonString()); | ||||
|                     } | ||||
|                     await variableService.ImportAsync(previewResult2); | ||||
|                 } | ||||
|             }); | ||||
|             CacheStatic.Cache.Remove(ThingsGatewayCacheConst.Cache_CollectDevice);//cache删除 | ||||
|             CacheStatic.Cache.Remove(ThingsGatewayCacheConst.Cache_UploadDevice);//cache删除 | ||||
|  | ||||
|             if (dbResult.IsSuccess)//如果成功了 | ||||
|             { | ||||
|                 _clientLogger.LogInformation("子网关接收配置,并保存至数据库-执行成功"); | ||||
|                 result = OperResult.CreateSuccessResult(); | ||||
|                 if (mqttDBRpc.IsRestart) | ||||
|                 { | ||||
|                     _clientLogger.LogInformation("子网关接收配置,并重启"); | ||||
|                     await ServiceHelper.GetBackgroundService<CollectDeviceWorker>().RestartDeviceThreadAsync(); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 //写日志 | ||||
|                 result.Message = dbResult.ErrorMessage; | ||||
|             } | ||||
|  | ||||
|             var variableMessage = new MqttApplicationMessageBuilder() | ||||
|     .WithTopic(GetRpcReturnTopic(args.ApplicationMessage.Topic)) | ||||
|     .WithPayload(result.ToJsonString()).Build(); | ||||
|             if (_mqttClient.IsConnected) | ||||
|                 await _mqttClient.PublishAsync(variableMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task DBUploadTopicMethod(MqttApplicationMessageReceivedEventArgs args) | ||||
|     { | ||||
|         MqttDBUploadRpcResult result = new(); | ||||
|         var collectDeviceService = App.GetService<CollectDeviceService>(); | ||||
|         var variableService = App.GetService<VariableService>(); | ||||
|         var uploadDeviceService = App.GetService<UploadDeviceService>(); | ||||
|         result.CollectDevices = collectDeviceService.GetCacheList(false); | ||||
|         result.DeviceVariables = await variableService.GetListAsync(); | ||||
|         result.UploadDevices = uploadDeviceService.GetCacheList(false); | ||||
|  | ||||
|         var variableMessage = new MqttApplicationMessageBuilder() | ||||
| .WithTopic(GetRpcReturnTopic(args.ApplicationMessage.Topic)) | ||||
| .WithPayload(result.ToJsonString()).Build(); | ||||
|         if (_mqttClient.IsConnected) | ||||
|             await _mqttClient.PublishAsync(variableMessage); | ||||
|     } | ||||
|  | ||||
|     private string GetRpcReturnIdTopic(string gatewayId, string topic, string rpcId) | ||||
|     { | ||||
|         var responseTopic = $"{gatewayId}/{topic}/rpc/Return/rpcId"; | ||||
|         return responseTopic; | ||||
|     } | ||||
|  | ||||
|     private string GetRpcReturnTopic(string gatewayId, string topic) | ||||
|     { | ||||
|         var responseTopic = $"{gatewayId}/{topic}/rpc/Return"; | ||||
|         return responseTopic; | ||||
|     } | ||||
|  | ||||
|     private string GetRpcReturnTopic(string requestTopic) | ||||
|     { | ||||
|         var responseTopic = $"{requestTopic}/Return"; | ||||
|         return responseTopic; | ||||
|     } | ||||
|  | ||||
|     private string GetRpcTopic(string gatewayId, string topic) | ||||
|     { | ||||
|         var requestTopic = $"{gatewayId}/{topic}/rpc"; | ||||
|         return requestTopic; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs args) | ||||
|     { | ||||
|         if (args.ApplicationMessage.Topic == GetRpcTopic(ClientGatewayConfig.GatewayId, ClientGatewayConfig.DBUploadTopic)) | ||||
|         { | ||||
|             _clientLogger.LogInformation("子网关配置上传"); | ||||
|             await DBUploadTopicMethod(args); | ||||
|             return; | ||||
|         } | ||||
|         if (args.ApplicationMessage.Topic == GetRpcTopic(ClientGatewayConfig.GatewayId, ClientGatewayConfig.DBDownTopic)) | ||||
|         { | ||||
|  | ||||
|             _clientLogger.LogInformation("子网关接收配置,并保存至数据库"); | ||||
|             await DBDownTopicMethod(args); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|         if (args.ApplicationMessage.Topic == ClientGatewayConfig.WriteRpcTopic) | ||||
|         { | ||||
|  | ||||
|             await WriteRpcTopicMethod(args); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs args) | ||||
|     { | ||||
|         var subResult = await _mqttClient.SubscribeAsync(_mqttSubscribeOptions); | ||||
|         if (subResult.Items.Any(a => a.ResultCode > (MqttClientSubscribeResultCode)10)) | ||||
|         { | ||||
|             _clientLogger?.LogWarning("订阅失败-" + subResult.Items | ||||
|                 .Where(a => a.ResultCode > (MqttClientSubscribeResultCode)10) | ||||
|                 .Select(a => | ||||
|                 new | ||||
|                 { | ||||
|                     Topic = a.TopicFilter.Topic, | ||||
|                     ResultCode = a.ResultCode.ToString() | ||||
|                 } | ||||
|                 ) | ||||
|                 .ToJsonString() | ||||
|                 ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Task MqttServer_InterceptingPublishAsync(InterceptingPublishEventArgs eventArgs) | ||||
|     { | ||||
|         if (eventArgs.ApplicationMessage.Topic == GetRpcReturnTopic(ManageGatewayConfig.WriteRpcTopic)) | ||||
|         { | ||||
|             if (!_writerRpcResultWaitingCalls.IsEmpty) | ||||
|             { | ||||
|                 var payloadBuffer = eventArgs.ApplicationMessage.PayloadSegment.ToArray(); | ||||
|                 var manageMqttRpcResult = Encoding.UTF8.GetString(payloadBuffer).FromJsonString<ManageMqttRpcResult>(); | ||||
|                 var key = GetRpcReturnIdTopic(manageMqttRpcResult.GatewayId, ManageGatewayConfig.WriteRpcTopic, manageMqttRpcResult.RpcId); | ||||
|                 if (!_writerRpcResultWaitingCalls.TryRemove(key, out var writeRpcResultAsync)) | ||||
|                 { | ||||
|                     return CompletedTask.Instance; | ||||
|                 } | ||||
|                 writeRpcResultAsync.Set(manageMqttRpcResult); | ||||
|  | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|  | ||||
|             if (!_waitingCalls.TryRemove(eventArgs.ApplicationMessage.Topic, out var awaitable)) | ||||
|             { | ||||
|                 return CompletedTask.Instance; | ||||
|             } | ||||
|  | ||||
|             var payloadBuffer = eventArgs.ApplicationMessage.PayloadSegment.ToArray(); | ||||
|             awaitable.Set(payloadBuffer); | ||||
|         } | ||||
|  | ||||
|         return CompletedTask.Instance; | ||||
|     } | ||||
|  | ||||
|     private Task MqttServer_ValidatingConnectionAsync(ValidatingConnectionEventArgs arg) | ||||
|     { | ||||
|         if (ManageGatewayConfig.UserName != arg.UserName) | ||||
|         { | ||||
|             arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; | ||||
|             return CompletedTask.Instance; | ||||
|         } | ||||
|         if (ManageGatewayConfig.Password != arg.Password) | ||||
|         { | ||||
|             arg.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; | ||||
|             return CompletedTask.Instance; | ||||
|         } | ||||
|         _manageLogger?.LogInformation(ToString() + "-" + arg.ClientId + "-客户端已连接成功"); | ||||
|         return CompletedTask.Instance; | ||||
|     } | ||||
|  | ||||
|     private async Task<OperResult> TryMqttClientAsync(CancellationToken token) | ||||
|     { | ||||
|         if (_mqttClient?.IsConnected == true) | ||||
|             return OperResult.CreateSuccessResult(); | ||||
|         return await Cilent(); | ||||
|  | ||||
|         async Task<OperResult> Cilent() | ||||
|         { | ||||
|             if (_mqttClient?.IsConnected == true) | ||||
|                 return OperResult.CreateSuccessResult(); | ||||
|             try | ||||
|             { | ||||
|                 await clientLock.WaitAsync(); | ||||
|                 if (_mqttClient?.IsConnected == true) | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 using var timeoutToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(5000)); | ||||
|                 using CancellationTokenSource StoppingToken = CancellationTokenSource.CreateLinkedTokenSource(token, timeoutToken.Token); | ||||
|                 if (_mqttClient?.IsConnected == true) | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 if (_mqttClient == null) | ||||
|                 { | ||||
|                     return new OperResult("未初始化"); | ||||
|                 } | ||||
|                 var result = await _mqttClient?.ConnectAsync(_mqttClientOptions, StoppingToken.Token); | ||||
|                 if (result.ResultCode == MqttClientConnectResultCode.Success) | ||||
|                 { | ||||
|                     return OperResult.CreateSuccessResult(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     return new OperResult(result.ReasonString); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 return new OperResult(ex); | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|                 clientLock.Release(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     private async Task WriteRpcTopicMethod(MqttApplicationMessageReceivedEventArgs args) | ||||
|     { | ||||
|         var manageMqttRpcFrom = args.ApplicationMessage.PayloadSegment.Count > 0 ? Encoding.UTF8.GetString(args.ApplicationMessage.PayloadSegment).FromJsonString<ManageMqttRpcFrom>() : null; | ||||
|         if (manageMqttRpcFrom != null && manageMqttRpcFrom.GatewayId == ClientGatewayConfig.GatewayId) | ||||
|         { | ||||
|             ManageMqttRpcResult mqttRpcResult = new() { RpcId = manageMqttRpcFrom.RpcId, GatewayId = manageMqttRpcFrom.GatewayId }; | ||||
|             _rpcCore ??= App.GetService<RpcSingletonService>(); | ||||
|             var result = await _rpcCore.InvokeDeviceMethodAsync("子网关RPC" + "-" + args.ClientId, | ||||
|     manageMqttRpcFrom.WriteInfos.Where( | ||||
|     a => !mqttRpcResult.Message.Any(b => b.Key == a.Key)).ToDictionary(a => a.Key, a => a.Value)); | ||||
|             mqttRpcResult.Message.AddRange(result); | ||||
|             mqttRpcResult.Success = !mqttRpcResult.Message.Any(a => !a.Value.IsSuccess); | ||||
|  | ||||
|             var variableMessage = new MqttApplicationMessageBuilder() | ||||
|     .WithTopic(GetRpcReturnTopic(args.ApplicationMessage.Topic)) | ||||
|     .WithPayload(mqttRpcResult.ToJsonString()).Build(); | ||||
|             if (_mqttClient.IsConnected) | ||||
|                 await _mqttClient.PublishAsync(variableMessage); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     #endregion | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using MQTTnet.Diagnostics; | ||||
|  | ||||
|  | ||||
| namespace ThingsGateway.Application; | ||||
|  | ||||
| internal class MqttNetLogger : IMqttNetLogger | ||||
| { | ||||
|     readonly ILogger LogMessage; | ||||
|     public MqttNetLogger(ILogger logger) | ||||
|     { | ||||
|         LogMessage = logger; | ||||
|     } | ||||
|  | ||||
|     public bool IsEnabled => true; | ||||
|     public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception) | ||||
|     { | ||||
|         switch (logLevel) | ||||
|         { | ||||
|             case MqttNetLogLevel.Verbose: | ||||
|                 LogMessage?.Log(LogLevel.Trace, source, message != null ? (parameters != null ? message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty : message) : string.Empty, exception); | ||||
|                 break; | ||||
|  | ||||
|             case MqttNetLogLevel.Info: | ||||
|                 LogMessage?.Log(LogLevel.Information, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception); | ||||
|                 break; | ||||
|  | ||||
|             case MqttNetLogLevel.Warning: | ||||
|                 LogMessage?.Log(LogLevel.Warning, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception); | ||||
|                 break; | ||||
|  | ||||
|             case MqttNetLogLevel.Error: | ||||
|                 LogMessage?.Log(LogLevel.Warning, source, message != null ? (parameters != null ? string.Format(message, parameters) : message) : string.Empty, exception); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| #region copyright | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using CodingSeb.ExpressionEvaluator; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using System.ComponentModel; | ||||
| @@ -24,6 +26,13 @@ namespace ThingsGateway.Application; | ||||
| /// </summary> | ||||
| public class DeviceVariableRunTime : DeviceVariable | ||||
| { | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     public DeviceVariableRunTime() | ||||
|     { | ||||
|         expressionEvaluator.PreEvaluateVariable += ExpressionEvaluatorExtensions.Evaluator_PreEvaluateVariable; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 设备名称 | ||||
|     /// </summary> | ||||
| @@ -71,9 +80,9 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|     [DataTable(Order = 3, IsShow = true, Sortable = false, CellClass = " table-text-truncate ")] | ||||
|     public object Value { get => _value; private set => _value = value; } | ||||
|     /// <summary> | ||||
|     /// 最近一次值 | ||||
|     /// 上次值 | ||||
|     /// </summary> | ||||
|     [Description("最近一次值")] | ||||
|     [Description("上次值")] | ||||
|     [DataTable(Order = 3, IsShow = true, Sortable = false, CellClass = " table-text-truncate ")] | ||||
|     public object LastSetValue { get; private set; } | ||||
|  | ||||
| @@ -83,10 +92,11 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|     /// <param name="value"></param> | ||||
|     /// <param name="dateTime"></param> | ||||
|     /// <param name="isOnline"></param> | ||||
|     public OperResult SetValue(object value, DateTime dateTime = default,bool isOnline=true) | ||||
|     public OperResult SetValue(object value, DateTime dateTime = default, bool isOnline = true) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|  | ||||
|             IsOnline = isOnline; | ||||
|  | ||||
|             if (!IsOnline) | ||||
| @@ -101,7 +111,7 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|                 object data = null; | ||||
|                 try | ||||
|                 { | ||||
|                     data = ReadExpressions.GetExpressionsResult(RawValue); | ||||
|                     data = ReadExpressions.GetExpressionsResult(expressionEvaluator, RawValue); | ||||
|                     Set(data); | ||||
|                 } | ||||
|                 catch (Exception ex) | ||||
| @@ -137,14 +147,17 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|             } | ||||
|             CollectTime = time; | ||||
|             { | ||||
|                 if ((data?.ToString() != _value?.ToString() && LastSetValue?.ToString() != data?.ToString()) || isOnlineChanged) | ||||
|                 if ((data?.ToString() != _value?.ToString()) || isOnlineChanged) | ||||
|                 { | ||||
|                     ChangeTime = time; | ||||
|  | ||||
|                     LastSetValue = _value; | ||||
|  | ||||
|                     if (IsOnline) | ||||
|                     { | ||||
|                         _value = data; | ||||
|                     } | ||||
|                     LastSetValue = data; | ||||
|  | ||||
|                     VariableValueChange?.Invoke(this); | ||||
|                 } | ||||
|             } | ||||
| @@ -176,7 +189,7 @@ public class DeviceVariableRunTime : DeviceVariable | ||||
|     /// 谨慎使用,务必采用队列等方式 | ||||
|     /// </summary> | ||||
|     public event VariableChangeEventHandler VariableValueChange; | ||||
|  | ||||
|     private ExpressionEvaluator expressionEvaluator = new(); | ||||
|     private bool isOnline; | ||||
|     private bool isOnlineChanged; | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using Newtonsoft.Json.Linq; | ||||
| @@ -157,7 +159,7 @@ public abstract class CollectBase : DriverBase | ||||
|             { | ||||
|                 deviceVariableSourceRead.DeviceVariables.ForEach(it => | ||||
|                 { | ||||
|                     var operResult = it.SetValue(null,isOnline:false); | ||||
|                     var operResult = it.SetValue(null, isOnline: false); | ||||
|                     if (!operResult.IsSuccess) | ||||
|                     { | ||||
|                         _logger.LogWarning("变量值更新失败:" + operResult.Message); | ||||
| @@ -220,6 +222,31 @@ public abstract class CollectBase : DriverBase | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     internal override void NewMessage(TouchSocket.Core.LogLevel arg1, object arg2, string arg3, Exception arg4) | ||||
|     { | ||||
|         if (IsSaveLog) | ||||
|         { | ||||
|             if (arg3.StartsWith(FoundationConst.LogMessageHeader)) | ||||
|             { | ||||
|                 var customLevel = App.GetConfig<Microsoft.Extensions.Logging.LogLevel?>("Logging:LogLevel:BackendLog") ?? Microsoft.Extensions.Logging.LogLevel.Trace; | ||||
|                 if ((byte)arg1 < (byte)customLevel) | ||||
|                 { | ||||
|                     var logRuntime = new BackendLog | ||||
|                     { | ||||
|                         LogLevel = (Microsoft.Extensions.Logging.LogLevel)arg1, | ||||
|                         LogMessage = arg3, | ||||
|                         LogSource = "采集设备:" + CurDevice.Name, | ||||
|                         LogTime = SysDateTimeExtensions.CurrentDateTime, | ||||
|                         Exception = null, | ||||
|                     }; | ||||
|                     _logQueues.Enqueue(logRuntime); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         base.NewMessage(arg1, arg2, arg3, arg4); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 返回全部内容字节数组 | ||||
|     /// <br></br> | ||||
|   | ||||
| @@ -12,7 +12,10 @@ | ||||
|  | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using System.Collections.Concurrent; | ||||
|  | ||||
| using ThingsGateway.Foundation; | ||||
| using ThingsGateway.Foundation.Extension.ConcurrentQueue; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
|  | ||||
| @@ -40,6 +43,7 @@ public abstract class DriverBase : DisposableObject | ||||
|         LogMessage = new LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(Log_Out) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         FoundataionConfig.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         Task.Factory.StartNew(LogInsertAsync); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     protected override void Dispose(bool disposing) | ||||
| @@ -67,6 +71,12 @@ public abstract class DriverBase : DisposableObject | ||||
|     /// </summary> | ||||
|     public bool IsLogOut { get; set; } | ||||
|  | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 是否存储报文 | ||||
|     /// </summary> | ||||
|     public bool IsSaveLog { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 报文信息 | ||||
|     /// </summary> | ||||
| @@ -82,11 +92,14 @@ public abstract class DriverBase : DisposableObject | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     public abstract bool IsConnected(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 存储日志队列 | ||||
|     /// </summary> | ||||
|     protected ConcurrentQueue<BackendLog> _logQueues = new(); | ||||
|     /// <summary> | ||||
|     /// 设备报文 | ||||
|     /// </summary> | ||||
|     internal void NewMessage(TouchSocket.Core.LogLevel arg1, object arg2, string arg3, Exception arg4) | ||||
|     internal virtual void NewMessage(TouchSocket.Core.LogLevel arg1, object arg2, string arg3, Exception arg4) | ||||
|     { | ||||
|         if (IsLogOut) | ||||
|         { | ||||
| @@ -102,6 +115,27 @@ public abstract class DriverBase : DisposableObject | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     private async Task LogInsertAsync() | ||||
|     { | ||||
|         var db = DbContext.Db.CopyNew(); | ||||
|         while (!DisposedValue) | ||||
|         { | ||||
|             if (_logQueues.Count > 0) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var data = _logQueues.ToListWithDequeue(); | ||||
|                     await db.InsertableWithAttr(data).ExecuteCommandAsync();//入库 | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|  | ||||
|             await Task.Delay(5000); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 底层日志输出 | ||||
|   | ||||
| @@ -14,6 +14,8 @@ using Furion; | ||||
|  | ||||
| using Microsoft.Extensions.Logging; | ||||
|  | ||||
| using ThingsGateway.Foundation; | ||||
|  | ||||
| using TouchSocket.Core; | ||||
|  | ||||
| namespace ThingsGateway.Application; | ||||
| @@ -153,6 +155,32 @@ public abstract class UpLoadBase : DriverBase | ||||
|             _logger.Log_Out(arg1, arg2, arg3, arg4); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     internal override void NewMessage(TouchSocket.Core.LogLevel arg1, object arg2, string arg3, Exception arg4) | ||||
|     { | ||||
|         if (IsSaveLog) | ||||
|         { | ||||
|             if (arg3.StartsWith(FoundationConst.LogMessageHeader)) | ||||
|             { | ||||
|                 var customLevel = App.GetConfig<Microsoft.Extensions.Logging.LogLevel?>("Logging:LogLevel:BackendLog") ?? Microsoft.Extensions.Logging.LogLevel.Trace; | ||||
|                 if ((byte)arg1 < (byte)customLevel) | ||||
|                 { | ||||
|                     var logRuntime = new BackendLog | ||||
|                     { | ||||
|                         LogLevel = (Microsoft.Extensions.Logging.LogLevel)arg1, | ||||
|                         LogMessage = arg3, | ||||
|                         LogSource = "上传设备:" + CurDevice.Name, | ||||
|                         LogTime = SysDateTimeExtensions.CurrentDateTime, | ||||
|                         Exception = null, | ||||
|                     }; | ||||
|                     _logQueues.Enqueue(logRuntime); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         base.NewMessage(arg1, arg2, arg3, arg4); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,9 @@ public class DriverPluginSeedData : ISqlSugarEntitySeedData<DriverPlugin> | ||||
|     /// <inheritdoc/> | ||||
|     public IEnumerable<DriverPlugin> SeedData() | ||||
|     { | ||||
|         return SeedDataUtil.GetSeedData<DriverPlugin>("driver_plugin.json"); | ||||
|         return SeedDataUtil.GetSeedData<DriverPlugin>("driver_plugin.json") | ||||
|             .Concat(SeedDataUtil.GetSeedData<DriverPlugin>("pro_driver_plugin.json")) | ||||
|             .Concat(SeedDataUtil.GetSeedData<DriverPlugin>("custom_driver_plugin.json")) | ||||
|             ; | ||||
|     } | ||||
| } | ||||
| @@ -95,6 +95,23 @@ | ||||
|       "UpdateUser": "superAdmin", | ||||
|       "UpdateUserId": "212725263002001" | ||||
|     }, | ||||
|     { | ||||
|       "Id": "200001904", | ||||
|       "Title": "管理网关", | ||||
|       "Icon": "mdi-database-sync-outline", | ||||
|       "Component": "/gatewayconfig/manage", | ||||
|       "Category": "MENU", | ||||
|       "ParentId": "200001", | ||||
|       "SortCode": "3", | ||||
|       "TargetType": "SELF", | ||||
|       "CreateTime": "2023-02-26 01:02:12.089", | ||||
|       "CreateUser": "superAdmin", | ||||
|       "CreateUserId": "212725263002001", | ||||
|       "IsDelete": false, | ||||
|       "UpdateTime": "2023-03-03 18:01:49.2309339", | ||||
|       "UpdateUser": "superAdmin", | ||||
|       "UpdateUserId": "212725263002001" | ||||
|     }, | ||||
|     { | ||||
|       "Id": "200001004", | ||||
|       "Title": "运行状态", | ||||
|   | ||||
| @@ -22,6 +22,6 @@ public class OpenApiUserSeedData : ISqlSugarEntitySeedData<OpenApiUser> | ||||
|     /// <inheritdoc/> | ||||
|     public IEnumerable<OpenApiUser> SeedData() | ||||
|     { | ||||
|         return SeedDataUtil.GetSeedData<OpenApiUser>("gatewayopenapi_user.json"); | ||||
|         return SeedDataUtil.GetSeedData<OpenApiUser>("gateway_openapi_user.json"); | ||||
|     } | ||||
| } | ||||
| @@ -360,6 +360,8 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|  | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
| @@ -367,10 +369,17 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS | ||||
|     public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile file) | ||||
|     { | ||||
|         _fileService.ImportVerification(file); | ||||
|         using var fs = new MemoryStream(); | ||||
|         using var stream = file.OpenReadStream(512000000); | ||||
|         await stream.CopyToAsync(fs); | ||||
|         var sheetNames = MiniExcel.GetSheetNames(fs); | ||||
|         using var stream = new MemoryStream(); | ||||
|         using var fs = file.OpenReadStream(512000000); | ||||
|         await fs.CopyToAsync(stream); | ||||
|         return await PreviewAsync(stream); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(MemoryStream stream) | ||||
|     { | ||||
|         var sheetNames = MiniExcel.GetSheetNames(stream); | ||||
|         var deviceDicts = GetCacheList(false).ToDictionary(a => a.Name); | ||||
|         var pluginDicts = _driverPluginService.GetCacheList(false).ToDictionary(a => a.AssembleName); | ||||
|  | ||||
| @@ -381,7 +390,7 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS | ||||
|         foreach (var sheetName in sheetNames) | ||||
|         { | ||||
|             //单页数据 | ||||
|             var rows = fs.Query(useHeaderRow: true, sheetName: sheetName).Cast<IDictionary<string, object>>(); | ||||
|             var rows = stream.Query(useHeaderRow: true, sheetName: sheetName).Cast<IDictionary<string, object>>(); | ||||
|             #region 采集设备sheet | ||||
|             if (sheetName == ExportHelpers.CollectDeviceSheetName) | ||||
|             { | ||||
| @@ -496,8 +505,7 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|         return ImportPreviews; | ||||
|         return Task.FromResult(ImportPreviews); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|   | ||||
| @@ -63,6 +63,7 @@ public class BackendLogService : DbRepository<BackendLog>, IBackendLogService | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
| @@ -86,6 +87,8 @@ public class BackendLogService : DbRepository<BackendLog>, IBackendLogService | ||||
|     private ISugarQueryable<BackendLog> GetPage(BackendLogPageInput input) | ||||
|     { | ||||
|         var query = Context.Queryable<BackendLog>() | ||||
|                            .WhereIF(input.StartTime != null, a => a.LogTime >= input.StartTime.Value.ToLocalTime()) | ||||
|                            .WhereIF(input.EndTime != null, a => a.LogTime <= input.EndTime.Value.ToLocalTime()) | ||||
|                            .WhereIF(!string.IsNullOrEmpty(input.Source), it => it.LogSource.Contains(input.Source)) | ||||
|                            .WhereIF(!string.IsNullOrEmpty(input.Level), it => it.LogLevel.ToString().Contains(input.Level)); | ||||
|         for (int i = 0; i < input.SortField.Count; i++) | ||||
|   | ||||
| @@ -19,6 +19,15 @@ namespace ThingsGateway.Application; | ||||
| /// </summary> | ||||
| public class BackendLogPageInput : BasePageInput | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 开始时间 | ||||
|     /// </summary> | ||||
|     public DateTime? StartTime { get; set; } = DateTime.UtcNow.AddDays(-1); | ||||
|     /// <summary> | ||||
|     /// 结束时间 | ||||
|     /// </summary> | ||||
|     public DateTime? EndTime { get; set; } = DateTime.UtcNow.AddDays(1); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 日志源 | ||||
|     /// </summary> | ||||
| @@ -55,6 +64,14 @@ public class BackendLogInput | ||||
| /// </summary> | ||||
| public class RpcLogPageInput : BasePageInput | ||||
| { | ||||
|     /// <summary> | ||||
|     /// 开始时间 | ||||
|     /// </summary> | ||||
|     public DateTime? StartTime { get; set; } = DateTime.UtcNow.AddDays(-1); | ||||
|     /// <summary> | ||||
|     /// 结束时间 | ||||
|     /// </summary> | ||||
|     public DateTime? EndTime { get; set; } = DateTime.UtcNow.AddDays(1); | ||||
|     /// <summary> | ||||
|     /// 操作源 | ||||
|     /// </summary> | ||||
|   | ||||
| @@ -44,6 +44,8 @@ public class RpcLogService : DbRepository<RpcLog>, IRpcLogService | ||||
|     private ISugarQueryable<RpcLog> GetPage(RpcLogPageInput input) | ||||
|     { | ||||
|         var query = Context.Queryable<RpcLog>() | ||||
|                            .WhereIF(input.StartTime != null, a => a.LogTime >= input.StartTime.Value.ToLocalTime()) | ||||
|                            .WhereIF(input.EndTime != null, a => a.LogTime <= input.EndTime.Value.ToLocalTime()) | ||||
|                            .WhereIF(!string.IsNullOrEmpty(input.Source), it => it.OperateSource.Contains(input.Source)) | ||||
|                            .WhereIF(!string.IsNullOrEmpty(input.Object), it => it.OperateObject.Contains(input.Object)) | ||||
|                            .WhereIF(!string.IsNullOrEmpty(input.Method), it => it.OperateMethod.Contains(input.Method)); | ||||
| @@ -88,6 +90,7 @@ public class RpcLogService : DbRepository<RpcLog>, IRpcLogService | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -64,10 +64,10 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ | ||||
|     [OperDesc("复制上传设备")] | ||||
|     public async Task CopyDevAsync(IEnumerable<UploadDevice> input) | ||||
|     { | ||||
|         var newId = YitIdHelper.NextId(); | ||||
|         var newDevs = input.Adapt<List<UploadDevice>>(); | ||||
|         newDevs.ForEach(a => | ||||
|         { | ||||
|             var newId = YitIdHelper.NextId(); | ||||
|             a.Id = newId; | ||||
|             a.Name = "Copy-" + a.Name + "-" + newId.ToString(); | ||||
|         }); | ||||
| @@ -284,6 +284,7 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
| @@ -305,15 +306,19 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ | ||||
|         CacheStatic.Cache.Remove(ThingsGatewayCacheConst.Cache_UploadDevice);//cache删除 | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile file) | ||||
|     { | ||||
|         _fileService.ImportVerification(file); | ||||
|         using var fs = new MemoryStream(); | ||||
|         using var stream = file.OpenReadStream(512000000); | ||||
|         await stream.CopyToAsync(fs); | ||||
|         var sheetNames = MiniExcel.GetSheetNames(fs); | ||||
|         using var stream = new MemoryStream(); | ||||
|         using var fs = file.OpenReadStream(512000000); | ||||
|         await fs.CopyToAsync(stream); | ||||
|         return await PreviewAsync(stream); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(MemoryStream stream) | ||||
|     { | ||||
|         var sheetNames = MiniExcel.GetSheetNames(stream); | ||||
|         var deviceDicts = GetCacheList(false).ToDictionary(a => a.Name); | ||||
|         var pluginDicts = _driverPluginService.GetCacheList(false).ToDictionary(a => a.AssembleName); | ||||
|  | ||||
| @@ -324,7 +329,7 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ | ||||
|         foreach (var sheetName in sheetNames) | ||||
|         { | ||||
|             //单页数据 | ||||
|             var rows = (fs.Query(useHeaderRow: true, sheetName: sheetName)).Cast<IDictionary<string, object>>(); | ||||
|             var rows = (stream.Query(useHeaderRow: true, sheetName: sheetName)).Cast<IDictionary<string, object>>(); | ||||
|             #region 上传设备sheet | ||||
|             if (sheetName == ExportHelpers.UploadDeviceSheetName) | ||||
|             { | ||||
| @@ -434,7 +439,7 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ | ||||
|  | ||||
|  | ||||
|  | ||||
|         return ImportPreviews; | ||||
|         return Task.FromResult(ImportPreviews); | ||||
|     } | ||||
|     #endregion | ||||
| } | ||||
| @@ -129,11 +129,11 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|         { | ||||
|             uploadDevid = _uploadDeviceService.GetIdByName(input.UploadDeviceName); | ||||
|         } | ||||
|  | ||||
|         if (!string.IsNullOrEmpty(input.UploadDeviceName)) | ||||
|         { | ||||
|             var pageInfo = await query.ToPagedListAsync(input.Current, input.Size, a => a.VariablePropertys.ContainsKey(uploadDevid ?? 0));//分页 | ||||
|             var pageInfo = await query.ToPagedListAsync(input.Current, input.Size, a => SqlFunc.JsonLike(a.VariablePropertys, uploadDevid.ToString()));//分页 | ||||
|             return pageInfo; | ||||
|  | ||||
|         } | ||||
|         else | ||||
|         { | ||||
| @@ -313,6 +313,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
| @@ -406,6 +407,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|  | ||||
|         var memoryStream = new MemoryStream(); | ||||
|         await memoryStream.SaveAsAsync(sheets); | ||||
|         memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|         return memoryStream; | ||||
|     } | ||||
|  | ||||
| @@ -571,15 +573,21 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|         return ImportPreviews; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile file) | ||||
|     { | ||||
|         _fileService.ImportVerification(file); | ||||
|         using var fs = new MemoryStream(); | ||||
|         using var stream = file.OpenReadStream(512000000); | ||||
|         await stream.CopyToAsync(fs); | ||||
|         var sheetNames = MiniExcel.GetSheetNames(fs); | ||||
|         using var stream = new MemoryStream(); | ||||
|         using var fs = file.OpenReadStream(512000000); | ||||
|         await fs.CopyToAsync(stream); | ||||
|         return await PreviewAsync(stream); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(MemoryStream stream, List<CollectDevice> memCollectDevices = null, List<UploadDevice> memUploadDevices = null) | ||||
|     { | ||||
|  | ||||
|         var sheetNames = MiniExcel.GetSheetNames(stream); | ||||
|  | ||||
|         var dbVariables = await Context.Queryable<DeviceVariable>().Select(it => new { it.Id, it.Name }).ToListAsync(); | ||||
|         //转为字典,提高查找效率 | ||||
| @@ -591,7 +599,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|         foreach (var sheetName in sheetNames) | ||||
|         { | ||||
|             //单页数据 | ||||
|             var rows = fs.Query(useHeaderRow: true, sheetName: sheetName, configuration: new OpenXmlConfiguration { EnableSharedStringCache = false }) | ||||
|             var rows = stream.Query(useHeaderRow: true, sheetName: sheetName, configuration: new OpenXmlConfiguration { EnableSharedStringCache = false }) | ||||
|                 .Cast<IDictionary<string, object>>(); | ||||
|  | ||||
|             if (sheetName == ExportHelpers.DeviceVariableSheetName) | ||||
| @@ -600,7 +608,10 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|                 ImportPreviewOutput<DeviceVariable> importPreviewOutput = new(); | ||||
|                 ImportPreviews.Add(sheetName, importPreviewOutput); | ||||
|                 deviceImportPreview = importPreviewOutput; | ||||
|                 var cacheDeviceDicts = _collectDeviceService.GetCacheList(false).ToDictionary(a => a.Name); | ||||
|  | ||||
|                 var cacheDeviceDicts = memCollectDevices == null ? _collectDeviceService.GetCacheList(false).ToDictionary(a => a.Name) : | ||||
|                     _collectDeviceService.GetCacheList(false).Concat(memCollectDevices).ToDictionary(a => a.Name) | ||||
|                     ; | ||||
|                 //线程安全 | ||||
|                 var variables = new ConcurrentList<DeviceVariable>(); | ||||
|                 //并行注意线程安全 | ||||
| @@ -679,7 +690,9 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService | ||||
|                         .Where(a => a.GetCustomAttribute<VariablePropertyAttribute>() != null) | ||||
|                         .ToDictionary(a => a.FindDisplayAttribute(a => a.GetCustomAttribute<VariablePropertyAttribute>()?.Description)); | ||||
|  | ||||
|                     var cacheUpdeviceDicts = _uploadDeviceService.GetCacheList(false).ToDictionary(a => a.Name); | ||||
|                     var cacheUpdeviceDicts = memUploadDevices == null ? _uploadDeviceService.GetCacheList(false).ToDictionary(a => a.Name) : | ||||
|                     _uploadDeviceService.GetCacheList(false).Concat(memUploadDevices).ToDictionary(a => a.Name) | ||||
|                         ; | ||||
|                     rows.ParallelForEach(item => | ||||
|                        { | ||||
|                            try | ||||
|   | ||||
| @@ -44,6 +44,7 @@ public class Startup : AppStartup | ||||
|         services.AddHostedService<AlarmWorker>(); | ||||
|         services.AddHostedService<HistoryValueWorker>(); | ||||
|         services.AddHostedService<UploadDeviceWorker>(); | ||||
|         services.AddHostedService<ManageGatewayWorker>(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -6,7 +6,7 @@ | ||||
|  | ||||
| 	<ItemGroup> | ||||
| 	  <None Remove="SeedData\Json\driver_plugin.json" /> | ||||
| 	  <None Remove="SeedData\Json\gatewayopenapi_user.json" /> | ||||
| 	  <None Remove="SeedData\Json\gateway_openapi_user.json" /> | ||||
| 	  <None Remove="SeedData\Json\gateway_relation.json" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| @@ -24,7 +24,7 @@ | ||||
| 	  <Content Include="SeedData\Json\gateway_resource.json"> | ||||
| 	    <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
| 	  </Content> | ||||
| 	  <Content Include="SeedData\Json\gatewayopenapi_user.json"> | ||||
| 	  <Content Include="SeedData\Json\gateway_openapi_user.json"> | ||||
| 	    <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
| 	  </Content> | ||||
| 	  <Content Include="SeedData\Json\gateway_relation.json"> | ||||
| @@ -38,6 +38,7 @@ | ||||
| 		<PackageReference Include="CS-Script" Version="4.8.1" /> | ||||
| 		<!--CS-Script与Furion冲突,直接安装覆盖版本--> | ||||
| 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.7.0" /> | ||||
| 		<PackageReference Include="MQTTnet" Version="4.3.1.873" /> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| 	<ItemGroup> | ||||
|   | ||||
| @@ -1139,7 +1139,7 @@ | ||||
|             表达式扩展 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.Extensions.ExpressionEvaluatorExtensions.GetExpressionsResult(System.String,System.Object)"> | ||||
|         <member name="M:ThingsGateway.Application.Extensions.ExpressionEvaluatorExtensions.GetExpressionsResult(System.String,CodingSeb.ExpressionEvaluator.ExpressionEvaluator,System.Object)"> | ||||
|             <summary> | ||||
|             计算表达式:例如:raw*100,raw为原始值 | ||||
|             </summary> | ||||
| @@ -1250,50 +1250,50 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.TGAPPInfo"> | ||||
|         <member name="T:ThingsGateway.Application.APPInfo"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.Environment"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.Environment"> | ||||
|             <summary> | ||||
|             主机环境 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.FrameworkDescription"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.FrameworkDescription"> | ||||
|             <summary> | ||||
|             NET框架 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.HostName"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.HostName"> | ||||
|             <summary> | ||||
|             主机名称 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.OsArchitecture"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.OsArchitecture"> | ||||
|             <summary> | ||||
|             系统架构 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.RemoteIp"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.RemoteIp"> | ||||
|             <summary> | ||||
|             外网地址 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.Stage"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.Stage"> | ||||
|             <summary> | ||||
|             Stage环境 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.SystemOs"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.SystemOs"> | ||||
|             <summary> | ||||
|             操作系统 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.UpdateTime"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.UpdateTime"> | ||||
|             <summary> | ||||
|             更新时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.TGAPPInfo.DriveInfo"> | ||||
|         <member name="P:ThingsGateway.Application.APPInfo.DriveInfo"> | ||||
|             <summary> | ||||
|             当前磁盘信息 | ||||
|             </summary> | ||||
| @@ -1397,6 +1397,249 @@ | ||||
|         <member name="M:ThingsGateway.Application.BackendLogDatabaseLoggingWriter.Write(Furion.Logging.LogMessage,System.Boolean)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.ManageGatewayConfig"> | ||||
|             <summary> | ||||
|             ManageGatewayConfig | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.Enable"> | ||||
|             <summary> | ||||
|             启用 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.MqttBrokerIP"> | ||||
|             <summary> | ||||
|             MqttBrokerIP | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.MqttBrokerPort"> | ||||
|             <summary> | ||||
|             MqttBrokerPort | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.UserName"> | ||||
|             <summary> | ||||
|             UserName | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.Password"> | ||||
|             <summary> | ||||
|             Password | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.WriteRpcTopic"> | ||||
|             <summary> | ||||
|             WriteRpcTopic,Rpc返回为{WriteRpcTopic}/Return,只有这个topic才开放外部订阅权限 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.DBDownTopic"> | ||||
|             <summary> | ||||
|             DBDownTopic | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayConfig.DBUploadTopic"> | ||||
|             <summary> | ||||
|             DBUploadTopic | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.ClientGatewayConfig"> | ||||
|             <summary> | ||||
|             ClientGatewayConfig | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ClientGatewayConfig.GatewayId"> | ||||
|             <summary> | ||||
|             标识 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.MqttDBUploadRpcResult"> | ||||
|             <summary> | ||||
|             用于Mqtt Json传输,上传/下载配置信息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBUploadRpcResult.CollectDevices"> | ||||
|             <summary> | ||||
|             采集设备 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBUploadRpcResult.UploadDevices"> | ||||
|             <summary> | ||||
|             上传设备 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBUploadRpcResult.DeviceVariables"> | ||||
|             <summary> | ||||
|             变量 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.MqttDBDownRpc"> | ||||
|             <summary> | ||||
|             用于Mqtt Json传输,上传/下载配置信息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.CollectDevices"> | ||||
|             <summary> | ||||
|             采集设备 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.UploadDevices"> | ||||
|             <summary> | ||||
|             上传设备 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.DeviceVariables"> | ||||
|             <summary> | ||||
|             变量 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.IsCollectDevicesFullUp"> | ||||
|             <summary> | ||||
|             true=>删除全部后增加 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.IsUploadDevicesFullUp"> | ||||
|             <summary> | ||||
|             true=>删除全部后增加 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.IsDeviceVariablesFullUp"> | ||||
|             <summary> | ||||
|             true=>删除全部后增加 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.MqttDBDownRpc.IsRestart"> | ||||
|             <summary> | ||||
|             是否立即重启,使配置生效 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.ManageMqttRpcFrom"> | ||||
|             <summary> | ||||
|             MqttRpc传入 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcFrom.GatewayId"> | ||||
|             <summary> | ||||
|             标识 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcFrom.RpcId"> | ||||
|             <summary> | ||||
|             标识 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcFrom.WriteInfos"> | ||||
|             <summary> | ||||
|             "WriteInfos":{"test":"1"} | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.ManageMqttRpcResult"> | ||||
|             <summary> | ||||
|             MqttRpc输出 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcResult.GatewayId"> | ||||
|             <summary> | ||||
|             标识 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcResult.RpcId"> | ||||
|             <summary> | ||||
|             标识 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcResult.Message"> | ||||
|             <summary> | ||||
|             消息 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageMqttRpcResult.Success"> | ||||
|             <summary> | ||||
|             是否成功 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.ManageGatewayWorker"> | ||||
|             <summary> | ||||
|             ManageGatewayWorker | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Application.ManageGatewayWorker.restartLock"> | ||||
|             <summary> | ||||
|             全部重启锁 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.#ctor(Microsoft.Extensions.Logging.ILoggerFactory)"> | ||||
|             <inheritdoc cref="T:ThingsGateway.Application.ManageGatewayWorker"/> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayWorker.ClientStatuString"> | ||||
|             <summary> | ||||
|             服务状态 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.ManageGatewayWorker.ManageStatuString"> | ||||
|             <summary> | ||||
|             服务状态 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.StartAsync(System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.StopAsync(System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.ExecuteAsync(System.Threading.CancellationToken)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.GetClientGatewayDBAsync(System.String,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             获取子网关的配置信息 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.RestartAsync"> | ||||
|             <summary> | ||||
|             重启 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.SetClientGatewayDBAsync(System.String,ThingsGateway.Application.MqttDBDownRpc,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             下载配置信息到子网关 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.WriteVariableAsync(ThingsGateway.Application.ManageMqttRpcFrom,System.Int32,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             写入变量到子网关 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.GetClientGatewayAsync"> | ||||
|             <summary> | ||||
|             获取子网关列表 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.RpcDataExecuteAsync(System.String,System.String,System.Byte[],System.Int32,MQTTnet.Protocol.MqttQualityOfServiceLevel,System.Threading.CancellationToken)"> | ||||
|             <summary> | ||||
|             RPC请求子网关并返回,需要传入子网关ID,作为Topic参数一部分 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.ManageGatewayWorker.InitAsync"> | ||||
|             <summary> | ||||
|             初始化 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Application.ManageGatewayWorker.ClientGatewayConfig"> | ||||
|             <summary> | ||||
|             ClientGatewayConfig | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Application.ManageGatewayWorker.ManageGatewayConfig"> | ||||
|             <summary> | ||||
|             ManageGatewayConfig | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.CollectDeviceRunTime"> | ||||
|             <summary> | ||||
|             采集设备状态表示 | ||||
| @@ -1571,6 +1814,11 @@ | ||||
|             变量运行状态表示 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableRunTime.#ctor"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DeviceVariableRunTime.DeviceName"> | ||||
|             <summary> | ||||
|             设备名称 | ||||
| @@ -1598,7 +1846,7 @@ | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DeviceVariableRunTime.LastSetValue"> | ||||
|             <summary> | ||||
|             最近一次值 | ||||
|             上次值 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DeviceVariableRunTime.SetValue(System.Object,System.DateTime,System.Boolean)"> | ||||
| @@ -1978,6 +2226,11 @@ | ||||
|             是否输出日志 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverBase.IsSaveLog"> | ||||
|             <summary> | ||||
|             是否存储报文 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.DriverBase.Messages"> | ||||
|             <summary> | ||||
|             报文信息 | ||||
| @@ -1994,6 +2247,11 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="F:ThingsGateway.Application.DriverBase._logQueues"> | ||||
|             <summary> | ||||
|             存储日志队列 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.DriverBase.NewMessage(TouchSocket.Core.LogLevel,System.Object,System.String,System.Exception)"> | ||||
|             <summary> | ||||
|             设备报文 | ||||
| @@ -2352,6 +2610,9 @@ | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceService.PreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceService.PreviewAsync(System.IO.MemoryStream)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.CollectDeviceService.ImportAsync(System.Collections.Generic.Dictionary{System.String,ThingsGateway.Application.ImportPreviewOutputBase})"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
| @@ -2583,6 +2844,16 @@ | ||||
|             运行日志分页DTO | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.BackendLogPageInput.StartTime"> | ||||
|             <summary> | ||||
|             开始时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.BackendLogPageInput.EndTime"> | ||||
|             <summary> | ||||
|             结束时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.BackendLogPageInput.Source"> | ||||
|             <summary> | ||||
|             日志源 | ||||
| @@ -2613,6 +2884,16 @@ | ||||
|             RPC日志分页DTO | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.RpcLogPageInput.StartTime"> | ||||
|             <summary> | ||||
|             开始时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.RpcLogPageInput.EndTime"> | ||||
|             <summary> | ||||
|             结束时间 | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:ThingsGateway.Application.RpcLogPageInput.Source"> | ||||
|             <summary> | ||||
|             操作源 | ||||
| @@ -3029,6 +3310,9 @@ | ||||
|         <member name="M:ThingsGateway.Application.UploadDeviceService.PreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.UploadDeviceService.PreviewAsync(System.IO.MemoryStream)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Application.VariableAddInput"> | ||||
|             <summary> | ||||
|             添加变量DTO | ||||
| @@ -3285,6 +3569,9 @@ | ||||
|         <member name="M:ThingsGateway.Application.VariableService.PreviewAsync(Microsoft.AspNetCore.Components.Forms.IBrowserFile)"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.VariableService.PreviewAsync(System.IO.MemoryStream,System.Collections.Generic.List{ThingsGateway.Application.CollectDevice},System.Collections.Generic.List{ThingsGateway.Application.UploadDevice})"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Application.VariableService.ImportAsync(System.Collections.Generic.Dictionary{System.String,ThingsGateway.Application.ImportPreviewOutputBase})"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|   | ||||
| @@ -10,6 +10,9 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using CodingSeb.ExpressionEvaluator; | ||||
|  | ||||
| using Furion; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| using Mapster; | ||||
| @@ -48,6 +51,7 @@ public class AlarmWorker : BackgroundService | ||||
|     { | ||||
|         _logger = logger; | ||||
|         _globalDeviceData = ServiceHelper.Services.GetService<GlobalDeviceData>(); | ||||
|         expressionEvaluator.PreEvaluateVariable += ExpressionEvaluatorExtensions.Evaluator_PreEvaluateVariable; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 报警变化事件 | ||||
| @@ -73,7 +77,7 @@ public class AlarmWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult<SqlSugarClient>> GetAlarmDbAsync() | ||||
|     { | ||||
|         var ConfigService = ServiceHelper.Services.GetService<IConfigService>(); | ||||
|         var ConfigService = App.GetService<IConfigService>(); | ||||
|         var alarmEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_Enable))?.ConfigValue?.ToBoolean(); | ||||
|         var alarmDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_DbType))?.ConfigValue; | ||||
|         var alarmConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_AlarmConfig_Base, ThingsGatewayConfigConst.Config_Alarm_ConnStr))?.ConfigValue; | ||||
| @@ -233,7 +237,7 @@ public class AlarmWorker : BackgroundService | ||||
|     /// <summary> | ||||
|     /// 循环线程取消标识 | ||||
|     /// </summary> | ||||
|     public ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     private ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     /// <summary> | ||||
|     /// 全部重启锁 | ||||
|     /// </summary> | ||||
| @@ -371,6 +375,7 @@ public class AlarmWorker : BackgroundService | ||||
|             restartLock.Release(); | ||||
|         } | ||||
|     } | ||||
|     private ExpressionEvaluator expressionEvaluator = new(); | ||||
|  | ||||
|     private void AlarmAnalysis(DeviceVariableRunTime item) | ||||
|     { | ||||
| @@ -396,7 +401,7 @@ public class AlarmWorker : BackgroundService | ||||
|             //需更新报警,不管是否存在 | ||||
|             if (!string.IsNullOrEmpty(ex)) | ||||
|             { | ||||
|                 var data = ex.GetExpressionsResult(item.Value); | ||||
|                 var data = ex.GetExpressionsResult(expressionEvaluator, item.Value); | ||||
|                 if (data is bool result) | ||||
|                 { | ||||
|                     if (result) | ||||
| @@ -497,24 +502,24 @@ public class AlarmWorker : BackgroundService | ||||
|     private async Task InitAsync() | ||||
|     { | ||||
|         CacheDb = new("HistoryAlarmCache"); | ||||
|         CancellationTokenSource stoppingToken = StoppingTokens.Last(); | ||||
|         var stoppingToken = StoppingTokens.Last().Token; | ||||
|         RealAlarmTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"实时报警线程开始"); | ||||
|             while (!stoppingToken.Token.IsCancellationRequested) | ||||
|             while (!stoppingToken.IsCancellationRequested) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     await Task.Delay(500, stoppingToken.Token); | ||||
|                     await Task.Delay(500, stoppingToken); | ||||
|                     var list = DeviceVariables.ToListWithDequeue(); | ||||
|                     foreach (var item in list) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         if (stoppingToken.IsCancellationRequested) | ||||
|                             break; | ||||
|                         if (!item.AlarmEnable) continue; | ||||
|                         AlarmAnalysis(item); | ||||
|                     } | ||||
|                     if (stoppingToken.Token.IsCancellationRequested) | ||||
|                     if (stoppingToken.IsCancellationRequested) | ||||
|                         break; | ||||
|                 } | ||||
|                 catch (TaskCanceledException) | ||||
| @@ -539,7 +544,7 @@ public class AlarmWorker : BackgroundService | ||||
|             await Task.Yield();//返回线程控制,不再阻塞 | ||||
|             try | ||||
|             { | ||||
|                 await Task.Delay(500, stoppingToken.Token); | ||||
|                 await Task.Delay(500, stoppingToken); | ||||
|  | ||||
|                 var result = await GetAlarmDbAsync(); | ||||
|                 if (!result.IsSuccess) | ||||
| @@ -556,13 +561,13 @@ public class AlarmWorker : BackgroundService | ||||
|                     /***创建/更新单个表***/ | ||||
|                     try | ||||
|                     { | ||||
|                         await sqlSugarClient.Queryable<HistoryAlarm>().FirstAsync(stoppingToken.Token); | ||||
|                         await sqlSugarClient.Queryable<HistoryAlarm>().FirstAsync(stoppingToken); | ||||
|                         isSuccess = true; | ||||
|                         StatuString = OperResult.CreateSuccessResult(); | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         if (stoppingToken.IsCancellationRequested) | ||||
|                         { | ||||
|                             IsExited = true; | ||||
|                             return; | ||||
| @@ -582,13 +587,13 @@ public class AlarmWorker : BackgroundService | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     while (!stoppingToken.Token.IsCancellationRequested) | ||||
|                     while (!stoppingToken.IsCancellationRequested) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             await Task.Delay(500, stoppingToken.Token); | ||||
|                             await Task.Delay(500, stoppingToken); | ||||
|  | ||||
|                             if (stoppingToken.Token.IsCancellationRequested) | ||||
|                             if (stoppingToken.IsCancellationRequested) | ||||
|                                 break; | ||||
|  | ||||
|                             //缓存值 | ||||
| @@ -598,7 +603,7 @@ public class AlarmWorker : BackgroundService | ||||
|                                 var data = cacheData.SelectMany(a => a.CacheStr.FromJsonString<List<HistoryAlarm>>()).ToList(); | ||||
|                                 try | ||||
|                                 { | ||||
|                                     var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                     var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken); | ||||
|                                     await CacheDb.DeleteCacheData(cacheData.Select(a => a.Id).ToArray()); | ||||
|                                 } | ||||
|                                 catch (Exception ex) | ||||
| @@ -607,7 +612,7 @@ public class AlarmWorker : BackgroundService | ||||
|                                         _logger.LogWarning(ex, "写入历史报警失败"); | ||||
|                                 } | ||||
|                             } | ||||
|                             if (stoppingToken.Token.IsCancellationRequested) | ||||
|                             if (stoppingToken.IsCancellationRequested) | ||||
|                                 break; | ||||
|  | ||||
|  | ||||
| @@ -622,7 +627,7 @@ public class AlarmWorker : BackgroundService | ||||
|                                 //插入 | ||||
|                                 try | ||||
|                                 { | ||||
|                                     await sqlSugarClient.Insertable(list).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                     await sqlSugarClient.Insertable(list).ExecuteCommandAsync(stoppingToken); | ||||
|                                     isSuccess = true; | ||||
|                                 } | ||||
|                                 catch (Exception ex) | ||||
|   | ||||
| @@ -10,6 +10,9 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using CodingSeb.ExpressionEvaluator; | ||||
|  | ||||
| using Furion; | ||||
| using Furion.FriendlyException; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| @@ -79,7 +82,7 @@ public class CollectDeviceCore | ||||
|     { | ||||
|         _pluginService = ServiceHelper.Services.GetService<PluginSingletonService>(); | ||||
|         GlobalDeviceData = ServiceHelper.Services.GetService<GlobalDeviceData>(); | ||||
|         DriverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         DriverPluginService = App.GetService<IDriverPluginService>(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -206,6 +209,8 @@ public class CollectDeviceCore | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime); | ||||
|  | ||||
|             if (_device == null) | ||||
|             { | ||||
|                 _logger?.LogError(nameof(CollectDeviceRunTime) + "设备不能为null"); | ||||
| @@ -287,6 +292,8 @@ public class CollectDeviceCore | ||||
|         { | ||||
|             bool isUpDevice = Device != device; | ||||
|             _device = device; | ||||
|             Device.SetDeviceStatus(SysDateTimeExtensions.CurrentDateTime); | ||||
|  | ||||
|             _logger = ServiceHelper.Services.GetService<ILoggerFactory>().CreateLogger("采集设备:" + _device.Name); | ||||
|             //更新插件信息 | ||||
|             CreatDriver(); | ||||
| @@ -677,9 +684,9 @@ public class CollectDeviceCore | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         if (isRead&& !result.IsSuccess) | ||||
|                         if (isRead && !result.IsSuccess) | ||||
|                         { | ||||
|                             var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null,isOnline: false); | ||||
|                             var operResult = deviceVariableMethodSource.DeviceVariable.SetValue(null, isOnline: false); | ||||
|                             if (!operResult.IsSuccess) | ||||
|                             { | ||||
|                                 _logger?.LogWarning(operResult.Message, ToString()); | ||||
| @@ -716,6 +723,8 @@ public class CollectDeviceCore | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             ExpressionEvaluator expressionEvaluator = new(); | ||||
|             expressionEvaluator.PreEvaluateVariable += ExpressionEvaluatorExtensions.Evaluator_PreEvaluateVariable; | ||||
|             await easyLock.WaitAsync(); | ||||
|             if (IsShareChannel) _driver.InitDataAdapter(); | ||||
|             Dictionary<string, OperResult> results = new(); | ||||
| @@ -736,7 +745,7 @@ public class CollectDeviceCore | ||||
|                     object data; | ||||
|                     try | ||||
|                     { | ||||
|                         data = deviceVariable.WriteExpressions.GetExpressionsResult(rawdata); | ||||
|                         data = deviceVariable.WriteExpressions.GetExpressionsResult(expressionEvaluator, rawdata); | ||||
|                         writeInfoLists[deviceVariable] = JToken.FromObject(data); | ||||
|                     } | ||||
|                     catch (Exception ex) | ||||
|   | ||||
| @@ -30,7 +30,7 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|     /// <summary> | ||||
|     /// CancellationTokenSources | ||||
|     /// </summary> | ||||
|     public ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     private ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 线程 | ||||
| @@ -165,7 +165,7 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|     /// </summary> | ||||
|     protected async Task InitTaskAsync() | ||||
|     { | ||||
|         CancellationTokenSource stoppingToken = StoppingTokens.Last(); | ||||
|         var stoppingToken = StoppingTokens.Last().Token; | ||||
|         DeviceTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             var channelResult = CollectDeviceCores.FirstOrDefault().Driver.GetShareChannel(); | ||||
| @@ -184,11 +184,11 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|                 device.IsShareChannel = CollectDeviceCores.Count > 1; | ||||
|                 if (channelResult.IsSuccess) | ||||
|                 { | ||||
|                     await device.BeforeActionAsync(stoppingToken.Token, channelResult.Content); | ||||
|                     await device.BeforeActionAsync(stoppingToken, channelResult.Content); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     await device.BeforeActionAsync(stoppingToken.Token); | ||||
|                     await device.BeforeActionAsync(stoppingToken); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -206,7 +206,7 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|                             //如果是共享通道类型,需要每次转换时切换适配器 | ||||
|                             if (device.IsShareChannel) device.Driver.InitDataAdapter(); | ||||
|  | ||||
|                             var result = await device.RunActionAsync(stoppingToken.Token); | ||||
|                             var result = await device.RunActionAsync(stoppingToken); | ||||
|                             if (result == ThreadRunReturn.None) | ||||
|                             { | ||||
|                                 await Task.Delay(CycleInterval); | ||||
| @@ -224,7 +224,7 @@ public class CollectDeviceThread : IAsyncDisposable | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             await Task.Delay(1000, stoppingToken.Token); | ||||
|                             await Task.Delay(1000, stoppingToken); | ||||
|                         } | ||||
|                     } | ||||
|                     catch (TaskCanceledException) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
| using Furion.FriendlyException; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| @@ -38,13 +39,13 @@ public class CollectDeviceWorker : BackgroundService | ||||
|         ServiceHelper.Services = serviceProvider; | ||||
|         _logger = logger; | ||||
|         _pluginService = ServiceHelper.Services.GetService<PluginSingletonService>(); | ||||
|         _collectDeviceService = ServiceHelper.Services.GetService<ICollectDeviceService>(); | ||||
|         _collectDeviceService = App.GetService<ICollectDeviceService>(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 读取未停止的采集设备List | ||||
|     /// </summary> | ||||
|     public List<CollectDeviceCore> CollectDeviceCores => CollectDeviceThreads | ||||
|         .Where(a => !a.StoppingTokens.Any(b => b.IsCancellationRequested)) | ||||
|         .Where(a => a.CollectDeviceCores.Any(b => b.Device != null)) | ||||
|         .SelectMany(a => a.CollectDeviceCores).ToList(); | ||||
|  | ||||
|     /// <summary> | ||||
| @@ -95,10 +96,13 @@ public class CollectDeviceWorker : BackgroundService | ||||
|             await RemoveAllDeviceThreadAsync(); | ||||
|             //创建全部采集线程 | ||||
|             await CreatAllDeviceThreadsAsync(); | ||||
|             //开始全部采集线程 | ||||
|             await StartAllDeviceThreadsAsync(); | ||||
|  | ||||
|             //开始其他后台服务 | ||||
|             await StartOtherHostService(); | ||||
|  | ||||
|             //开始全部采集线程 | ||||
|             await StartAllDeviceThreadsAsync(); | ||||
|  | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
| @@ -411,7 +415,7 @@ public class CollectDeviceWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public Type GetDebugUI(long driverId) | ||||
|     { | ||||
|         var driverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         var driverPluginService = App.GetService<IDriverPluginService>(); | ||||
|         var driverPlugin = driverPluginService.GetDriverPluginById(driverId); | ||||
|         var driver = _pluginService.GetDriver(driverPlugin); | ||||
|         driver?.SafeDispose(); | ||||
| @@ -425,7 +429,7 @@ public class CollectDeviceWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public List<string> GetDeviceMethods(long devId) | ||||
|     { | ||||
|         var driverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         var driverPluginService = App.GetService<IDriverPluginService>(); | ||||
|         var driverId = _collectDeviceService.GetDeviceById(devId).PluginId; | ||||
|         var driverPlugin = driverPluginService.GetDriverPluginById(driverId); | ||||
|         var driver = (CollectBase)_pluginService.GetDriver(driverPlugin); | ||||
| @@ -442,14 +446,14 @@ public class CollectDeviceWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public List<DependencyProperty> GetDevicePropertys(long driverId, long devId = 0) | ||||
|     { | ||||
|         var driverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         var driverPluginService = App.GetService<IDriverPluginService>(); | ||||
|         var driverPlugin = driverPluginService.GetDriverPluginById(driverId); | ||||
|         var driver = _pluginService.GetDriver(driverPlugin); | ||||
|         var Propertys = _pluginService.GetDriverProperties(driver); | ||||
|         if (devId != 0) | ||||
|         { | ||||
|             var devcore = CollectDeviceCores.FirstOrDefault(it => it.Device.Id == devId); | ||||
|             devcore?.Device?.DevicePropertys?.ForEach(it => | ||||
|             var devcore = App.GetService<CollectDeviceService>().GetDeviceById(devId); | ||||
|             devcore?.DevicePropertys?.ForEach(it => | ||||
|             { | ||||
|                 var dependencyProperty = Propertys.FirstOrDefault(a => a.PropertyName == it.PropertyName); | ||||
|                 if (dependencyProperty != null) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| using Mapster; | ||||
| @@ -59,7 +60,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public async Task<OperResult<SqlSugarClient>> GetHisDbAsync() | ||||
|     { | ||||
|         var ConfigService = ServiceHelper.Services.GetService<IConfigService>(); | ||||
|         var ConfigService = App.GetService<IConfigService>(); | ||||
|         var hisEnable = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_Enable))?.ConfigValue?.ToBoolean(); | ||||
|         var hisDbType = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_DbType))?.ConfigValue; | ||||
|         var hisConnstr = (await ConfigService.GetByConfigKeyAsync(ThingsGatewayConfigConst.ThingGateway_HisConfig_Base, ThingsGatewayConfigConst.Config_His_ConnStr))?.ConfigValue; | ||||
| @@ -144,7 +145,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|     /// <summary> | ||||
|     /// 循环线程取消标识 | ||||
|     /// </summary> | ||||
|     public ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     private ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     /// <summary> | ||||
|     /// 全部重启锁 | ||||
|     /// </summary> | ||||
| @@ -163,7 +164,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|     private async Task InitAsync() | ||||
|     { | ||||
|         CacheDb = new("HistoryValueCache"); | ||||
|         CancellationTokenSource stoppingToken = StoppingTokens.Last(); | ||||
|         var stoppingToken = StoppingTokens.Last().Token; | ||||
|         HistoryValueTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"历史数据线程开始"); | ||||
| @@ -185,13 +186,13 @@ public class HistoryValueWorker : BackgroundService | ||||
|                     /***创建/更新单个表***/ | ||||
|                     try | ||||
|                     { | ||||
|                         await sqlSugarClient.Queryable<HistoryValue>().FirstAsync(stoppingToken.Token); | ||||
|                         await sqlSugarClient.Queryable<HistoryValue>().FirstAsync(stoppingToken); | ||||
|                         LastIsSuccess = true; | ||||
|                         StatuString = OperResult.CreateSuccessResult(); | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         if (stoppingToken.IsCancellationRequested) | ||||
|                         { | ||||
|                             IsExited = true; | ||||
|                             return; | ||||
| @@ -212,14 +213,14 @@ public class HistoryValueWorker : BackgroundService | ||||
|                     } | ||||
|                     IsExited = false; | ||||
|  | ||||
|                     while (!stoppingToken.Token.IsCancellationRequested) | ||||
|                     while (!stoppingToken.IsCancellationRequested) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             await Task.Delay(500, stoppingToken.Token); | ||||
|                             await Task.Delay(500, stoppingToken); | ||||
|  | ||||
|  | ||||
|                             if (stoppingToken.Token.IsCancellationRequested) | ||||
|                             if (stoppingToken.IsCancellationRequested) | ||||
|                                 break; | ||||
|  | ||||
|                             //缓存值 | ||||
| @@ -227,7 +228,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                             var data = cacheData.SelectMany(a => a.CacheStr.FromJsonString<List<HistoryValue>>()).ToList(); | ||||
|                             try | ||||
|                             { | ||||
|                                 var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                 var count = await sqlSugarClient.Insertable(data).ExecuteCommandAsync(stoppingToken); | ||||
|                                 await CacheDb.DeleteCacheData(cacheData.Select(a => a.Id).ToArray()); | ||||
|                             } | ||||
|                             catch (Exception ex) | ||||
| @@ -236,7 +237,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                                     _logger.LogWarning(ex, "写入历史数据失败"); | ||||
|                             } | ||||
|  | ||||
|                             if (stoppingToken.Token.IsCancellationRequested) | ||||
|                             if (stoppingToken.IsCancellationRequested) | ||||
|                                 break; | ||||
|                             var collectList = DeviceVariables.ToListWithDequeue(); | ||||
|                             if (collectList.Count != 0) | ||||
| @@ -247,7 +248,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                                 //插入 | ||||
|                                 try | ||||
|                                 { | ||||
|                                     count = await sqlSugarClient.Insertable(collecthis).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                     count = await sqlSugarClient.Insertable(collecthis).ExecuteCommandAsync(stoppingToken); | ||||
|                                     LastIsSuccess = true; | ||||
|                                 } | ||||
|                                 catch (Exception ex) | ||||
| @@ -263,7 +264,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                             } | ||||
|  | ||||
|  | ||||
|                             if (stoppingToken.Token.IsCancellationRequested) | ||||
|                             if (stoppingToken.IsCancellationRequested) | ||||
|                                 break; | ||||
|                             var changeList = ChangeDeviceVariables.ToListWithDequeue(); | ||||
|                             if (changeList.Count != 0) | ||||
| @@ -274,7 +275,7 @@ public class HistoryValueWorker : BackgroundService | ||||
|                                 //插入 | ||||
|                                 try | ||||
|                                 { | ||||
|                                     count = await sqlSugarClient.Insertable(changehis).ExecuteCommandAsync(stoppingToken.Token); | ||||
|                                     count = await sqlSugarClient.Insertable(changehis).ExecuteCommandAsync(stoppingToken); | ||||
|                                     LastIsSuccess = true; | ||||
|                                 } | ||||
|                                 catch (Exception ex) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| @@ -83,7 +84,7 @@ public class MemoryVariableWorker : BackgroundService | ||||
|     /// <summary> | ||||
|     /// 循环线程取消标识 | ||||
|     /// </summary> | ||||
|     public ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     private ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     private Task MemoryWorkerTask; | ||||
|     /// <summary> | ||||
|     /// 全部重启锁 | ||||
| @@ -94,23 +95,23 @@ public class MemoryVariableWorker : BackgroundService | ||||
|     /// </summary> | ||||
|     public async Task InitAsync() | ||||
|     { | ||||
|         CancellationTokenSource stoppingToken = StoppingTokens.Last(); | ||||
|         var stoppingToken = StoppingTokens.Last().Token; | ||||
|         MemoryWorkerTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             _logger?.LogInformation($"中间变量计算线程开始"); | ||||
|             try | ||||
|             { | ||||
|                 var variableService = ServiceHelper.Services.GetService<IVariableService>(); | ||||
|                 var variableService = App.GetService<IVariableService>(); | ||||
|                 var data = await variableService.GetMemoryVariableRuntimeAsync(); | ||||
|                 _globalDeviceData.MemoryVariables = new(data); | ||||
|                 StatuString = OperResult.CreateSuccessResult(); | ||||
|                 while (!stoppingToken.Token.IsCancellationRequested) | ||||
|                 while (!stoppingToken.IsCancellationRequested) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         await Task.Delay(500, stoppingToken.Token); | ||||
|                         await Task.Delay(500, stoppingToken); | ||||
|  | ||||
|                         if (stoppingToken.Token.IsCancellationRequested) | ||||
|                         if (stoppingToken.IsCancellationRequested) | ||||
|                             break; | ||||
|                         var isSuccess = true; | ||||
|                         foreach (var item in _globalDeviceData.MemoryVariables) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
| using Furion.FriendlyException; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| @@ -57,7 +58,7 @@ public class UploadDeviceCore | ||||
|     public UploadDeviceCore() | ||||
|     { | ||||
|         _pluginService = ServiceHelper.Services.GetService<PluginSingletonService>(); | ||||
|         DriverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         DriverPluginService = App.GetService<IDriverPluginService>(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|   | ||||
| @@ -26,7 +26,7 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|     /// <summary> | ||||
|     /// CancellationTokenSources | ||||
|     /// </summary> | ||||
|     public ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|     private ConcurrentList<CancellationTokenSource> StoppingTokens = new(); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 线程 | ||||
| @@ -154,7 +154,7 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|     /// </summary> | ||||
|     protected async Task InitTaskAsync() | ||||
|     { | ||||
|         CancellationTokenSource stoppingToken = StoppingTokens.Last(); | ||||
|         var stoppingToken = StoppingTokens.Last().Token; | ||||
|         DeviceTask = await Task.Factory.StartNew(async () => | ||||
|         { | ||||
|             LoggerGroup log = UploadDeviceCores.FirstOrDefault().Driver.LogMessage; | ||||
| @@ -168,7 +168,7 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|                 //添加通道报文到每个设备 | ||||
|                 var data = new EasyLogger(device.Driver.NewMessage) { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|                 log.AddLogger(data); | ||||
|                 await device.BeforeActionAsync(stoppingToken.Token); | ||||
|                 await device.BeforeActionAsync(stoppingToken); | ||||
|             } | ||||
|  | ||||
|             while (!stoppingToken.IsCancellationRequested) | ||||
| @@ -183,7 +183,7 @@ public class UploadDeviceThread : IAsyncDisposable | ||||
|                         if (device.IsInitSuccess) | ||||
|                         { | ||||
|  | ||||
|                             var result = await device.RunActionAsync(stoppingToken.Token); | ||||
|                             var result = await device.RunActionAsync(stoppingToken); | ||||
|                             if (result == ThreadRunReturn.None) | ||||
|                             { | ||||
|                                 await Task.Delay(CycleInterval); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
| using Furion.FriendlyException; | ||||
| using Furion.Logging.Extensions; | ||||
|  | ||||
| @@ -41,13 +42,13 @@ public class UploadDeviceWorker : BackgroundService | ||||
|         _logger = logger; | ||||
|  | ||||
|         _pluginService = ServiceHelper.Services.GetService<PluginSingletonService>(); | ||||
|         _uploadDeviceService = ServiceHelper.Services.GetService<IUploadDeviceService>(); | ||||
|         _uploadDeviceService = App.GetService<IUploadDeviceService>(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// 上传设备List | ||||
|     /// </summary> | ||||
|     public List<UploadDeviceCore> UploadDeviceCores => UploadDeviceThreads | ||||
|         .Where(a => !a.StoppingTokens.Any(b => b.IsCancellationRequested)) | ||||
|         .Where(a => a.UploadDeviceCores.Any(b => b.Device != null)) | ||||
|         .SelectMany(a => a.UploadDeviceCores).ToList(); | ||||
|     /// <summary> | ||||
|     /// 全部设备子线程 | ||||
| @@ -294,15 +295,15 @@ public class UploadDeviceWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public List<DependencyProperty> GetDevicePropertys(long driverId, long devId = 0) | ||||
|     { | ||||
|         var driverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         var driverPluginService = App.GetService<IDriverPluginService>(); | ||||
|         var driverPlugin = driverPluginService.GetDriverPluginById(driverId); | ||||
|  | ||||
|         var driver = _pluginService.GetDriver(driverPlugin); | ||||
|         var Propertys = _pluginService.GetDriverProperties(driver); | ||||
|         if (devId != 0) | ||||
|         { | ||||
|             var devcore = UploadDeviceCores.FirstOrDefault(it => it.Device.Id == devId); | ||||
|             devcore?.Device?.DevicePropertys?.ForEach(it => | ||||
|             var devcore = App.GetService<UploadDeviceService>().GetDeviceById(devId); | ||||
|             devcore?.DevicePropertys?.ForEach(it => | ||||
|             { | ||||
|                 var dependencyProperty = Propertys.FirstOrDefault(a => a.PropertyName == it.PropertyName); | ||||
|                 if (dependencyProperty != null) | ||||
| @@ -325,7 +326,7 @@ public class UploadDeviceWorker : BackgroundService | ||||
|     /// <returns></returns> | ||||
|     public List<DependencyProperty> GetVariablePropertys(long driverId, List<DependencyProperty> dependencyProperties = null) | ||||
|     { | ||||
|         var driverPluginService = ServiceHelper.Services.GetService<IDriverPluginService>(); | ||||
|         var driverPluginService = App.GetService<IDriverPluginService>(); | ||||
|         var driverPlugin = driverPluginService.GetDriverPluginById(driverId); | ||||
|         var driver = (UpLoadBase)_pluginService.GetDriver(driverPlugin); | ||||
|         var Propertys = _pluginService.GetDriverVariableProperties(driver); | ||||
|   | ||||
| @@ -75,30 +75,33 @@ | ||||
|                                         (item.Value.HasError ? "出现错误" : "验证成功") | ||||
|                                         ) | ||||
|                                 </MSubheader> | ||||
|  | ||||
|                                 <MVirtualScroll Context="item1" Height=300 OverscanCount=2 ItemSize="60" Items="item.Value.Results"> | ||||
|                                     <ItemContent> | ||||
|                                         <MListItem> | ||||
|                                             <MListItemAction> | ||||
|                                                 <MChip Class="ma-2"> | ||||
|                                                     @( | ||||
|                                 if (item.Value.HasError) | ||||
|                                 { | ||||
|                                     <MVirtualScroll Context="item1" Height=300 OverscanCount=2 ItemSize="60" Items="item.Value.Results.Where(a=>!a.isSuccess).ToList()"> | ||||
|                                         <ItemContent> | ||||
|                                             <MListItem> | ||||
|                                                 <MListItemAction> | ||||
|                                                     <MChip Class="ma-2"> | ||||
|                                                         @( | ||||
|                                             $"第{item1.row}行" | ||||
|                                             ) | ||||
|                                                 </MChip> | ||||
|                                             </MListItemAction> | ||||
|                                                     </MChip> | ||||
|                                                 </MListItemAction> | ||||
|  | ||||
|                                             <MListItemContent> | ||||
|                                                 <MListItemTitle Class=@((item1.isSuccess?"green--text":"red--text"))> | ||||
|                                                     <strong>@item1.resultString</strong> | ||||
|                                                 </MListItemTitle> | ||||
|                                             </MListItemContent> | ||||
|                                                 <MListItemContent> | ||||
|                                                     <MListItemTitle Class=@((item1.isSuccess?"green--text":"red--text"))> | ||||
|                                                         <strong>@item1.resultString</strong> | ||||
|                                                     </MListItemTitle> | ||||
|                                                 </MListItemContent> | ||||
|  | ||||
|                                         </MListItem> | ||||
|                                             </MListItem> | ||||
|  | ||||
|                                         <MDivider></MDivider> | ||||
|                                             <MDivider></MDivider> | ||||
|  | ||||
|                                     </ItemContent> | ||||
|                                 </MVirtualScroll> | ||||
|                                         </ItemContent> | ||||
|                                     </MVirtualScroll> | ||||
|                                 } | ||||
|                                  | ||||
|  | ||||
|                             } | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Microsoft.JSInterop; | ||||
| @@ -65,11 +67,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|     /// 写入值 | ||||
|     /// </summary> | ||||
|     public virtual string WriteValue { get; set; } | ||||
|     [Inject] | ||||
|     private ICollectDeviceService CollectDeviceService { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     private IVariableService VariableService { get; set; } | ||||
|     [Inject] | ||||
|     private InitTimezone InitTimezone { get; set; } | ||||
|  | ||||
| @@ -133,7 +131,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             await CollectDeviceService.AddAsync(data); | ||||
|             await App.GetService<CollectDeviceService>().AddAsync(data); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
| @@ -151,7 +149,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             await VariableService.AddBatchAsync(data); | ||||
|             await App.GetService<VariableService>().AddBatchAsync(data); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
| @@ -172,7 +170,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             using var memoryStream = new MemoryStream(); | ||||
|             StreamWriter writer = new(memoryStream); | ||||
|             using StreamWriter writer = new(memoryStream); | ||||
|             foreach (var item in values) | ||||
|             { | ||||
|                 writer.WriteLine(item); | ||||
| @@ -199,8 +197,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             using var memoryStream = await CollectDeviceService.ExportFileAsync(new List<CollectDevice>() { data }); | ||||
|             memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|             using var memoryStream = await App.GetService<CollectDeviceService>().ExportFileAsync(new List<CollectDevice>() { data }); | ||||
|             using var streamRef = new DotNetStreamReference(stream: memoryStream); | ||||
|             _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|             await _helper.InvokeVoidAsync("downloadFileFromStream", $"设备导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
| @@ -221,8 +218,7 @@ public abstract class DriverDebugUIBase : ComponentBase, IDisposable | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             using var memoryStream = await VariableService.ExportFileAsync(data, devName); | ||||
|             memoryStream.Seek(0, SeekOrigin.Begin); | ||||
|             using var memoryStream = await App.GetService<VariableService>().ExportFileAsync(data, devName); | ||||
|             using var streamRef = new DotNetStreamReference(stream: memoryStream); | ||||
|             _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|             await _helper.InvokeVoidAsync("downloadFileFromStream", $"变量导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
|   | ||||
| @@ -82,7 +82,7 @@ public partial class TcpClientPage | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)).SetBufferLength(300); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)); | ||||
|         //载入配置 | ||||
|         TcpClientEx.Setup(config); | ||||
|         return TcpClientEx; | ||||
| @@ -96,7 +96,7 @@ public partial class TcpClientPage | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)).SetBufferLength(300); | ||||
|         config.SetRemoteIPHost(new IPHost(IP + ":" + Port)); | ||||
|         TcpClientEx = new TcpClientEx(); | ||||
|         TcpClientEx.Setup(config); | ||||
|         base.OnInitialized(); | ||||
|   | ||||
| @@ -72,7 +72,6 @@ public partial class TcpServerPage | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); | ||||
|         config.SetBufferLength(300); | ||||
|         //载入配置 | ||||
|         TcpServer.Setup(config); | ||||
|         return TcpServer; | ||||
| @@ -88,7 +87,6 @@ public partial class TcpServerPage | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetListenIPHosts(new IPHost[] { new IPHost(ip + ":" + port) }); | ||||
|         config.SetBufferLength(300); | ||||
|         TcpServer = new TcpService(); | ||||
|         TcpServer.Setup(config); | ||||
|         base.OnInitialized(); | ||||
|   | ||||
| @@ -71,7 +71,7 @@ public partial class UdpSessionPage : IDisposable | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(ip + ":" + port)).SetBufferLength(300); | ||||
|         config.SetRemoteIPHost(new IPHost(ip + ":" + port)); | ||||
|         config.SetBindIPHost(new IPHost(0)); | ||||
|         //载入配置 | ||||
|         UdpSession.Setup(config); | ||||
| @@ -88,7 +88,7 @@ public partial class UdpSessionPage : IDisposable | ||||
|         var LogMessage = new TouchSocket.Core.LoggerGroup() { LogLevel = TouchSocket.Core.LogLevel.Trace }; | ||||
|         LogMessage.AddLogger(new EasyLogger(LogOut) { LogLevel = TouchSocket.Core.LogLevel.Trace }); | ||||
|         config.ConfigureContainer(a => a.RegisterSingleton<ILog>(LogMessage)); | ||||
|         config.SetRemoteIPHost(new IPHost(ip + ":" + port)).SetBufferLength(300); | ||||
|         config.SetRemoteIPHost(new IPHost(ip + ":" + port)); | ||||
|         config.SetBindIPHost(new IPHost(0)); | ||||
|         UdpSession = new UdpSession(); | ||||
|         UdpSession.Setup(config); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
|  | ||||
| @page "/gatewaylog/backendlog" | ||||
| @using System.Linq.Expressions; | ||||
| @inject IBackendLogService BackendLogService | ||||
|   | ||||
| @inject UserResoures UserResoures | ||||
| @namespace ThingsGateway.Blazor | ||||
| @using BlazorComponent; | ||||
| @@ -32,6 +32,30 @@ | ||||
|                 IsShowDetailButton | ||||
|                 IsShowQueryButton> | ||||
|     <SearchTemplate> | ||||
|  | ||||
|  | ||||
|         <MMenu CloseOnContentClick="false" OffsetY Context="menu"> | ||||
|             <ActivatorContent> | ||||
|                 <MTextField Dense Readonly Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " | ||||
|                             Value="context.StartTime.Value.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)" | ||||
|                 @attributes="menu.Attrs" Outlined Label=@context.Description(x => x.StartTime) /> | ||||
|             </ActivatorContent> | ||||
|             <ChildContent> | ||||
|                 <AppDateTimePicker @bind-Value="context.StartTime"></AppDateTimePicker> | ||||
|             </ChildContent> | ||||
|         </MMenu> | ||||
|  | ||||
|         <MMenu CloseOnContentClick="false" OffsetY Context="menu"> | ||||
|             <ActivatorContent> | ||||
|                 <MTextField Dense Readonly Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " | ||||
|                             Value="context.EndTime.Value.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)" Clearable | ||||
|                 @attributes="menu.Attrs" Outlined Label=@context.Description(x => x.EndTime) /> | ||||
|             </ActivatorContent> | ||||
|             <ChildContent> | ||||
|                 <AppDateTimePicker @bind-Value="context.EndTime"></AppDateTimePicker> | ||||
|             </ChildContent> | ||||
|         </MMenu> | ||||
|  | ||||
|         <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " @bind-Value="context.Source" | ||||
|                         Outlined Label=@context.Description(x => x.Source) /> | ||||
|         <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " @bind-Value="context.Level" | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| @@ -30,12 +32,14 @@ public partial class BackendLogPage | ||||
|     [Inject] | ||||
|     AjaxService AjaxService { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     InitTimezone InitTimezone { get; set; } | ||||
|     private async Task ClearClickAsync() | ||||
|     { | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("删除", "确定 ?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await BackendLogService.DeleteAsync(); | ||||
|             await App.GetService<BackendLogService>().DeleteAsync(); | ||||
|             await _datatable?.QueryClickAsync(); | ||||
|         } | ||||
|     } | ||||
| @@ -54,7 +58,7 @@ public partial class BackendLogPage | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<BackendLog>> QueryCallAsync(BackendLogPageInput input) | ||||
|     { | ||||
|         var data = await BackendLogService.PageAsync(input); | ||||
|         var data = await App.GetService<BackendLogService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
| } | ||||
| @@ -14,6 +14,7 @@ | ||||
| @namespace ThingsGateway.Blazor | ||||
| @using System.Linq.Expressions; | ||||
| @using BlazorComponent; | ||||
| @using Furion; | ||||
| @using Mapster; | ||||
| @using Masa.Blazor | ||||
| @using Masa.Blazor.Presets; | ||||
| @@ -22,11 +23,11 @@ | ||||
| @using ThingsGateway.Admin.Blazor.Core; | ||||
| @using ThingsGateway.Admin.Blazor; | ||||
| @using ThingsGateway.Application; | ||||
| @inject ICollectDeviceService CollectDeviceService | ||||
|   | ||||
| @attribute [Authorize] | ||||
| @inherits BaseComponentBase | ||||
| @inject UserResoures UserResoures | ||||
| @inject IDriverPluginService DriverPluginService | ||||
|   | ||||
| @layout MainLayout | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @if (IsMobile) | ||||
| @@ -172,7 +173,7 @@ else | ||||
|                 case nameof(context.Item.PluginId): | ||||
|                         <span title=@context.Value> | ||||
|                         @( | ||||
|                             DriverPluginService.GetNameById(context.Item.PluginId) | ||||
|                             App.GetService<DriverPluginService>().GetNameById(context.Item.PluginId) | ||||
|                                 ) | ||||
|                     </span> | ||||
|                     break; | ||||
|   | ||||
| @@ -57,8 +57,8 @@ public partial class CollectDevicePage | ||||
|  | ||||
|     private async Task AddCallAsync(CollectDeviceAddInput input) | ||||
|     { | ||||
|         await CollectDeviceService.AddAsync(input); | ||||
|         CollectDevices = CollectDeviceService.GetCacheList(); | ||||
|         await App.GetService<CollectDeviceService>().AddAsync(input); | ||||
|         CollectDevices = App.GetService<CollectDeviceService>().GetCacheList(); | ||||
|         _deviceGroups = CollectDevices?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
| @@ -71,7 +71,7 @@ public partial class CollectDevicePage | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         await CollectDeviceService.CopyDevAndVarAsync(data); | ||||
|         await App.GetService<CollectDeviceService>().CopyDevAndVarAsync(data); | ||||
|         await DatatableQueryAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("复制成功", AlertTypes.Success); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
| @@ -85,7 +85,7 @@ public partial class CollectDevicePage | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         await CollectDeviceService.CopyDevAsync(data); | ||||
|         await App.GetService<CollectDeviceService>().CopyDevAsync(data); | ||||
|         await DatatableQueryAsync(); | ||||
|         await PopupService.EnqueueSnackbarAsync("复制成功", AlertTypes.Success); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
| @@ -98,15 +98,15 @@ public partial class CollectDevicePage | ||||
|  | ||||
|     private async Task DeleteCallAsync(IEnumerable<CollectDevice> input) | ||||
|     { | ||||
|         await CollectDeviceService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         CollectDevices = CollectDeviceService.GetCacheList(); | ||||
|         await App.GetService<CollectDeviceService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         CollectDevices = App.GetService<CollectDeviceService>().GetCacheList(); | ||||
|         _deviceGroups = CollectDevices?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file) | ||||
|     { | ||||
|         return CollectDeviceService.PreviewAsync(file); | ||||
|         return App.GetService<CollectDeviceService>().PreviewAsync(file); | ||||
|     } | ||||
|     async Task DownExportAsync(CollectDevicePageInput input = null) | ||||
|     { | ||||
| @@ -133,8 +133,8 @@ public partial class CollectDevicePage | ||||
|  | ||||
|     private async Task EditCallAsync(CollectDeviceEditInput input) | ||||
|     { | ||||
|         await CollectDeviceService.EditAsync(input); | ||||
|         CollectDevices = CollectDeviceService.GetCacheList(); | ||||
|         await App.GetService<CollectDeviceService>().EditAsync(input); | ||||
|         CollectDevices = App.GetService<CollectDeviceService>().GetCacheList(); | ||||
|         _deviceGroups = CollectDevices?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
| @@ -147,13 +147,13 @@ public partial class CollectDevicePage | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<CollectDevice>> QueryCallAsync(CollectDevicePageInput input) | ||||
|     { | ||||
|         var data = await CollectDeviceService.PageAsync(input); | ||||
|         var data = await App.GetService<CollectDeviceService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
|  | ||||
|     async Task SaveDeviceImportAsync(Dictionary<string, ImportPreviewOutputBase> data) | ||||
|     { | ||||
|         await CollectDeviceService.ImportAsync(data); | ||||
|         await App.GetService<CollectDeviceService>().ImportAsync(data); | ||||
|         await DatatableQueryAsync(); | ||||
|         ImportExcel.IsShowImport = false; | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|   | ||||
| @@ -19,8 +19,7 @@ | ||||
| @using ThingsGateway.Admin.Blazor; | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @using ThingsGateway.Application; | ||||
|  | ||||
| @inject IConfigService ConfigService | ||||
|   | ||||
| @namespace ThingsGateway.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -56,7 +56,7 @@ public partial class ConfigPage | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("确认", "保存配置后将重启报警服务,是否确定?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await ConfigService.EditBatchAsync(_alarmConfig); | ||||
|             await App.GetService<ConfigService>().EditBatchAsync(_alarmConfig); | ||||
|             await AlarmHostService.RestartAsync(); | ||||
|             await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|         } | ||||
| @@ -67,7 +67,7 @@ public partial class ConfigPage | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("确认", "保存配置后将重启历史服务,是否确定?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await ConfigService.EditBatchAsync(_hisConfig); | ||||
|             await App.GetService<ConfigService>().EditBatchAsync(_hisConfig); | ||||
|             await HistoryValueHostService.RestartAsync(); | ||||
|             await PopupService.EnqueueSnackbarAsync("成功", AlertTypes.Success); | ||||
|         } | ||||
|   | ||||
| @@ -24,14 +24,12 @@ | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @using ThingsGateway.Application; | ||||
| @using TouchSocket.Core; | ||||
| @inject ICollectDeviceService CollectDeviceService | ||||
| @inject IUploadDeviceService UploadDeviceService | ||||
|  | ||||
|   | ||||
| @attribute [Authorize] | ||||
| @inherits BaseComponentBase | ||||
| @inject UserResoures UserResoures | ||||
| @inject NavigationManager NavigationManager | ||||
| @inject IDriverPluginService DriverPluginService | ||||
|   | ||||
| @layout MainLayout | ||||
| <MSheet Style="overflow:auto"> | ||||
|  | ||||
| @@ -253,6 +251,23 @@ | ||||
|                                             </ChildContent> | ||||
|                                         </MTooltip> | ||||
|  | ||||
|                                         <MTooltip Bottom Context="tip"> | ||||
|                                             <ActivatorContent> | ||||
|                                                 <MButton Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicepause")) Class="mx-2" @attributes="@tip.Attrs" Dark Fab Small | ||||
|                                                          OnClick=@(()=> | ||||
|                                                  { | ||||
|                                                  if(collectDeviceInfoItem.Driver!=null) | ||||
|                                                  collectDeviceInfoItem.Driver.IsSaveLog=! collectDeviceInfoItem.Driver.IsSaveLog; | ||||
|                                                  } | ||||
|                                                  )> | ||||
|                                                     <MIcon>@((collectDeviceInfoItem.Driver?.IsSaveLog == true) ? "mdi-pause" : "mdi-play")</MIcon> | ||||
|                                                     </MButton> | ||||
|                                                 </ActivatorContent> | ||||
|                                                 <ChildContent> | ||||
|                                                     <span>@((collectDeviceInfoItem.Driver?.IsSaveLog != true) ? "存入数据库,注意若交互频繁,可能导致数据库太大" : "不存入数据库")</span> | ||||
|                                             </ChildContent> | ||||
|                                         </MTooltip> | ||||
|  | ||||
|                                         <MTooltip Bottom Context="tip"> | ||||
|                                             <ActivatorContent> | ||||
|                                                 <MButton Loading=isDownExport Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicepause")) Class="mx-2" @attributes="@tip.Attrs" Dark Fab Small | ||||
| @@ -407,6 +422,10 @@ | ||||
|                                                     <span>@(item.Device?.KeepRun == true ? "暂停" : "运行")</span> | ||||
|                                             </ChildContent> | ||||
|                                         </MTooltip> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|                                         <MTooltip Bottom Context="tip"> | ||||
|                                             <ActivatorContent> | ||||
|                                                 <MButton Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicerestart")) Class="mx-2" @attributes="@tip.Attrs" Dark Fab Small Loading=isRestart OnClick=@(()=> UpRestartAsync(item.DeviceId))> | ||||
| @@ -495,7 +514,22 @@ | ||||
|                                                     <span>@((!pauseMessage) ? "暂停日志" : "运行日志")</span> | ||||
|                                             </ChildContent> | ||||
|                                         </MTooltip> | ||||
|  | ||||
|                                         <MTooltip Bottom Context="tip"> | ||||
|                                             <ActivatorContent> | ||||
|                                                 <MButton Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicepause")) Class="mx-2" @attributes="@tip.Attrs" Dark Fab Small | ||||
|                                                          OnClick=@(()=> | ||||
|                                                  { | ||||
|                                                  if(uploadDeviceInfoItem.Driver!=null) | ||||
|                                                  uploadDeviceInfoItem.Driver.IsSaveLog=! uploadDeviceInfoItem.Driver.IsSaveLog; | ||||
|                                                  } | ||||
|                                                  )> | ||||
|                                                     <MIcon>@((uploadDeviceInfoItem.Driver?.IsSaveLog == true) ? "mdi-pause" : "mdi-play")</MIcon> | ||||
|                                                     </MButton> | ||||
|                                                 </ActivatorContent> | ||||
|                                                 <ChildContent> | ||||
|                                                     <span>@((uploadDeviceInfoItem.Driver?.IsSaveLog != true) ? "存入数据库,注意若交互频繁,可能导致数据库太大" : "不存入数据库")</span> | ||||
|                                             </ChildContent> | ||||
|                                         </MTooltip> | ||||
|                                         <MTooltip Bottom Context="tip"> | ||||
|                                             <ActivatorContent> | ||||
|                                                 <MButton Loading=isDownExport Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicepause")) Class="mx-2" @attributes="@tip.Attrs" Dark Fab Small | ||||
|   | ||||
| @@ -73,8 +73,6 @@ public partial class DeviceStatusPage : IDisposable | ||||
|  | ||||
|     UploadDeviceWorker UploadDeviceHostService { get; set; } | ||||
|     StringNumber Uppanel { get; set; } | ||||
|     [Inject] | ||||
|     IVariableService VariableService { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
| @@ -157,7 +155,7 @@ public partial class DeviceStatusPage : IDisposable | ||||
|             isDownExport = true; | ||||
|             StateHasChanged(); | ||||
|             using var memoryStream = new MemoryStream(); | ||||
|             StreamWriter writer = new(memoryStream); | ||||
|             using StreamWriter writer = new(memoryStream); | ||||
|             foreach (var item in values) | ||||
|             { | ||||
|                 writer.WriteLine(item); | ||||
|   | ||||
| @@ -53,8 +53,6 @@ public partial class DeviceVariablePage | ||||
|     [Inject] | ||||
|     AjaxService AjaxService { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     IVariableService VariableService { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
| @@ -70,7 +68,7 @@ public partial class DeviceVariablePage | ||||
|     } | ||||
|     private async Task AddCallAsync(DeviceVariableAddInput input) | ||||
|     { | ||||
|         await VariableService.AddAsync(input); | ||||
|         await App.GetService<VariableService>().AddAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task ClearAsync() | ||||
| @@ -78,7 +76,7 @@ public partial class DeviceVariablePage | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("确认", "清空?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await VariableService.ClearDeviceVariableAsync(); | ||||
|             await App.GetService<VariableService>().ClearDeviceVariableAsync(); | ||||
|         } | ||||
|         await DatatableQueryAsync(); | ||||
|  | ||||
| @@ -91,7 +89,7 @@ public partial class DeviceVariablePage | ||||
|  | ||||
|     private async Task DeleteCallAsync(IEnumerable<DeviceVariable> input) | ||||
|     { | ||||
|         await VariableService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<VariableService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|     } | ||||
|  | ||||
|     void DeviceChanged(long devId) | ||||
| @@ -107,7 +105,7 @@ public partial class DeviceVariablePage | ||||
|  | ||||
|     Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file) | ||||
|     { | ||||
|         return VariableService.PreviewAsync(file); | ||||
|         return App.GetService<VariableService>().PreviewAsync(file); | ||||
|     } | ||||
|     async Task DownExportAsync(DeviceVariablePageInput input = null) | ||||
|     { | ||||
| @@ -116,7 +114,7 @@ public partial class DeviceVariablePage | ||||
|  | ||||
|     private async Task EditCallAsync(VariableEditInput input) | ||||
|     { | ||||
|         await VariableService.EditAsync(input); | ||||
|         await App.GetService<VariableService>().EditAsync(input); | ||||
|     } | ||||
|  | ||||
|     List<DependencyProperty> GetDriverProperties(long driverId, List<DependencyProperty> dependencyProperties) | ||||
| @@ -126,13 +124,13 @@ public partial class DeviceVariablePage | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<DeviceVariable>> QueryCallAsync(DeviceVariablePageInput input) | ||||
|     { | ||||
|         var data = await VariableService.PageAsync(input); | ||||
|         var data = await App.GetService<VariableService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
|  | ||||
|     async Task SaveDeviceImportAsync(Dictionary<string, ImportPreviewOutputBase> data) | ||||
|     { | ||||
|         await VariableService.ImportAsync(data); | ||||
|         await App.GetService<VariableService>().ImportAsync(data); | ||||
|         await DatatableQueryAsync(); | ||||
|         ImportExcel.IsShowImport = false; | ||||
|     } | ||||
|   | ||||
| @@ -52,8 +52,6 @@ public partial class DeviceVariableRunTimePage | ||||
|     GlobalDeviceData GlobalDeviceData { get; set; } | ||||
|  | ||||
|     VariablePageInput SearchModel { get; set; } = new(); | ||||
|     [Inject] | ||||
|     IUploadDeviceService UploadDeviceService { get; set; } | ||||
|  | ||||
|     CollectDeviceWorker CollectDeviceHostService { get; set; } | ||||
|     [Inject] | ||||
| @@ -121,7 +119,7 @@ public partial class DeviceVariableRunTimePage | ||||
|  | ||||
|     private Task<SqlSugarPagedList<DeviceVariableRunTime>> QueryCallAsync(VariablePageInput input) | ||||
|     { | ||||
|         var uploadDevId = UploadDeviceService.GetIdByName(input.UploadDeviceName); | ||||
|         var uploadDevId = App.GetService<UploadDeviceService>().GetIdByName(input.UploadDeviceName); | ||||
|         var data = GlobalDeviceData.AllVariables | ||||
|             .WhereIF(!input.DeviceName.IsNullOrEmpty(), a => a.DeviceName == input.DeviceName) | ||||
|             .WhereIF(!input.Name.IsNullOrEmpty(), a => a.Name.Contains(input.Name)) | ||||
|   | ||||
| @@ -24,11 +24,11 @@ | ||||
| @using ThingsGateway.Admin.Blazor; | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @using ThingsGateway.Application; | ||||
| @inject IVariableService VariableService | ||||
|   | ||||
| @attribute [Authorize] | ||||
| @inherits BaseComponentBase | ||||
| @inject UserResoures UserResoures | ||||
| @inject ICollectDeviceService CollectDeviceService | ||||
|   | ||||
| @layout MainLayout | ||||
|  | ||||
| <MRow NoGutters> | ||||
|   | ||||
| @@ -12,6 +12,8 @@ | ||||
|  | ||||
| using BlazorComponent; | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Masa.Blazor; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| @@ -33,14 +35,13 @@ public partial class DriverDebugPage | ||||
|     List<DriverPluginCategory> DriverPlugins; | ||||
|     bool IsShowTreeView = true; | ||||
|     PluginDebugUIInput SearchModel { get; set; } = new(); | ||||
|     [Inject] | ||||
|     IDriverPluginService DriverPluginService { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         DriverPlugins = DriverPluginService.GetDriverPluginChildrenList(); | ||||
|         DriverPlugins = App.GetService<DriverPluginService>().GetDriverPluginChildrenList(); | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ | ||||
| @using ThingsGateway.Admin.Blazor; | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @using ThingsGateway.Application; | ||||
| @inject IDriverPluginService DriverPluginService | ||||
|   | ||||
| @attribute [Authorize] | ||||
| @inherits BaseComponentBase | ||||
| @inject UserResoures UserResoures | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using ThingsGateway.Admin.Blazor.Core; | ||||
| using ThingsGateway.Admin.Core; | ||||
| using ThingsGateway.Application; | ||||
| @@ -25,12 +27,12 @@ public partial class DriverPluginPage | ||||
|  | ||||
|     private async Task AddCallAsync(DriverPluginAddInput input) | ||||
|     { | ||||
|         await DriverPluginService.AddAsync(input); | ||||
|         await App.GetService<DriverPluginService>().AddAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<DriverPlugin>> QueryCallAsync(DriverPluginPageInput input) | ||||
|     { | ||||
|         var data = await DriverPluginService.PageAsync(input); | ||||
|         var data = await App.GetService<DriverPluginService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
| } | ||||
| @@ -49,5 +49,10 @@ public partial class HardwareInfoPage | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override void Dispose() | ||||
|     { | ||||
|         _periodicTimer?.Dispose(); | ||||
|         base.Dispose(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										198
									
								
								framework/ThingsGateway.Blazor/Page/ManageGatewayPage.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								framework/ThingsGateway.Blazor/Page/ManageGatewayPage.razor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| @* | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| *@ | ||||
|  | ||||
| @page "/gatewayconfig/manage" | ||||
| @namespace ThingsGateway.Blazor | ||||
| @using System.Linq.Expressions; | ||||
| @using BlazorComponent; | ||||
| @using MQTTnet.Server; | ||||
| @using Mapster; | ||||
| @using Masa.Blazor.Presets; | ||||
| @using System.IO; | ||||
| @using Masa.Blazor; | ||||
| @using Microsoft.AspNetCore.Authorization; | ||||
| @using ThingsGateway.Admin.Blazor.Core; | ||||
| @using ThingsGateway.Admin.Blazor; | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @using ThingsGateway.Application; | ||||
| @using TouchSocket.Core; | ||||
| @attribute [Authorize] | ||||
| @inject MasaBlazor MasaBlazor | ||||
| @inherits BaseComponentBase | ||||
| @inject UserResoures UserResoures | ||||
| @inject NavigationManager NavigationManager | ||||
| @layout MainLayout | ||||
|  | ||||
| <MRow NoGutters> | ||||
|     <MExpansionPanels @bind-Values="Panel" | ||||
|                             Multiple> | ||||
|         <MExpansionPanel Value="1"> | ||||
|             <MExpansionPanelHeader> | ||||
|                 @($"子网关服务信息-{ManageGatewayWorker.ClientStatuString.Message}") | ||||
|             </MExpansionPanelHeader> | ||||
|             <MExpansionPanelContent> | ||||
|                 @{ | ||||
|                     var config = ManageGatewayWorker.ClientGatewayConfig; | ||||
|                 } | ||||
|                 @if (config != null) | ||||
|                 { | ||||
|  | ||||
|                     <MDescriptions Title="子网关服务配置信息" Bordered="true"> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.Enable)>@config.Enable</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.GatewayId)>@config.GatewayId</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.MqttBrokerIP)>@config.MqttBrokerIP</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.MqttBrokerPort)>@config.MqttBrokerPort</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.UserName)>@config.UserName</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.Password)>@config.Password</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.DBDownTopic)>@config.DBDownTopic</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.DBUploadTopic)>@config.DBUploadTopic</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.WriteRpcTopic)>@config.WriteRpcTopic</MDescriptionsItem> | ||||
|  | ||||
|                     </MDescriptions> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             </MExpansionPanelContent> | ||||
|         </MExpansionPanel> | ||||
|  | ||||
|         <MExpansionPanel Value="2"> | ||||
|             <MExpansionPanelHeader> | ||||
|                 @($"管理服务信息-{ManageGatewayWorker.ManageStatuString.Message}") | ||||
|  | ||||
|             </MExpansionPanelHeader> | ||||
|             <MExpansionPanelContent> | ||||
|                 @{ | ||||
|                     var config = ManageGatewayWorker.ManageGatewayConfig; | ||||
|                 } | ||||
|                 @if (config != null) | ||||
|                 { | ||||
|                     <MDescriptions Title="管理服务配置信息" Bordered="true"> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.Enable)>@config.Enable</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.MqttBrokerIP)>@config.MqttBrokerIP</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.MqttBrokerPort)>@config.MqttBrokerPort</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.UserName)>@config.UserName</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.Password)>@config.Password</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.DBDownTopic)>@config.DBDownTopic</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.DBUploadTopic)>@config.DBUploadTopic</MDescriptionsItem> | ||||
|                         <MDescriptionsItem Label=@config.Description(a=>a.WriteRpcTopic)>@config.WriteRpcTopic</MDescriptionsItem> | ||||
|  | ||||
|                     </MDescriptions> | ||||
|                 } | ||||
|                 <MCard Flat Class="ma-0" Style="min-height:1000px"> | ||||
|                     <div class="m-descriptions-header__title my-2"> | ||||
|                         当前服务下的子网关 | ||||
|                     </div> | ||||
|                     <MRow NoGutters> | ||||
|                         <MCol Md=3> | ||||
|  | ||||
|                             <MTreeview Dense TItem="MqttClientStatus" | ||||
|                                        TKey="MqttClientStatus" OpenOnClick @bind-Active=CurClients | ||||
|                                        Items="MqttClientStatuses" ItemText=@(r=>r.Id) ItemChildren="r=> null" | ||||
|                                        Activatable ItemKey=@(r=>r)> | ||||
|                                 <LabelContent> | ||||
|                                     <span title=@context.Item.Id> | ||||
|                                         @(context.Item.Id + "-" + context.Item.Endpoint) | ||||
|                                     </span> | ||||
|                                 </LabelContent> | ||||
|                             </MTreeview> | ||||
|                         </MCol> | ||||
|                         <MCol Md=9> | ||||
|                             @if (CurClients != null && CurClients.Count > 0) | ||||
|                             { | ||||
|                                 var CurClient = CurClients.FirstOrDefault(); | ||||
|                                 <MCard Flat Class="ml-4"> | ||||
|                                     <MDescriptions Title="当前选择的子网关" Bordered="true"> | ||||
|                                         <MDescriptionsItem Label=@CurClient.Description(a=>a.Id)>@CurClient.Id</MDescriptionsItem> | ||||
|                                         <MDescriptionsItem Label=@CurClient.Description(a=>a.Endpoint)>@CurClient.Endpoint</MDescriptionsItem> | ||||
|  | ||||
|                                     </MDescriptions> | ||||
|                                     <MDivider></MDivider> | ||||
|                                     <MRow> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|                                             <div class="m-descriptions-header__title my-2"> | ||||
|                                                 导出子网关配置信息 | ||||
|                                             </div> | ||||
|                                         </MCol> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|  | ||||
|  | ||||
|                                             <MButton Loading=isDownExport Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicepause")) Class="ma-2" | ||||
|                                                      OnClick=@(()=>DBUpload(CurClient))> | ||||
|                                                 导出 | ||||
|                                             </MButton> | ||||
|  | ||||
|                                         </MCol> | ||||
|                                     </MRow> | ||||
|                                     <MDivider></MDivider> | ||||
|                                     <MRow> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|                                             <div class="m-descriptions-header__title my-2"> | ||||
|                                                 下发子网关配置信息 | ||||
|                                             </div> | ||||
|                                         </MCol> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|                                             <MFileInput Label="采集设备Excel" @bind-Value="_importCollectDevicesFile" Style="width:60%;" ShowSize></MFileInput> | ||||
|                                             <MSwitch Label=@typeof(MqttDBDownRpc).GetDescription(nameof(MqttDBDownRpc.IsCollectDevicesFullUp)) @bind-Value=@IsCollectDevicesFullUp /> | ||||
|                                         </MCol> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|                                             <MFileInput Label="上传设备Excel" @bind-Value="_importUploadDevicesFile" Style="width:60%;" ShowSize></MFileInput> | ||||
|                                             <MSwitch Label=@typeof(MqttDBDownRpc).GetDescription(nameof(MqttDBDownRpc.IsUploadDevicesFullUp)) @bind-Value=@IsUploadDevicesFullUp /> | ||||
|                                         </MCol> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|                                             <MFileInput Label="变量Excel" @bind-Value="_importDeviceVariablesFile" Style="width:60%;" ShowSize></MFileInput> | ||||
|                                             <MSwitch Label=@typeof(MqttDBDownRpc).GetDescription(nameof(MqttDBDownRpc.IsDeviceVariablesFullUp)) @bind-Value=@IsDeviceVariablesFullUp /> | ||||
|                                         </MCol> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|                                             <MSwitch Label=@typeof(MqttDBDownRpc).GetDescription(nameof(MqttDBDownRpc.IsRestart)) @bind-Value=@IsRestart /> | ||||
|                                         </MCol> | ||||
|                                         <MCol Cols="12" Md="12"> | ||||
|  | ||||
|                                             <MButton Loading=isDownExport Disabled=@(!UserResoures.IsHasButtonWithRole("gatewaydevicepause")) Class="ma-2" | ||||
|                                                      OnClick=@(()=>DBDown(CurClient))> | ||||
|                                                 下发 | ||||
|                                             </MButton> | ||||
|                                         </MCol> | ||||
|  | ||||
|                                     </MRow> | ||||
|                                     <MDivider></MDivider> | ||||
|  | ||||
|  | ||||
|  | ||||
|                                 </MCard> | ||||
|                             } | ||||
|  | ||||
|  | ||||
|                         </MCol> | ||||
|  | ||||
|                     </MRow> | ||||
|                 </MCard> | ||||
|  | ||||
|             </MExpansionPanelContent> | ||||
|         </MExpansionPanel> | ||||
|  | ||||
|  | ||||
|  | ||||
|     </MExpansionPanels> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| </MRow> | ||||
|  | ||||
|  | ||||
							
								
								
									
										209
									
								
								framework/ThingsGateway.Blazor/Page/ManageGatewayPage.razor.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								framework/ThingsGateway.Blazor/Page/ManageGatewayPage.razor.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,209 @@ | ||||
| #region copyright | ||||
| //------------------------------------------------------------------------------ | ||||
| //  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充 | ||||
| //  此代码版权(除特别声明外的代码)归作者本人Diego所有 | ||||
| //  源代码使用协议遵循本仓库的开源协议及附加协议 | ||||
| //  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway | ||||
| //  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway | ||||
| //  使用文档:https://diego2098.gitee.io/thingsgateway-docs/ | ||||
| //  QQ群:605534569 | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using BlazorComponent; | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Masa.Blazor; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| using Microsoft.AspNetCore.Components.Forms; | ||||
| using Microsoft.JSInterop; | ||||
|  | ||||
| using MQTTnet.Server; | ||||
|  | ||||
| using System.IO; | ||||
| using System.Threading; | ||||
|  | ||||
| using ThingsGateway.Admin.Core; | ||||
| using ThingsGateway.Application; | ||||
|  | ||||
| namespace ThingsGateway.Blazor; | ||||
|  | ||||
| /// <summary> | ||||
| /// ManageGatewayPage | ||||
| /// </summary> | ||||
| public partial class ManageGatewayPage | ||||
| { | ||||
|     List<StringNumber> Panel { get; set; } = new(); | ||||
|  | ||||
|     readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(5)); | ||||
|     ManageGatewayWorker ManageGatewayWorker { get; set; } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
|     protected override void OnInitialized() | ||||
|     { | ||||
|         ManageGatewayWorker = ServiceHelper.GetBackgroundService<ManageGatewayWorker>(); | ||||
|         Panel.Add("2"); | ||||
|         _ = RunTimerAsync(); | ||||
|         base.OnInitialized(); | ||||
|     } | ||||
|     private async Task RunTimerAsync() | ||||
|     { | ||||
|         await RefreshAsync(); | ||||
|         while (await _periodicTimer.WaitForNextTickAsync()) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 await RefreshAsync(); | ||||
|                 await InvokeAsync(StateHasChanged); | ||||
|             } | ||||
|             catch | ||||
|             { | ||||
|             } | ||||
|  | ||||
|         } | ||||
|     } | ||||
|     List<MqttClientStatus> CurClients { get; set; } | ||||
|     List<MqttClientStatus> MqttClientStatuses { get; set; } = new(); | ||||
|     private async Task RefreshAsync() | ||||
|     { | ||||
|         MqttClientStatuses = await ManageGatewayWorker.GetClientGatewayAsync(); | ||||
|     } | ||||
|     /// <inheritdoc/> | ||||
|     public override void Dispose() | ||||
|     { | ||||
|         _periodicTimer?.Dispose(); | ||||
|         base.Dispose(); | ||||
|     } | ||||
|     IJSObjectReference _helper; | ||||
|     [Inject] | ||||
|     IJSRuntime JS { get; set; } | ||||
|  | ||||
|     private bool isDownExport; | ||||
|  | ||||
|     private bool IsCollectDevicesFullUp; | ||||
|     private bool IsUploadDevicesFullUp; | ||||
|     private bool IsDeviceVariablesFullUp; | ||||
|     private bool IsRestart; | ||||
|  | ||||
|     IBrowserFile _importCollectDevicesFile; | ||||
|     IBrowserFile _importUploadDevicesFile; | ||||
|     IBrowserFile _importDeviceVariablesFile; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 获取子网关配置,导出excel | ||||
|     /// </summary> | ||||
|     /// <param name="mqttClientStatus"></param> | ||||
|     /// <returns></returns> | ||||
|     private async Task DBUpload(MqttClientStatus mqttClientStatus) | ||||
|     { | ||||
|         var data = await ManageGatewayWorker.GetClientGatewayDBAsync(mqttClientStatus.Id); | ||||
|         if (data.IsSuccess) | ||||
|         { | ||||
|             isDownExport = true; | ||||
|             await InvokeAsync(StateHasChanged); | ||||
|             if (data.Content.CollectDevices.Count > 0) | ||||
|             { | ||||
|                 using var devices = await App.GetService<CollectDeviceService>().ExportFileAsync(data.Content.CollectDevices); | ||||
|                 using var streamRef = new DotNetStreamReference(stream: devices); | ||||
|                 _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|                 await _helper.InvokeVoidAsync("downloadFileFromStream", $"子网关{mqttClientStatus.Id}采集设备导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 await PopupService.EnqueueSnackbarAsync("无采集设备", AlertTypes.None); | ||||
|  | ||||
|             } | ||||
|             if (data.Content.UploadDevices.Count > 0) | ||||
|             { | ||||
|                 using var devices = await App.GetService<UploadDeviceService>().ExportFileAsync(data.Content.UploadDevices); | ||||
|                 using var streamRef = new DotNetStreamReference(stream: devices); | ||||
|                 _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|                 await _helper.InvokeVoidAsync("downloadFileFromStream", $"子网关{mqttClientStatus.Id}上传设备导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
|  | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 await PopupService.EnqueueSnackbarAsync("无上传设备", AlertTypes.None); | ||||
|  | ||||
|             } | ||||
|             if (data.Content.DeviceVariables.Count > 0) | ||||
|             { | ||||
|                 using var devices = await App.GetService<VariableService>().ExportFileAsync(data.Content.DeviceVariables); | ||||
|                 using var streamRef = new DotNetStreamReference(stream: devices); | ||||
|                 _helper ??= await JS.InvokeAsync<IJSObjectReference>("import", $"/_content/ThingsGateway.Admin.Blazor.Core/js/downloadFileFromStream.js"); | ||||
|                 await _helper.InvokeVoidAsync("downloadFileFromStream", $"子网关{mqttClientStatus.Id}变量导出{SysDateTimeExtensions.CurrentDateTime.ToFileDateTimeFormat()}.xlsx", streamRef); | ||||
|  | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 await PopupService.EnqueueSnackbarAsync("无采集变量", AlertTypes.None); | ||||
|  | ||||
|             } | ||||
|             await PopupService.EnqueueSnackbarAsync("上传成功", AlertTypes.Success); | ||||
|  | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync(data.Message, AlertTypes.Error); | ||||
|         } | ||||
|         isDownExport = false; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 下发子网关配置 | ||||
|     /// </summary> | ||||
|     /// <returns></returns> | ||||
|     private async Task DBDown(MqttClientStatus mqttClientStatus) | ||||
|     { | ||||
|         MqttDBDownRpc rpc = new() | ||||
|         { | ||||
|             IsCollectDevicesFullUp = IsCollectDevicesFullUp, | ||||
|             IsDeviceVariablesFullUp = IsDeviceVariablesFullUp, | ||||
|             IsUploadDevicesFullUp = IsUploadDevicesFullUp, | ||||
|             IsRestart = IsRestart | ||||
|         }; | ||||
|  | ||||
|         if (_importCollectDevicesFile != null) | ||||
|         { | ||||
|             using var fs1 = new MemoryStream(); | ||||
|             using var stream1 = _importCollectDevicesFile.OpenReadStream(512000000); | ||||
|             await stream1.CopyToAsync(fs1); | ||||
|             rpc.CollectDevices = fs1.ToArray(); | ||||
|         } | ||||
|         if (_importUploadDevicesFile != null) | ||||
|         { | ||||
|  | ||||
|             using var fs2 = new MemoryStream(); | ||||
|             using var stream2 = _importUploadDevicesFile.OpenReadStream(512000000); | ||||
|             await stream2.CopyToAsync(fs2); | ||||
|             rpc.UploadDevices = fs2.ToArray(); | ||||
|         } | ||||
|         if (_importDeviceVariablesFile != null) | ||||
|         { | ||||
|             using var fs3 = new MemoryStream(); | ||||
|             using var stream3 = _importDeviceVariablesFile.OpenReadStream(512000000); | ||||
|             await stream3.CopyToAsync(fs3); | ||||
|             rpc.DeviceVariables = fs3.ToArray(); | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|         var data = await ManageGatewayWorker.SetClientGatewayDBAsync(mqttClientStatus.Id, rpc); | ||||
|         if (data.IsSuccess) | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync("下发成功", AlertTypes.Success); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             await PopupService.EnqueueSnackbarAsync(data.Message, AlertTypes.Error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -45,11 +45,6 @@ public partial class MemoryVariablePage | ||||
|     [Inject] | ||||
|     AjaxService AjaxService { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     InitTimezone InitTimezone { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     IVariableService VariableService { get; set; } | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
|     /// </summary> | ||||
| @@ -70,7 +65,7 @@ public partial class MemoryVariablePage | ||||
|  | ||||
|     private async Task AddCallAsync(MemoryVariableAddInput input) | ||||
|     { | ||||
|         await VariableService.AddAsync(input); | ||||
|         await App.GetService<VariableService>().AddAsync(input); | ||||
|     } | ||||
|  | ||||
|     private async Task ClearAsync() | ||||
| @@ -78,7 +73,7 @@ public partial class MemoryVariablePage | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("确认", "清空?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await VariableService.ClearMemoryVariableAsync(); | ||||
|             await App.GetService<VariableService>().ClearMemoryVariableAsync(); | ||||
|         } | ||||
|         await DatatableQueryAsync(); | ||||
|  | ||||
| @@ -91,12 +86,12 @@ public partial class MemoryVariablePage | ||||
|  | ||||
|     private async Task DeleteCallAsync(IEnumerable<DeviceVariable> input) | ||||
|     { | ||||
|         await VariableService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         await App.GetService<VariableService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|     } | ||||
|  | ||||
|     Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file) | ||||
|     { | ||||
|         return VariableService.MemoryVariablePreviewAsync(file); | ||||
|         return App.GetService<VariableService>().MemoryVariablePreviewAsync(file); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @@ -108,7 +103,7 @@ public partial class MemoryVariablePage | ||||
|  | ||||
|     private async Task EditCallAsync(MemoryVariableAddInput input) | ||||
|     { | ||||
|         await VariableService.EditAsync(input); | ||||
|         await App.GetService<VariableService>().EditAsync(input); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @@ -119,12 +114,12 @@ public partial class MemoryVariablePage | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<DeviceVariable>> QueryCallAsync(MemoryVariablePageInput input) | ||||
|     { | ||||
|         var data = await VariableService.PageAsync(input); | ||||
|         var data = await App.GetService<VariableService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
|     async Task SaveDeviceImportAsync(Dictionary<string, ImportPreviewOutputBase> data) | ||||
|     { | ||||
|         await VariableService.ImportAsync(data); | ||||
|         await App.GetService<VariableService>().ImportAsync(data); | ||||
|         await DatatableQueryAsync(); | ||||
|         ImportExcel.IsShowImport = false; | ||||
|     } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
| @using ThingsGateway.Admin.Blazor; | ||||
| @using ThingsGateway.Admin.Core; | ||||
| @using ThingsGateway.Application; | ||||
| @inject IRpcLogService RpcLogService | ||||
|   | ||||
| @namespace ThingsGateway.Blazor | ||||
| @attribute [Authorize] | ||||
| @inject UserResoures UserResoures | ||||
| @@ -30,6 +30,31 @@ | ||||
|               QueryCallAsync="QueryCallAsync" | ||||
|                 IsShowDetailButton IsShowQueryButton> | ||||
|     <SearchTemplate> | ||||
|  | ||||
|          | ||||
|         <MMenu CloseOnContentClick="false" OffsetY Context="menu"> | ||||
|             <ActivatorContent> | ||||
|                 <MTextField Dense Readonly Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " | ||||
|                             Value="context.StartTime.Value.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)" | ||||
|                 @attributes="menu.Attrs" Outlined Label=@context.Description(x => x.StartTime) /> | ||||
|             </ActivatorContent> | ||||
|             <ChildContent> | ||||
|                 <AppDateTimePicker @bind-Value="context.StartTime"></AppDateTimePicker> | ||||
|             </ChildContent> | ||||
|         </MMenu> | ||||
|  | ||||
|         <MMenu CloseOnContentClick="false" OffsetY Context="menu"> | ||||
|             <ActivatorContent> | ||||
|                 <MTextField Dense Readonly Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " | ||||
|                             Value="context.EndTime.Value.ToDefaultDateTimeFormat(InitTimezone.TimezoneOffset)" Clearable | ||||
|                 @attributes="menu.Attrs" Outlined Label=@context.Description(x => x.EndTime) /> | ||||
|             </ActivatorContent> | ||||
|             <ChildContent> | ||||
|                 <AppDateTimePicker @bind-Value="context.EndTime"></AppDateTimePicker> | ||||
|             </ChildContent> | ||||
|         </MMenu> | ||||
|  | ||||
|  | ||||
|         <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " @bind-Value="context.Source" | ||||
|                         Outlined Label=@context.Description(x => x.Source) /> | ||||
|         <MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="my-1  mx-2 " @bind-Value="context.Object" | ||||
|   | ||||
| @@ -10,6 +10,8 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
| #endregion | ||||
|  | ||||
| using Furion; | ||||
|  | ||||
| using Mapster; | ||||
|  | ||||
| using Microsoft.AspNetCore.Components; | ||||
| @@ -29,13 +31,14 @@ public partial class RpcLogPage | ||||
|     [Inject] | ||||
|     AjaxService AjaxService { get; set; } | ||||
|  | ||||
|  | ||||
|     [Inject] | ||||
|     InitTimezone InitTimezone { get; set; } | ||||
|     private async Task ClearClickAsync() | ||||
|     { | ||||
|         var confirm = await PopupService.OpenConfirmDialogAsync("删除", "确定 ?"); | ||||
|         if (confirm) | ||||
|         { | ||||
|             await RpcLogService.DeleteAsync(); | ||||
|             await App.GetService<RpcLogService>().DeleteAsync(); | ||||
|             await _datatable?.QueryClickAsync(); | ||||
|         } | ||||
|     } | ||||
| @@ -53,7 +56,7 @@ public partial class RpcLogPage | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<RpcLog>> QueryCallAsync(RpcLogPageInput input) | ||||
|     { | ||||
|         var data = await RpcLogService.PageAsync(input); | ||||
|         var data = await App.GetService<RpcLogService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
| } | ||||
| @@ -14,6 +14,7 @@ | ||||
| @namespace ThingsGateway.Blazor | ||||
| @using System.Linq.Expressions; | ||||
| @using BlazorComponent; | ||||
| @using Furion; | ||||
| @using Mapster; | ||||
| @using Masa.Blazor.Presets; | ||||
| @using System.IO; | ||||
| @@ -149,7 +150,7 @@ else | ||||
|                 case nameof(context.Item.PluginId): | ||||
|                     <span title=@context.Value> | ||||
|                         @( | ||||
|                             DriverPluginService.GetNameById(context.Item.PluginId) | ||||
|                             App.GetService<DriverPluginService>().GetNameById(context.Item.PluginId) | ||||
|                                 ) | ||||
|                     </span> | ||||
|                     break; | ||||
|   | ||||
| @@ -44,16 +44,10 @@ public partial class UploadDevicePage | ||||
|     StringNumber tab; | ||||
|     [Inject] | ||||
|     AjaxService AjaxService { get; set; } | ||||
|     [Inject] | ||||
|     IDriverPluginService DriverPluginService { get; set; } | ||||
|  | ||||
|     [Inject] | ||||
|     InitTimezone InitTimezone { get; set; } | ||||
|  | ||||
|     [CascadingParameter] | ||||
|     MainLayout MainLayout { get; set; } | ||||
|     [Inject] | ||||
|     IUploadDeviceService UploadDeviceService { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// <inheritdoc/> | ||||
| @@ -67,8 +61,8 @@ public partial class UploadDevicePage | ||||
|     } | ||||
|     private async Task AddCallAsync(UploadDeviceAddInput input) | ||||
|     { | ||||
|         await UploadDeviceService.AddAsync(input); | ||||
|         _deviceGroups = UploadDeviceService.GetCacheList()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await App.GetService<UploadDeviceService>().AddAsync(input); | ||||
|         _deviceGroups = App.GetService<UploadDeviceService>().GetCacheList()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
| @@ -80,7 +74,7 @@ public partial class UploadDevicePage | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         await UploadDeviceService.CopyDevAsync(data); | ||||
|         await App.GetService<UploadDeviceService>().CopyDevAsync(data); | ||||
|         await DatatableQuery(); | ||||
|         await PopupService.EnqueueSnackbarAsync("复制成功", AlertTypes.Success); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
| @@ -93,14 +87,14 @@ public partial class UploadDevicePage | ||||
|  | ||||
|     private async Task DeleteCallAsync(IEnumerable<UploadDevice> input) | ||||
|     { | ||||
|         await UploadDeviceService.DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         _deviceGroups = UploadDeviceService.GetCacheList()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await App.GetService<UploadDeviceService>().DeleteAsync(input.Select(a => a.Id).ToArray()); | ||||
|         _deviceGroups = App.GetService<UploadDeviceService>().GetCacheList()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
|     Task<Dictionary<string, ImportPreviewOutputBase>> DeviceImportAsync(IBrowserFile file) | ||||
|     { | ||||
|         return UploadDeviceService.PreviewAsync(file); | ||||
|         return App.GetService<UploadDeviceService>().PreviewAsync(file); | ||||
|     } | ||||
|     async Task DownExportAsync(UploadDevicePageInput input = null) | ||||
|     { | ||||
| @@ -128,8 +122,8 @@ public partial class UploadDevicePage | ||||
|     } | ||||
|     private async Task EditCallAsync(UploadDeviceEditInput input) | ||||
|     { | ||||
|         await UploadDeviceService.EditAsync(input); | ||||
|         _deviceGroups = UploadDeviceService.GetCacheList()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await App.GetService<UploadDeviceService>().EditAsync(input); | ||||
|         _deviceGroups = App.GetService<UploadDeviceService>().GetCacheList()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList(); | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|     } | ||||
|  | ||||
| @@ -141,13 +135,13 @@ public partial class UploadDevicePage | ||||
|  | ||||
|     private async Task<SqlSugarPagedList<UploadDevice>> QueryCallAsync(UploadDevicePageInput input) | ||||
|     { | ||||
|         var data = await UploadDeviceService.PageAsync(input); | ||||
|         var data = await App.GetService<UploadDeviceService>().PageAsync(input); | ||||
|         return data; | ||||
|     } | ||||
|  | ||||
|     async Task SaveDeviceImportAsync(Dictionary<string, ImportPreviewOutputBase> data) | ||||
|     { | ||||
|         await UploadDeviceService.ImportAsync(data); | ||||
|         await App.GetService<UploadDeviceService>().ImportAsync(data); | ||||
|         await DatatableQuery(); | ||||
|         ImportExcel.IsShowImport = false; | ||||
|         await MainLayout.StateHasChangedAsync(); | ||||
|   | ||||
| @@ -321,6 +321,9 @@ | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Blazor.HardwareInfoPage.Dispose"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Blazor.HistoryAlarmPage"> | ||||
|             <summary> | ||||
|             历史报警页面 | ||||
| @@ -343,6 +346,32 @@ | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Blazor.ManageGatewayPage"> | ||||
|             <summary> | ||||
|             ManageGatewayPage | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Blazor.ManageGatewayPage.OnInitialized"> | ||||
|             <summary> | ||||
|             <inheritdoc/> | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Blazor.ManageGatewayPage.Dispose"> | ||||
|             <inheritdoc/> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Blazor.ManageGatewayPage.DBUpload(MQTTnet.Server.MqttClientStatus)"> | ||||
|             <summary> | ||||
|             获取子网关配置,导出excel | ||||
|             </summary> | ||||
|             <param name="mqttClientStatus"></param> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:ThingsGateway.Blazor.ManageGatewayPage.DBDown(MQTTnet.Server.MqttClientStatus)"> | ||||
|             <summary> | ||||
|             下发子网关配置 | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="T:ThingsGateway.Blazor.MemoryVariablePage"> | ||||
|             <summary> | ||||
|             内存变量页面 | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user