mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-11-04 17:43:58 +08:00 
			
		
		
		
	Compare commits
	
		
			53 Commits
		
	
	
		
			10.11.39.0
			...
			14f3c31265
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					14f3c31265 | ||
| 
						 | 
					1bad65378f | ||
| 
						 | 
					db3affc67e | ||
| 
						 | 
					5ee8b50a92 | ||
| 
						 | 
					301beda2a2 | ||
| 
						 | 
					628b51a353 | ||
| 
						 | 
					f03445bc83 | ||
| 
						 | 
					55a2ff5487 | ||
| 
						 | 
					0fef7dcf3b | ||
| 
						 | 
					19d9702606 | ||
| 
						 | 
					a8a9774932 | ||
| 
						 | 
					aad0f0e8c3 | ||
| 
						 | 
					e74eae50a7 | ||
| 
						 | 
					3b16d7019f | ||
| 
						 | 
					3e038028c2 | ||
| 
						 | 
					b1d8041f7e | ||
| 
						 | 
					53a98b26cd | ||
| 
						 | 
					42c740fa1b | ||
| 
						 | 
					556819c90c | ||
| 
						 | 
					2522333a9c | ||
| 
						 | 
					bd4ce7c09b | ||
| 
						 | 
					156ed88bd6 | ||
| 
						 | 
					2416226eb0 | ||
| 
						 | 
					976323a716 | ||
| 
						 | 
					3c9e397403 | ||
| 
						 | 
					79406ad4a0 | ||
| 
						 | 
					20c44f10ca | ||
| 
						 | 
					31d6b2a9e6 | ||
| 
						 | 
					68e5a9c546 | ||
| 
						 | 
					b2ea9f99b9 | ||
| 
						 | 
					6d7d0e468a | ||
| 
						 | 
					ff1f632de2 | ||
| 
						 | 
					fc3d7015ee | ||
| 
						 | 
					40c5acb522 | ||
| 
						 | 
					f9cc1cbb05 | ||
| 
						 | 
					cf6e8b58f0 | ||
| 
						 | 
					615e3bb24c | ||
| 
						 | 
					4a7534b210 | ||
| 
						 | 
					58e099cb93 | ||
| 
						 | 
					a94a9c953c | ||
| 
						 | 
					35e1ffa3e9 | ||
| 
						 | 
					4921642151 | ||
| 
						 | 
					d71ee29da8 | ||
| 
						 | 
					901aa2d59f | ||
| 
						 | 
					764957c014 | ||
| 
						 | 
					0e3898218b | ||
| 
						 | 
					61f13cef3c | ||
| 
						 | 
					0b663d9e01 | ||
| 
						 | 
					6c95c6209f | ||
| 
						 | 
					4d223d2622 | ||
| 
						 | 
					e8d7e91b64 | ||
| 
						 | 
					8175f541ec | ||
| 
						 | 
					0adbdb926b | 
@@ -45,6 +45,7 @@ public class VerificatInfo : PrimaryIdEntity
 | 
			
		||||
    /// 登录IP
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [AutoGenerateColumn(Filterable = true, Sortable = true, Width = 200)]
 | 
			
		||||
    [SugarColumn(IsNullable = true)]
 | 
			
		||||
    public string LoginIp { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -78,5 +79,6 @@ public class VerificatInfo : PrimaryIdEntity
 | 
			
		||||
    /// 登录设备
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    [AutoGenerateColumn(Filterable = true, Sortable = true, Width = 100)]
 | 
			
		||||
    [SugarColumn(IsNullable = true)]
 | 
			
		||||
    public string Device { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
using Riok.Mapperly.Abstractions;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Admin.Application;
 | 
			
		||||
 | 
			
		||||
[Mapper(UseDeepCloning = true, EnumMappingStrategy = EnumMappingStrategy.ByName, RequiredMappingStrategy = RequiredMappingStrategy.None)]
 | 
			
		||||
public static partial class AdminMapper
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -145,7 +145,7 @@ public class AdminOAuthHandler<TOptions>(
 | 
			
		||||
        var loginEvent = new LoginEvent
 | 
			
		||||
        {
 | 
			
		||||
            Ip = appService.RemoteIpAddress,
 | 
			
		||||
            Device = appService.UserAgent?.Platform,
 | 
			
		||||
            Device = appService.UserAgent?.Platform ?? "Unknown",
 | 
			
		||||
            Expire = expire,
 | 
			
		||||
            SysUser = sysUser,
 | 
			
		||||
            VerificatId = CommonUtils.GetSingleId()
 | 
			
		||||
@@ -156,7 +156,7 @@ public class AdminOAuthHandler<TOptions>(
 | 
			
		||||
        //生成verificat信息
 | 
			
		||||
        var verificatInfo = new VerificatInfo
 | 
			
		||||
        {
 | 
			
		||||
            Device = loginEvent.Device,
 | 
			
		||||
            Device = loginEvent.Device ?? "Unknown",
 | 
			
		||||
            Expire = loginEvent.Expire,
 | 
			
		||||
            VerificatTimeout = tokenTimeout,
 | 
			
		||||
            Id = loginEvent.VerificatId,
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
      "Module": 2,
 | 
			
		||||
      "Title": "权限管理",
 | 
			
		||||
      "Code": "System",
 | 
			
		||||
      "NavLinkMatch": "All",
 | 
			
		||||
      "NavLinkMatch": "Prefix",
 | 
			
		||||
      "Category": "MENU",
 | 
			
		||||
      "Target": "_self",
 | 
			
		||||
      "Href": null,
 | 
			
		||||
@@ -47,7 +47,7 @@
 | 
			
		||||
      "ParentId": 0,
 | 
			
		||||
      "Module": 2,
 | 
			
		||||
      "Title": "系统运维",
 | 
			
		||||
      "NavLinkMatch": "All",
 | 
			
		||||
      "NavLinkMatch": "Prefix",
 | 
			
		||||
      "Code": "System",
 | 
			
		||||
      "Category": "MENU",
 | 
			
		||||
      "Target": "_self",
 | 
			
		||||
 
 | 
			
		||||
@@ -235,7 +235,7 @@ public class AuthService : IAuthService
 | 
			
		||||
        var logingEvent = new LoginEvent
 | 
			
		||||
        {
 | 
			
		||||
            Ip = _appService.RemoteIpAddress,
 | 
			
		||||
            Device = _appService.UserAgent?.Platform,
 | 
			
		||||
            Device = _appService.UserAgent?.Platform ?? "Unknown",
 | 
			
		||||
            Expire = expire,
 | 
			
		||||
            SysUser = sysUser,
 | 
			
		||||
            VerificatId = verificatId
 | 
			
		||||
@@ -344,7 +344,7 @@ public class AuthService : IAuthService
 | 
			
		||||
        //生成verificat信息
 | 
			
		||||
        var verificatInfo = new VerificatInfo
 | 
			
		||||
        {
 | 
			
		||||
            Device = loginEvent.Device,
 | 
			
		||||
            Device = loginEvent.Device ?? "Unknown",
 | 
			
		||||
            Expire = loginEvent.Expire,
 | 
			
		||||
            VerificatTimeout = tokenTimeout,
 | 
			
		||||
            Id = loginEvent.VerificatId,
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Admin.Application;
 | 
			
		||||
 | 
			
		||||
internal sealed class NoticeService : INoticeService
 | 
			
		||||
{
 | 
			
		||||
    private IEventService<AppMessage>? MessageDispatchService { get; set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -282,7 +282,7 @@ internal sealed class SysRoleService : BaseService<SysRole>, ISysRoleService
 | 
			
		||||
        if (sysRole != null)
 | 
			
		||||
        {
 | 
			
		||||
            var resources = await _sysResourceService.GetAllAsync().ConfigureAwait(false);
 | 
			
		||||
            var menusList = resources.Where(a => a.Category == ResourceCategoryEnum.Menu).Where(a => menuIds.Contains(a.Id));
 | 
			
		||||
            var menusList = resources.Where(a => a.Category == ResourceCategoryEnum.Menu && menuIds.Contains(a.Id));
 | 
			
		||||
 | 
			
		||||
            #region 角色模块处理
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -550,7 +550,7 @@ internal sealed class SysUserService : BaseService<SysUser>, ISysUserService
 | 
			
		||||
        if (sysUser != null)
 | 
			
		||||
        {
 | 
			
		||||
            var resources = await _sysResourceService.GetAllAsync().ConfigureAwait(false);
 | 
			
		||||
            var menusList = resources.Where(a => a.Category == ResourceCategoryEnum.Menu).Where(a => menuIds.Contains(a.Id));
 | 
			
		||||
            var menusList = resources.Where(a => a.Category == ResourceCategoryEnum.Menu && menuIds.Contains(a.Id));
 | 
			
		||||
 | 
			
		||||
            #region 用户模块处理
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -119,7 +119,7 @@ internal sealed class VerificatInfoService : BaseService<VerificatInfo>, IVerifi
 | 
			
		||||
    public void Add(VerificatInfo verificatInfo)
 | 
			
		||||
    {
 | 
			
		||||
        using var db = GetDB();
 | 
			
		||||
        db.Insertable<VerificatInfo>(verificatInfo).ExecuteCommand();
 | 
			
		||||
        db.InsertableT<VerificatInfo>(verificatInfo).ExecuteCommand();
 | 
			
		||||
        VerificatInfoService.RemoveCache(verificatInfo.Id);
 | 
			
		||||
        if (verificatInfo != null)
 | 
			
		||||
            VerificatInfoService.SetCahce(verificatInfo);
 | 
			
		||||
@@ -132,7 +132,7 @@ internal sealed class VerificatInfoService : BaseService<VerificatInfo>, IVerifi
 | 
			
		||||
    public void Update(VerificatInfo verificatInfo)
 | 
			
		||||
    {
 | 
			
		||||
        using var db = GetDB();
 | 
			
		||||
        db.Updateable<VerificatInfo>(verificatInfo).ExecuteCommand();
 | 
			
		||||
        db.UpdateableT<VerificatInfo>(verificatInfo).ExecuteCommand();
 | 
			
		||||
        VerificatInfoService.RemoveCache(verificatInfo.Id);
 | 
			
		||||
        if (verificatInfo != null)
 | 
			
		||||
            VerificatInfoService.SetCahce(verificatInfo);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
		
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
 | 
			
		||||
		<TargetFrameworks>net8.0;$(OtherTargetFrameworks);</TargetFrameworks>
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
	
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
 | 
			
		||||
		<PackageReference Include="Rougamo.Fody" Version="5.0.1" />
 | 
			
		||||
		<PackageReference Include="Rougamo.Fody" Version="5.0.2" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
 | 
			
		||||
@@ -28,10 +28,10 @@
 | 
			
		||||
		<PackageReference Include="System.Threading.RateLimiting" Version="8.0.0" />
 | 
			
		||||
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="System.Formats.Asn1" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="System.Threading.RateLimiting" Version="$(NET9Version)" />
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net10.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(NET10Version)" />
 | 
			
		||||
		<PackageReference Include="System.Formats.Asn1" Version="$(NET10Version)" />
 | 
			
		||||
		<PackageReference Include="System.Threading.RateLimiting" Version="$(NET10Version)" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<Content Remove="SeedData\Admin\*.json" />
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,8 @@
 | 
			
		||||
 | 
			
		||||
<div class="tg-table h-100">
 | 
			
		||||
 | 
			
		||||
    <Table TItem="TItem" IsBordered="true" IsStriped="true" TableSize="TableSize.Compact" IsMultipleSelect="IsMultipleSelect" @ref="Instance" SearchTemplate="SearchTemplate"
 | 
			
		||||
           DataService="DataService" CreateItemCallback="CreateItemCallback!"
 | 
			
		||||
    <Table TItem="TItem" IsBordered="true" IsStriped="true" TableSize="TableSize.Compact" SelectedRows=SelectedRows SelectedRowsChanged=privateSelectedRowsChanged IsMultipleSelect="IsMultipleSelect" @ref="Instance" SearchTemplate="SearchTemplate"
 | 
			
		||||
           DataService="DataService" CreateItemCallback="CreateItemCallback!" RenderMode=RenderMode
 | 
			
		||||
           IsPagination="IsPagination" PageItemsSource="PageItemsSource" IsFixedHeader="IsFixedHeader" IndentSize=24 RowHeight=RowHeight ShowSearchText="ShowSearchText" ShowSearchButton="ShowSearchButton" DisableEditButtonCallback="DisableEditButtonCallback" DisableDeleteButtonCallback="DisableDeleteButtonCallback" BeforeShowEditDialogCallback=" BeforeShowEditDialogCallback!"
 | 
			
		||||
           IsTree="IsTree" OnTreeExpand="OnTreeExpand!" TreeNodeConverter="TreeNodeConverter!" TreeIcon="fa-solid fa-circle-chevron-right" TreeExpandIcon="fa-solid fa-circle-chevron-right fa-rotate-90" IsAutoQueryFirstRender=IsAutoQueryFirstRender
 | 
			
		||||
           ShowDefaultButtons="ShowDefaultButtons" ShowAdvancedSearch="ShowAdvancedSearch" ShowResetButton=ShowResetButton
 | 
			
		||||
@@ -41,6 +41,7 @@
 | 
			
		||||
           DoubleClickToEdit="DoubleClickToEdit"
 | 
			
		||||
           OnDoubleClickCellCallback="OnDoubleClickCellCallback"
 | 
			
		||||
           OnDoubleClickRowCallback="OnDoubleClickRowCallback"
 | 
			
		||||
           RowContentTemplate="RowContentTemplate"
 | 
			
		||||
           OnClickRowCallback="OnClickRowCallback">
 | 
			
		||||
    </Table>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,32 @@ namespace ThingsGateway.Admin.Razor;
 | 
			
		||||
[CascadingTypeParameter(nameof(TItem))]
 | 
			
		||||
public partial class AdminTable<TItem> where TItem : class, new()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.RenderMode"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public TableRenderMode RenderMode { get; set; }
 | 
			
		||||
 | 
			
		||||
    public List<ITableColumn> Columns => Instance?.Columns;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.SelectedRows"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public List<TItem> SelectedRows { get; set; } = new();
 | 
			
		||||
 | 
			
		||||
    private async Task privateSelectedRowsChanged(List<TItem> items)
 | 
			
		||||
    {
 | 
			
		||||
        SelectedRows = items;
 | 
			
		||||
        if (SelectedRowsChanged.HasDelegate)
 | 
			
		||||
            await SelectedRowsChanged.InvokeAsync(items);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.DoubleClickToEdit"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public bool DoubleClickToEdit { get; set; } = false;
 | 
			
		||||
@@ -22,6 +48,10 @@ public partial class AdminTable<TItem> where TItem : class, new()
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.OnDoubleClickRowCallback"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public Func<TItem, Task>? OnDoubleClickRowCallback { get; set; }
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.RowContentTemplate"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public RenderFragment<TableRowContext<TItem>>? RowContentTemplate { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.OnClickRowCallback"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public Func<TItem, Task>? OnClickRowCallback { get; set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -125,13 +125,22 @@ public class BlazorAppContext
 | 
			
		||||
            var ownMenus = OwnMenus.Where(a => a.Module == CurrentModuleId);
 | 
			
		||||
            OwnMenuItems = AdminResourceUtil.BuildMenuTrees(ownMenus).ToList();
 | 
			
		||||
            AllOwnMenuItems = AdminResourceUtil.BuildMenuTrees(OwnMenus).ToList();
 | 
			
		||||
            OwnSameLevelMenuItems = ownMenus.Where(a => !a.Href.IsNullOrWhiteSpace()).Select(item => new MenuItem()
 | 
			
		||||
            OwnSameLevelMenuItems = ownMenus.Where(a => !a.Href.IsNullOrWhiteSpace()).Select(item =>
 | 
			
		||||
            {
 | 
			
		||||
                Match = item.NavLinkMatch ?? Microsoft.AspNetCore.Components.Routing.NavLinkMatch.All,
 | 
			
		||||
                Text = item.Title,
 | 
			
		||||
                Icon = item.Icon,
 | 
			
		||||
                Url = item.Href,
 | 
			
		||||
                Target = item.Target.ToString(),
 | 
			
		||||
                var menu = new MenuItem()
 | 
			
		||||
                {
 | 
			
		||||
                    Match = item.NavLinkMatch ?? Microsoft.AspNetCore.Components.Routing.NavLinkMatch.Prefix,
 | 
			
		||||
                    Text = item.Title,
 | 
			
		||||
                    Icon = item.Icon,
 | 
			
		||||
                    Url = item.Href,
 | 
			
		||||
                    Target = item.Target.ToString(),
 | 
			
		||||
                };
 | 
			
		||||
                if (menu.Url.IsNullOrEmpty())
 | 
			
		||||
                {
 | 
			
		||||
                    menu.Match = Microsoft.AspNetCore.Components.Routing.NavLinkMatch.Prefix;
 | 
			
		||||
                }
 | 
			
		||||
                return menu;
 | 
			
		||||
 | 
			
		||||
            }).ToList();
 | 
			
		||||
            UserWorkbenchOutputs = AllMenus.Where(it => UserWorkBench.Shortcuts.Contains(it.Id)).ToList();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@
 | 
			
		||||
        </Card>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col-12 col-sm-10 h-100">
 | 
			
		||||
    <div class="col-12 col-sm-10 h-100 ps-2">
 | 
			
		||||
    <AdminTable @ref=table TItem="SysUser"
 | 
			
		||||
        AutoGenerateColumns="true"
 | 
			
		||||
        ShowAdvancedSearch=false
 | 
			
		||||
 
 | 
			
		||||
@@ -20,5 +20,6 @@ public class Startup : AppStartup
 | 
			
		||||
        services.AddScoped<IMenuService, MenuService>();
 | 
			
		||||
        services.AddScoped<IAuthRazorService, AuthRazorService>();
 | 
			
		||||
        services.AddBootstrapBlazorTableExportService();
 | 
			
		||||
        services.AddBootstrapBlazorWinBoxService();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,19 +5,21 @@
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.0" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.3" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.3" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="$(NET8Version)" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	<ItemGroup Condition="'$(TargetFramework)'=='net9.0'">
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="$(NET9Version)" />
 | 
			
		||||
	<ItemGroup Condition="'$(TargetFramework)'=='net10.0'">
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="$(NET10Version)" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
 | 
			
		||||
		<TargetFrameworks>net8.0;$(OtherTargetFrameworks);</TargetFrameworks>
 | 
			
		||||
		
 | 
			
		||||
		<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -41,15 +41,22 @@ public static class AdminResourceUtil
 | 
			
		||||
        return items
 | 
			
		||||
        .Where(it => it.ParentId == parentId)
 | 
			
		||||
        .Select((item, index) =>
 | 
			
		||||
            new MenuItem()
 | 
			
		||||
        {
 | 
			
		||||
            var menu = new MenuItem()
 | 
			
		||||
            {
 | 
			
		||||
                Match = item.NavLinkMatch ?? Microsoft.AspNetCore.Components.Routing.NavLinkMatch.All,
 | 
			
		||||
                Match = item.NavLinkMatch ?? Microsoft.AspNetCore.Components.Routing.NavLinkMatch.Prefix,
 | 
			
		||||
                Text = item.Title,
 | 
			
		||||
                Icon = item.Icon,
 | 
			
		||||
                Url = item.Href,
 | 
			
		||||
                Target = item.Target.ToString(),
 | 
			
		||||
                Items = BuildMenuTrees(items, item.Id).ToList()
 | 
			
		||||
            };
 | 
			
		||||
            if (menu.Url.IsNullOrEmpty())
 | 
			
		||||
            {
 | 
			
		||||
                menu.Match = Microsoft.AspNetCore.Components.Routing.NavLinkMatch.Prefix;
 | 
			
		||||
            }
 | 
			
		||||
            return menu;
 | 
			
		||||
        }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,13 @@
 | 
			
		||||
    <link rel="apple-touch-icon" href="favicon.png">
 | 
			
		||||
    <base href="/" />
 | 
			
		||||
    <title>ThingsGateway</title>
 | 
			
		||||
    <link rel="stylesheet" href=@($"_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css?v={this.GetType().Assembly.GetName().Version}") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css?v={this.GetType().Assembly.GetName().Version}") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"_content/BootstrapBlazor/css/motronic.min.css?v={this.GetType().Assembly.GetName().Version}") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"ThingsGateway.AdminServer.styles.css?v={this.GetType().Assembly.GetName().Version}") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"{WebsiteConst.DefaultResourceUrl}css/site.css?v={this.GetType().Assembly.GetName().Version}") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"_content/BootstrapBlazor/css/motronic.min.css") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"ThingsGateway.AdminServer.styles.css") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"{WebsiteConst.DefaultResourceUrl}css/site.css") />
 | 
			
		||||
    <link rel="stylesheet" href=@($"{WebsiteConst.DefaultResourceUrl}css/devui.css") />
 | 
			
		||||
 | 
			
		||||
    @* <script src=@($"{WebsiteConst.DefaultResourceUrl}js/theme.js") type="module"></script><!-- 初始主题 --> *@
 | 
			
		||||
    <!-- PWA Manifest -->
 | 
			
		||||
    <link rel="manifest" href="./manifest.json" />
 | 
			
		||||
@@ -38,12 +40,13 @@
 | 
			
		||||
 | 
			
		||||
    <BlazorReconnector @rendermode="new InteractiveServerRenderMode(false)" />
 | 
			
		||||
 | 
			
		||||
    <script src=@($"_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js?v={this.GetType().Assembly.GetName().Version}")></script>
 | 
			
		||||
    <script src=@($"{WebsiteConst.DefaultResourceUrl}js/localStorageUtil.js?v={this.GetType().Assembly.GetName().Version}")></script>
 | 
			
		||||
    <script src=@($"_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js")></script>
 | 
			
		||||
    <script src=@($"{WebsiteConst.DefaultResourceUrl}js/localStorageUtil.js")></script>
 | 
			
		||||
    <script src="_framework/blazor.web.js"></script>
 | 
			
		||||
    <!-- PWA Service Worker -->
 | 
			
		||||
    <script type="text/javascript">'serviceWorker' in navigator && navigator.serviceWorker.register('./service-worker.js')</script>
 | 
			
		||||
 | 
			
		||||
    <script src="pwa-install.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -70,7 +70,7 @@
 | 
			
		||||
                        <Button @onclick="ShowAbout" class="layout-header-bar d-none d-lg-flex px-2" Icon="fa fa-info" Color="Color.None" TooltipText="@Localizer[nameof(About)]" />
 | 
			
		||||
                    }
 | 
			
		||||
                    @* 版本号 *@
 | 
			
		||||
                    <div class="px-1 navbar-header-text d-none d-lg-block">@_versionString</div>
 | 
			
		||||
                    <div class="px-1 navbar-header-text text-nowrap d-none d-lg-block">@_versionString</div>
 | 
			
		||||
 | 
			
		||||
                    @* 主题切换 *@
 | 
			
		||||
                    @* <ThemeToggle /> *@
 | 
			
		||||
@@ -89,12 +89,19 @@
 | 
			
		||||
                    </div>
 | 
			
		||||
                </Side>
 | 
			
		||||
                <Main>
 | 
			
		||||
                        <Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
 | 
			
		||||
                    <Tab @ref=_tab ClickTabToNavigation="true" ShowToolbar="true" ShowContextMenu="true" ShowExtendButtons="false" ShowClose="true" AllowDrag=true
 | 
			
		||||
                         ShowFullscreenToolbarButton=false ShowContextMenuFullScreen=false ShowFullScreen=false AdditionalAssemblies="@App.RazorAssemblies" Menus="@MenuService.AllOwnMenuItems"
 | 
			
		||||
                             DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
 | 
			
		||||
                             {
 | 
			
		||||
                             return Task.FromResult(!(a.Url=="/"||a.Url.IsNullOrEmpty()));
 | 
			
		||||
                             })>
 | 
			
		||||
                         DefaultUrl=@("/") Body=@(Body!) OnCloseTabItemAsync=@((a)=>
 | 
			
		||||
                                                                                  {
 | 
			
		||||
                                                                                      return Task.FromResult(!(a.Url == "/" || a.Url.IsNullOrEmpty()));
 | 
			
		||||
                                                                                  })
 | 
			
		||||
                                                                                  >
 | 
			
		||||
                        <BeforeContextMenuTemplate>
 | 
			
		||||
 | 
			
		||||
                                                     <ContextMenuItem Icon="fa fa-window-restore" Text="@Localizer["WindowRestore"]" OnClick="WinboxRender"></ContextMenuItem>
 | 
			
		||||
                                                     <ContextMenuDivider></ContextMenuDivider>
 | 
			
		||||
 | 
			
		||||
                                                 </BeforeContextMenuTemplate>
 | 
			
		||||
                        </Tab>
 | 
			
		||||
                </Main>
 | 
			
		||||
                <NotAuthorized>
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,38 @@ public partial class MainLayout : IDisposable
 | 
			
		||||
 | 
			
		||||
    #endregion 注销
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private async Task WinboxRender(ContextMenuItem item, object? context)
 | 
			
		||||
    {
 | 
			
		||||
        if (context is TabItem tabItem)
 | 
			
		||||
        {
 | 
			
		||||
            await WinboxRender(tabItem.ChildContent, tabItem.Text);
 | 
			
		||||
            //await _tab.RemoveTab(tabItem);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    private WinBoxService? WinBoxService { get; set; }
 | 
			
		||||
 | 
			
		||||
    private async Task WinboxRender(RenderFragment item, string title)
 | 
			
		||||
    {
 | 
			
		||||
        if (item != null)
 | 
			
		||||
        {
 | 
			
		||||
            var option = new WinBoxOption()
 | 
			
		||||
            {
 | 
			
		||||
                Title = title,
 | 
			
		||||
                ContentTemplate = item,
 | 
			
		||||
                Max = false,
 | 
			
		||||
                Width = "80%",
 | 
			
		||||
                Height = "80%",
 | 
			
		||||
                Top = "0%",
 | 
			
		||||
                Left = "10%",
 | 
			
		||||
                Background = "var(--bb-primary-color)",
 | 
			
		||||
                Overflow = true
 | 
			
		||||
            };
 | 
			
		||||
            await WinBoxService.Show(option);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private string _versionString = string.Empty;
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,11 @@ public class Startup : AppStartup
 | 
			
		||||
        services.Configure<ForwardedHeadersOptions>(options =>
 | 
			
		||||
        {
 | 
			
		||||
            options.ForwardedHeaders = ForwardedHeaders.All;
 | 
			
		||||
#if NET10_0_OR_GREATER
 | 
			
		||||
            options.KnownIPNetworks.Clear();
 | 
			
		||||
#else
 | 
			
		||||
            options.KnownNetworks.Clear();
 | 
			
		||||
#endif
 | 
			
		||||
            options.KnownProxies.Clear();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -204,7 +208,16 @@ public class Startup : AppStartup
 | 
			
		||||
    public void Use(IApplicationBuilder applicationBuilder, IWebHostEnvironment env)
 | 
			
		||||
    {
 | 
			
		||||
        var app = (WebApplication)applicationBuilder;
 | 
			
		||||
        app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All, KnownNetworks = { }, KnownProxies = { } });
 | 
			
		||||
        app.UseForwardedHeaders(new ForwardedHeadersOptions
 | 
			
		||||
        {
 | 
			
		||||
            ForwardedHeaders = ForwardedHeaders.All,
 | 
			
		||||
#if NET10_0_OR_GREATER
 | 
			
		||||
            KnownIPNetworks = { },
 | 
			
		||||
#else
 | 
			
		||||
            KnownNetworks = { },
 | 
			
		||||
#endif
 | 
			
		||||
            KnownProxies = { }
 | 
			
		||||
        });
 | 
			
		||||
        app.UseBootstrapBlazor();
 | 
			
		||||
 | 
			
		||||
        // 启用本地化
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
 | 
			
		||||
		<TargetFrameworks>net8.0;$(OtherTargetFrameworks);</TargetFrameworks>
 | 
			
		||||
		
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
 | 
			
		||||
@@ -53,9 +53,9 @@
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.1" />
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.1" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="$(NET9Version)" />
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net10.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="$(NET10Version)" />
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="$(NET10Version)" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								src/Admin/ThingsGateway.AdminServer/wwwroot/pwa-install.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Admin/ThingsGateway.AdminServer/wwwroot/pwa-install.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
let installPromptTriggered = false;
 | 
			
		||||
 | 
			
		||||
function getCookie(name) {
 | 
			
		||||
    const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
 | 
			
		||||
    return match ? match[2] : null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function hasShownInstallPrompt() {
 | 
			
		||||
    return getCookie("tgPWAInstallPromptShown") === "true";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function markInstallPromptShown() {
 | 
			
		||||
    document.cookie = "tgPWAInstallPromptShown=true; max-age=31536000; path=/";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.addEventListener('beforeinstallprompt', (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
 | 
			
		||||
    if (!hasShownInstallPrompt() && !installPromptTriggered) {
 | 
			
		||||
        installPromptTriggered = true;
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
            e.prompt()
 | 
			
		||||
                .then(() => e.userChoice)
 | 
			
		||||
                .then(choiceResult => {
 | 
			
		||||
                    markInstallPromptShown();
 | 
			
		||||
                })
 | 
			
		||||
                .catch(err => {
 | 
			
		||||
                    // 可选错误处理
 | 
			
		||||
                });
 | 
			
		||||
        }, 2000); // 延迟 2 秒提示
 | 
			
		||||
    } else {
 | 
			
		||||
        // console.log("已提示过安装,不再弹出");
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
@@ -31,8 +31,8 @@ public static class GenericExtensions
 | 
			
		||||
 | 
			
		||||
        // 比较oldModel和model的属性,找出差异
 | 
			
		||||
        var differences = properties
 | 
			
		||||
            .Where(prop => prop.CanRead && prop.CanWrite) // 确保属性可读可写
 | 
			
		||||
            .Where(prop => !Equals(prop.GetValue(oldModel), prop.GetValue(model))) // 找出值不同的属性
 | 
			
		||||
            .Where(prop => prop.CanRead && prop.CanWrite && !Equals(prop.GetValue(oldModel), prop.GetValue(model))) // 确保属性可读可写
 | 
			
		||||
                                                                                                                    // 找出值不同的属性
 | 
			
		||||
            .ToDictionary(prop => prop.Name, prop => prop.GetValue(model)); // 将属性名和新值存储到字典中
 | 
			
		||||
 | 
			
		||||
        // 应用差异到channels列表中的每个Channel对象
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@ using System.Runtime.CompilerServices;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Common.Extension;
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 对象拓展类
 | 
			
		||||
@@ -48,113 +50,7 @@ public static class ObjectExtensions
 | 
			
		||||
        bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTimeOffset 转换成本地 DateTime
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTime ConvertToDateTime(this DateTimeOffset dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        if (dateTime.Offset.Equals(TimeSpan.Zero))
 | 
			
		||||
            return dateTime.UtcDateTime;
 | 
			
		||||
        if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
 | 
			
		||||
            return dateTime.ToLocalTime().DateTime;
 | 
			
		||||
        else
 | 
			
		||||
            return dateTime.DateTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTimeOffset? 转换成本地 DateTime?
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTime? ConvertToDateTime(this DateTimeOffset? dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        return dateTime.HasValue ? dateTime.Value.ConvertToDateTime() : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTime 转换成 DateTimeOffset
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTime? 转换成 DateTimeOffset?
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTimeOffset? ConvertToDateTimeOffset(this DateTime? dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        return dateTime.HasValue ? dateTime.Value.ConvertToDateTimeOffset() : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将流保存到本地磁盘
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="stream"></param>
 | 
			
		||||
    /// <param name="path"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static void CopyToSave(this Stream stream, string path)
 | 
			
		||||
    {
 | 
			
		||||
        // 空检查
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
 | 
			
		||||
 | 
			
		||||
        using var fileStream = File.Create(path);
 | 
			
		||||
        stream.CopyTo(fileStream);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将字节数组保存到本地磁盘
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="bytes"></param>
 | 
			
		||||
    /// <param name="path"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static void CopyToSave(this byte[] bytes, string path)
 | 
			
		||||
    {
 | 
			
		||||
        using var stream = new MemoryStream(bytes);
 | 
			
		||||
        stream.CopyToSave(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将流保存到本地磁盘
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="stream"></param>
 | 
			
		||||
    /// <param name="path">需包含文件名完整路径</param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static async Task CopyToSaveAsync(this Stream stream, string path)
 | 
			
		||||
    {
 | 
			
		||||
        // 空检查
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(path))
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentNullException(nameof(path));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 文件名判断
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(Path.GetFileName(path)))
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentException("The parameter of <path> parameter must include the complete file name.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        using var fileStream = File.Create(path);
 | 
			
		||||
        await stream.CopyToAsync(fileStream).ConfigureAwait(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将字节数组保存到本地磁盘
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="bytes"></param>
 | 
			
		||||
    /// <param name="path"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static async Task CopyToSaveAsync(this byte[] bytes, string path)
 | 
			
		||||
    {
 | 
			
		||||
        using var stream = new MemoryStream(bytes);
 | 
			
		||||
        await stream.CopyToSaveAsync(path).ConfigureAwait(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 合并两个字典
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ public static class ParallelExtensions
 | 
			
		||||
    /// <typeparam name="T">集合元素类型</typeparam>
 | 
			
		||||
    /// <param name="source">要操作的集合</param>
 | 
			
		||||
    /// <param name="body">要执行的操作</param>
 | 
			
		||||
    public static void ParallelForEach<T>(this IList<T> source, Action<T> body)
 | 
			
		||||
    public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T> body)
 | 
			
		||||
    {
 | 
			
		||||
        ParallelOptions options = new();
 | 
			
		||||
        options.MaxDegreeOfParallelism = Environment.ProcessorCount;
 | 
			
		||||
@@ -38,7 +38,7 @@ public static class ParallelExtensions
 | 
			
		||||
    /// <typeparam name="T">集合元素类型</typeparam>
 | 
			
		||||
    /// <param name="source">要操作的集合</param>
 | 
			
		||||
    /// <param name="body">要执行的操作</param>
 | 
			
		||||
    public static void ParallelForEach<T>(this IList<T> source, Action<T, ParallelLoopState, long> body)
 | 
			
		||||
    public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T, ParallelLoopState, long> body)
 | 
			
		||||
    {
 | 
			
		||||
        ParallelOptions options = new();
 | 
			
		||||
        options.MaxDegreeOfParallelism = Environment.ProcessorCount;
 | 
			
		||||
@@ -53,7 +53,7 @@ public static class ParallelExtensions
 | 
			
		||||
    /// <param name="source">要操作的集合</param>
 | 
			
		||||
    /// <param name="body">要执行的操作</param>
 | 
			
		||||
    /// <param name="parallelCount">最大并行度</param>
 | 
			
		||||
    public static void ParallelForEach<T>(this IList<T> source, Action<T> body, int parallelCount)
 | 
			
		||||
    public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T> body, int parallelCount)
 | 
			
		||||
    {
 | 
			
		||||
        // 创建并行操作的选项对象,设置最大并行度为指定的值
 | 
			
		||||
        var options = new ParallelOptions();
 | 
			
		||||
@@ -109,7 +109,7 @@ public static class ParallelExtensions
 | 
			
		||||
    /// <param name="parallelCount">最大并行度</param>
 | 
			
		||||
    /// <param name="cancellationToken">取消操作的标志</param>
 | 
			
		||||
    /// <returns>表示异步操作的任务</returns>
 | 
			
		||||
    public static Task ParallelForEachAsync<T>(this IList<T> source, Func<T, CancellationToken, ValueTask> body, int parallelCount, CancellationToken cancellationToken = default)
 | 
			
		||||
    public static Task ParallelForEachAsync<T>(this IEnumerable<T> source, Func<T, CancellationToken, ValueTask> body, int parallelCount, CancellationToken cancellationToken = default)
 | 
			
		||||
    {
 | 
			
		||||
        // 创建并行操作的选项对象,设置最大并行度和取消标志
 | 
			
		||||
        var options = new ParallelOptions();
 | 
			
		||||
@@ -126,7 +126,7 @@ public static class ParallelExtensions
 | 
			
		||||
    /// <param name="body">异步执行的操作</param>
 | 
			
		||||
    /// <param name="cancellationToken">取消操作的标志</param>
 | 
			
		||||
    /// <returns>表示异步操作的任务</returns>
 | 
			
		||||
    public static Task ParallelForEachAsync<T>(this IList<T> source, Func<T, CancellationToken, ValueTask> body, CancellationToken cancellationToken = default)
 | 
			
		||||
    public static Task ParallelForEachAsync<T>(this IEnumerable<T> source, Func<T, CancellationToken, ValueTask> body, CancellationToken cancellationToken = default)
 | 
			
		||||
    {
 | 
			
		||||
        return ParallelForEachAsync(source, body, Environment.ProcessorCount, cancellationToken);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,13 +8,13 @@
 | 
			
		||||
		
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
 | 
			
		||||
		<TargetFrameworks>net8.0;$(OtherTargetFrameworks);</TargetFrameworks>
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
	
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.7" />
 | 
			
		||||
		<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor" Version="9.10.1" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor" Version="9.11.2" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,15 @@ public abstract class PrimaryIdEntity : IPrimaryIdEntity
 | 
			
		||||
    public virtual long Id { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface IPrimaryKeyEntity
 | 
			
		||||
{
 | 
			
		||||
    string ExtJson { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 主键实体基类
 | 
			
		||||
/// </summary>
 | 
			
		||||
public abstract class PrimaryKeyEntity : PrimaryIdEntity
 | 
			
		||||
public abstract class PrimaryKeyEntity : PrimaryIdEntity, IPrimaryKeyEntity
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 拓展信息
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
		
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
 | 
			
		||||
		<TargetFrameworks>net8.0;$(OtherTargetFrameworks);</TargetFrameworks>
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway;
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace Microsoft.Extensions.Hosting;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.NewLife;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 对象拓展类
 | 
			
		||||
@@ -28,70 +28,10 @@ namespace ThingsGateway.Extensions;
 | 
			
		||||
[SuppressSniffer]
 | 
			
		||||
public static class ObjectExtensions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTimeOffset 转换成本地 DateTime
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTime ConvertToDateTime(this DateTimeOffset dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        if (dateTime.Offset.Equals(TimeSpan.Zero))
 | 
			
		||||
            return dateTime.UtcDateTime;
 | 
			
		||||
        if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
 | 
			
		||||
            return dateTime.ToLocalTime().DateTime;
 | 
			
		||||
        else
 | 
			
		||||
            return dateTime.DateTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTimeOffset? 转换成本地 DateTime?
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTime? ConvertToDateTime(this DateTimeOffset? dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        return dateTime.HasValue ? dateTime.Value.ConvertToDateTime() : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTime 转换成 DateTimeOffset
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 DateTime? 转换成 DateTimeOffset?
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="dateTime"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static DateTimeOffset? ConvertToDateTimeOffset(this DateTime? dateTime)
 | 
			
		||||
    {
 | 
			
		||||
        return dateTime.HasValue ? dateTime.Value.ConvertToDateTimeOffset() : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将时间戳转换为 DateTime
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="timestamp"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    internal static DateTime ConvertToDateTime(this long timestamp)
 | 
			
		||||
    {
 | 
			
		||||
        var timeStampDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 | 
			
		||||
        var digitCount = (int)Math.Floor(Math.Log10(timestamp) + 1);
 | 
			
		||||
 | 
			
		||||
        if (digitCount != 13 && digitCount != 10)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentException("Data is not a valid timestamp format.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (digitCount == 13
 | 
			
		||||
            ? timeStampDateTime.AddMilliseconds(timestamp)  // 13 位时间戳
 | 
			
		||||
            : timeStampDateTime.AddSeconds(timestamp)).ToLocalTime();   // 10 位时间戳
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 将 IFormFile 转换成 byte[]
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.AspNetCore;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.AspNetCore;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.AspNetCore;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway;
 | 
			
		||||
using ThingsGateway.ConfigurableOptions;
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,12 @@ public static class PBKDF2Encryption
 | 
			
		||||
        using var rng = RandomNumberGenerator.Create();
 | 
			
		||||
        var salt = new byte[saltSize];
 | 
			
		||||
        rng.GetBytes(salt);
 | 
			
		||||
 | 
			
		||||
#if NET10_0_OR_GREATER
 | 
			
		||||
        var hash = Rfc2898DeriveBytes.Pbkdf2(System.Text.Encoding.UTF8.GetBytes(text), salt, iterationCount, HashAlgorithmName.SHA256, derivedKeyLength);
 | 
			
		||||
#else
 | 
			
		||||
        using var pbkdf2 = new Rfc2898DeriveBytes(text, salt, iterationCount, HashAlgorithmName.SHA256);
 | 
			
		||||
        var hash = pbkdf2.GetBytes(derivedKeyLength);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        // 分别编码盐和哈希,并用分隔符拼接
 | 
			
		||||
        return Convert.ToBase64String(salt) + SaltHashSeparator + Convert.ToBase64String(hash);
 | 
			
		||||
@@ -65,8 +68,12 @@ public static class PBKDF2Encryption
 | 
			
		||||
            if (saltBytes.Length != saltSize || storedHashBytes.Length != derivedKeyLength)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
#if NET10_0_OR_GREATER
 | 
			
		||||
            var computedHash = Rfc2898DeriveBytes.Pbkdf2(System.Text.Encoding.UTF8.GetBytes(text), saltBytes, iterationCount, HashAlgorithmName.SHA256, derivedKeyLength);
 | 
			
		||||
#else
 | 
			
		||||
            using var pbkdf2 = new Rfc2898DeriveBytes(text, saltBytes, iterationCount, HashAlgorithmName.SHA256);
 | 
			
		||||
            var computedHash = pbkdf2.GetBytes(derivedKeyLength);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            return computedHash.SequenceEqual(storedHashBytes);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Templates.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.DataValidation;
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ using System.Collections.Concurrent;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.UnifyResult;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.DynamicApiController;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Templates.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.FriendlyException;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using Microsoft.AspNetCore.SignalR;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway;
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.InstantMessaging;
 | 
			
		||||
 | 
			
		||||
namespace Microsoft.AspNetCore.Builder;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Logging;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ using System.Text.Json;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway;
 | 
			
		||||
using ThingsGateway.DataValidation;
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.FriendlyException;
 | 
			
		||||
using ThingsGateway.JsonSerialization;
 | 
			
		||||
using ThingsGateway.Logging;
 | 
			
		||||
@@ -151,7 +151,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await MonitorAsync(actionMethod, context.ActionArguments, context, next).ConfigureAwait(false);
 | 
			
		||||
        await MonitorAsync(actionMethod, context.ActionArguments, context, () => next()).ConfigureAwait(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -183,7 +183,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await MonitorAsync(actionMethod, context.HandlerArguments, context, next).ConfigureAwait(false);
 | 
			
		||||
        await MonitorAsync(actionMethod, context.HandlerArguments, context, () => next()).ConfigureAwait(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -789,12 +789,12 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
        return typeName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task MonitorAsync(MethodInfo actionMethod, IDictionary<string, object> parameterValues, FilterContext context, dynamic next)
 | 
			
		||||
    private async Task MonitorAsync<T>(MethodInfo actionMethod, IDictionary<string, object> parameterValues, FilterContext context, Func<Task<T>> next)
 | 
			
		||||
    {
 | 
			
		||||
        // 排除 WebSocket 请求处理
 | 
			
		||||
        if (context.HttpContext.IsWebSocketRequest())
 | 
			
		||||
        {
 | 
			
		||||
            _ = await next();
 | 
			
		||||
            _ = await next().ConfigureAwait(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -805,14 +805,14 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
        if (actionMethod.IsDefined(typeof(SuppressMonitorAttribute), true)
 | 
			
		||||
            || actionMethod.DeclaringType.IsDefined(typeof(SuppressMonitorAttribute), true))
 | 
			
		||||
        {
 | 
			
		||||
            _ = await next();
 | 
			
		||||
            _ = await next().ConfigureAwait(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 判断是否自定义了日志筛选器,如果是则检查是否符合条件
 | 
			
		||||
        if (LoggingMonitorSettings.InternalWriteFilter?.Invoke(context) == false)
 | 
			
		||||
        {
 | 
			
		||||
            _ = await next();
 | 
			
		||||
            _ = await next().ConfigureAwait(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -825,7 +825,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
        // 解决局部和全局触发器同时配置触发两次问题
 | 
			
		||||
        if (isDefinedScopedAttribute && Settings.FromGlobalFilter == true)
 | 
			
		||||
        {
 | 
			
		||||
            _ = await next();
 | 
			
		||||
            _ = await next().ConfigureAwait(false);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -839,7 +839,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
                    && !Settings.IncludeOfMethods.Contains(methodFullName, StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    // 查找是否包含匹配,忽略大小写
 | 
			
		||||
                    _ = await next();
 | 
			
		||||
                    _ = await next().ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -847,7 +847,7 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
                if (Settings.GlobalEnabled
 | 
			
		||||
                    && Settings.ExcludeOfMethods.Contains(methodFullName, StringComparer.OrdinalIgnoreCase))
 | 
			
		||||
                {
 | 
			
		||||
                    _ = await next();
 | 
			
		||||
                    _ = await next().ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -958,7 +958,8 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
 | 
			
		||||
        // 计算接口执行时间
 | 
			
		||||
        var timeOperation = Stopwatch.StartNew();
 | 
			
		||||
        var resultContext = await next();
 | 
			
		||||
 | 
			
		||||
        var resultContext = await next().ConfigureAwait(false);
 | 
			
		||||
        timeOperation.Stop();
 | 
			
		||||
        writer.WriteNumber("timeOperationElapsedMilliseconds", timeOperation.ElapsedMilliseconds);
 | 
			
		||||
 | 
			
		||||
@@ -1014,8 +1015,13 @@ public sealed class LoggingMonitorAttribute : Attribute, IAsyncActionFilter, IAs
 | 
			
		||||
        var environment = httpContext.RequestServices.GetRequiredService<IWebHostEnvironment>().EnvironmentName;
 | 
			
		||||
        writer.WriteString(nameof(environment), environment);
 | 
			
		||||
 | 
			
		||||
        Exception exception = null;
 | 
			
		||||
        // 获取异常对象情况
 | 
			
		||||
        Exception exception = resultContext.Exception;
 | 
			
		||||
        if (resultContext is PageHandlerExecutedContext pageHandlerExecutedContext)
 | 
			
		||||
            exception = pageHandlerExecutedContext.Exception;
 | 
			
		||||
        else if (resultContext is ActionExecutedContext actionExecutedContext)
 | 
			
		||||
            exception = actionExecutedContext.Exception;
 | 
			
		||||
 | 
			
		||||
        if (exception == null)
 | 
			
		||||
        {
 | 
			
		||||
            // 解析存储的验证信息
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Options;
 | 
			
		||||
 | 
			
		||||
namespace Microsoft.Extensions.Options;
 | 
			
		||||
 
 | 
			
		||||
@@ -204,7 +204,7 @@ internal sealed partial class SchedulerFactory : ISchedulerFactory
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogWarning("Schedule hosted service preload completed, and a total of <{Count}> schedulers are appended.", _schedulers.Count);
 | 
			
		||||
                _logger.LogInformation("Schedule hosted service preload completed, and a total of <{Count}> schedulers are appended.", _schedulers.Count);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ using System.Xml.Linq;
 | 
			
		||||
using System.Xml.XPath;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.DynamicApiController;
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.SpecificationDocument;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.SpecificationDocument;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Templates.Extensions;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
	<Import Project="..\..\PackNuget.props" />
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
 | 
			
		||||
		<TargetFrameworks>net8.0;$(OtherTargetFrameworks);</TargetFrameworks>
 | 
			
		||||
		
 | 
			
		||||
	</PropertyGroup>
 | 
			
		||||
	
 | 
			
		||||
@@ -29,8 +29,8 @@
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.4" />
 | 
			
		||||
		<PackageReference Include="System.Text.Encoding.CodePages" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" />
 | 
			
		||||
		<PackageReference Include="System.Text.Encoding.CodePages" Version="$(NET10Version)" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
 | 
			
		||||
@@ -39,10 +39,10 @@
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="8.0.2" />
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
	
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net9.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(NET9Version)" />
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(NET9Version)" />
 | 
			
		||||
	<ItemGroup Condition=" '$(TargetFramework)' == 'net10.0' ">
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(NET10Version)" />
 | 
			
		||||
		<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(NET10Version)" />
 | 
			
		||||
		<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(NET10Version)" />
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
	</ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Http;
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.UnifyResult;
 | 
			
		||||
 | 
			
		||||
namespace Microsoft.AspNetCore.Mvc;
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ using Microsoft.Extensions.Options;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.FriendlyException;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.UnifyResult;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Converters.Json;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="Assembly" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="ConcurrentDictionary{TKey, TValue}" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Hosting;
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     核心模块 <see cref="IServiceCollection" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Data;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="DataTable" /> 和 <see cref="DataSet" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     委托拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     枚举拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="EventHandler{TEventArgs}" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="ICollection{T}" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="IDictionary{TKey, TValue}" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="IEnumerable" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ using System.Text.RegularExpressions;
 | 
			
		||||
using System.Xml;
 | 
			
		||||
using System.Xml.Linq;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     System.Text.Json 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.Linq.Expressions;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="Expression" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="MethodInfo" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     数值类型拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="string" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using System.Reflection;
 | 
			
		||||
using System.Reflection.Emit;
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="Type" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ using System.Buffers;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="Utf8JsonReader" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using System.Text.Json;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Extensions;
 | 
			
		||||
namespace ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
///     <see cref="object" /> 拓展类
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ using System.Collections.Concurrent;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Reflection;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ using System.Collections.Concurrent;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Reflection;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ using Microsoft.Net.Http.Headers;
 | 
			
		||||
using System.Net.Mime;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.AspNetCore.Extensions;
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.Net.Http.Headers;
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using System.Text;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using Microsoft.Extensions.Logging;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ using System.Net.Mime;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using System.Globalization;
 | 
			
		||||
using System.Net.Http.Headers;
 | 
			
		||||
using System.Net.Mime;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
using CacheControlHeaderValue = System.Net.Http.Headers.CacheControlHeaderValue;
 | 
			
		||||
using StringWithQualityHeaderValue = System.Net.Http.Headers.StringWithQualityHeaderValue;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.Net.Mime;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ using System.Net.Mime;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
using System.Net.Http.Headers;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote.Extensions;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ using System.Net.Http.Headers;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
using StringWithQualityHeaderValue = System.Net.Http.Headers.StringWithQualityHeaderValue;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Controllers;
 | 
			
		||||
using Microsoft.AspNetCore.Mvc.Filters;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.HttpRemote.Extensions;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Options;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Options;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ using Microsoft.Extensions.Options;
 | 
			
		||||
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Extensions;
 | 
			
		||||
using ThingsGateway.Extension;
 | 
			
		||||
using ThingsGateway.Utilities;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.HttpRemote;
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user