mirror of
				https://gitee.com/ThingsGateway/ThingsGateway.git
				synced 2025-11-04 01:23:58 +08:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			variablePa
			...
			21215d0379
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					21215d0379 | ||
| 
						 | 
					7448183791 | 
@@ -4,8 +4,8 @@
 | 
			
		||||
 | 
			
		||||
<div class="tg-table h-100">
 | 
			
		||||
 | 
			
		||||
    <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
 | 
			
		||||
    <Table Id=@Id 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 OnColumnCreating=OnColumnCreating
 | 
			
		||||
           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
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
           ShowSkeleton="true" ShowLoading="ShowLoading" ShowSearch="ShowSearch" SearchModel=@SearchModel ShowLineNo
 | 
			
		||||
           SearchMode=SearchMode ShowExportPdfButton=ShowExportPdfButton ExportButtonText=@ExportButtonText
 | 
			
		||||
           ShowExportButton=@ShowExportButton Items=Items ClickToSelect=ClickToSelect ScrollMode=ScrollMode
 | 
			
		||||
           ShowExportCsvButton=@ShowExportCsvButton ShowCardView=ShowCardView
 | 
			
		||||
           ShowExportCsvButton=@ShowExportCsvButton ShowCardView=ShowCardView OnColumnVisibleChanged=OnColumnVisibleChanged
 | 
			
		||||
           FixedExtendButtonsColumn=FixedExtendButtonsColumn FixedMultipleColumn=FixedMultipleColumn FixedDetailRowHeaderColumn=FixedDetailRowHeaderColumn FixedLineNoColumn=FixedLineNoColumn
 | 
			
		||||
           IsAutoRefresh=IsAutoRefresh AutoRefreshInterval=AutoRefreshInterval
 | 
			
		||||
           AllowDragColumn=@AllowDragColumn Height=@Height ShowRefresh=ShowRefresh
 | 
			
		||||
 
 | 
			
		||||
@@ -13,13 +13,22 @@ namespace ThingsGateway.Admin.Razor;
 | 
			
		||||
[CascadingTypeParameter(nameof(TItem))]
 | 
			
		||||
public partial class AdminTable<TItem> where TItem : class, new()
 | 
			
		||||
{
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.OnColumnVisibleChanged"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public Func<string,bool, Task> OnColumnVisibleChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.OnColumnCreating"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public Func<List<ITableColumn>,Task> OnColumnCreating { get; set; }
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.RenderMode"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public TableRenderMode RenderMode { get; set; }
 | 
			
		||||
 | 
			
		||||
    public List<ITableColumn> Columns => Instance?.Columns;
 | 
			
		||||
 | 
			
		||||
    public IEnumerable<ITableColumn> GetVisibleColumns => Instance?.GetVisibleColumns();
 | 
			
		||||
    public List<TItem> Rows => Instance?.Rows;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
@@ -158,6 +167,9 @@ public partial class AdminTable<TItem> where TItem : class, new()
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public IDataService<TItem> DataService { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public string? Id { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="Table{TItem}.CreateItemCallback"/>
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public Func<TItem> CreateItemCallback { get; set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ public partial class HardwareInfoPage : IDisposable
 | 
			
		||||
            ChartDataSource.Options.Title = Localizer[nameof(HistoryHardwareInfo)];
 | 
			
		||||
            ChartDataSource.Options.X.Title = Localizer["DateTime"];
 | 
			
		||||
            ChartDataSource.Options.Y.Title = Localizer["Data"];
 | 
			
		||||
            ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd HH:mm zz"));
 | 
			
		||||
            ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd-HH:mm"));
 | 
			
		||||
            ChartDataSource.Data.Add(new ChartDataset()
 | 
			
		||||
            {
 | 
			
		||||
                Tension = 0.4f,
 | 
			
		||||
@@ -116,7 +116,7 @@ public partial class HardwareInfoPage : IDisposable
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var hisHardwareInfos = await HardwareJob.GetHistoryHardwareInfos();
 | 
			
		||||
            ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd HH:mm zz"));
 | 
			
		||||
            ChartDataSource.Labels = hisHardwareInfos.Select(a => a.Date.ToString("dd-HH:mm"));
 | 
			
		||||
            ChartDataSource.Data[0].Data = hisHardwareInfos.Select(a => (object)a.CpuUsage);
 | 
			
		||||
            ChartDataSource.Data[1].Data = hisHardwareInfos.Select(a => (object)a.MemoryUsage);
 | 
			
		||||
            ChartDataSource.Data[2].Data = hisHardwareInfos.Select(a => (object)a.DriveUsage);
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
 | 
			
		||||
	<ItemGroup>
 | 
			
		||||
		<ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.3" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.4" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
 | 
			
		||||
		<PackageReference Include="BootstrapBlazor.CodeEditor" Version="9.0.3" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
<Project>
 | 
			
		||||
 | 
			
		||||
	<PropertyGroup>
 | 
			
		||||
		<PluginVersion>10.11.108</PluginVersion>
 | 
			
		||||
		<ProPluginVersion>10.11.108</ProPluginVersion>
 | 
			
		||||
		<DefaultVersion>10.11.108</DefaultVersion>
 | 
			
		||||
		<PluginVersion>10.11.109</PluginVersion>
 | 
			
		||||
		<ProPluginVersion>10.11.109</ProPluginVersion>
 | 
			
		||||
		<DefaultVersion>10.11.109</DefaultVersion>
 | 
			
		||||
		<AuthenticationVersion>10.11.6</AuthenticationVersion>
 | 
			
		||||
		<SourceGeneratorVersion>10.11.6</SourceGeneratorVersion>
 | 
			
		||||
		<NET8Version>8.0.21</NET8Version>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
@inherits ThingsGatewayModuleComponentBase
 | 
			
		||||
@attribute [JSModuleAutoLoader("Components/QuickActions.razor.js", AutoInvokeDispose = false)]
 | 
			
		||||
@attribute [JSModuleAutoLoader("Components/QuickActions.razor.js", AutoInvokeDispose = false, AutoInvokeInit = true)]
 | 
			
		||||
@namespace ThingsGateway.Gateway.Razor
 | 
			
		||||
 | 
			
		||||
<div id="@Id">
 | 
			
		||||
@@ -8,12 +8,12 @@
 | 
			
		||||
    <div class="quickactions-list">
 | 
			
		||||
        <div class="quickactions-header">
 | 
			
		||||
            <div class="flex-fill">@HeaderText</div>
 | 
			
		||||
            <button class="btn-close btn-close-white" type="button" aria-label="Close" onclick=@(async ()=>await ToggleOpen())></button>
 | 
			
		||||
            <button class="btn-close btn-close-white" type="button" aria-label="Close" onclick=@(async () => await ToggleOpen())></button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="mx-2 row g-0">
 | 
			
		||||
 | 
			
		||||
            <div class="col-12 my-1">
 | 
			
		||||
                <RadioList ShowLabel="true" TValue="bool" IsButton ValueExpression=@(()=> AutoRestartThread ) Value="AutoRestartThread" ValueChanged="OnAutoRestartThreadChanged" Items="AutoRestartThreadBoolItems" />
 | 
			
		||||
                <RadioList ShowLabel="true" TValue="bool" IsButton ValueExpression=@(() => AutoRestartThread) Value="AutoRestartThread" ValueChanged="OnAutoRestartThreadChanged" Items="AutoRestartThreadBoolItems" />
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
			
		||||
//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
			
		||||
//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
			
		||||
//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
			
		||||
//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
			
		||||
//  使用文档:https://thingsgateway.cn/
 | 
			
		||||
//  QQ群:605534569
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Gateway.Razor;
 | 
			
		||||
 | 
			
		||||
public readonly struct CellValue
 | 
			
		||||
{
 | 
			
		||||
    public readonly string Field { get; }
 | 
			
		||||
    public readonly string Value { get; }
 | 
			
		||||
    public CellValue(string f, string v) { Field = f; Value = v; }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
using ThingsGateway.NewLife.Caching;
 | 
			
		||||
using ThingsGateway.NewLife.Json.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Gateway.Razor;
 | 
			
		||||
 | 
			
		||||
public static class VariableModelUtils
 | 
			
		||||
{
 | 
			
		||||
    static MemoryCache MemoryCache = new();
 | 
			
		||||
    public static object GetPropertyValue(VariableRuntime model, string fieldName)
 | 
			
		||||
    {
 | 
			
		||||
        if (model == null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ArgumentNullException(nameof(model));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (MemoryCache.TryGetValue(fieldName, out Func<VariableRuntime, object> data))
 | 
			
		||||
        {
 | 
			
		||||
            return data(model);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var ret = MemoryCache.GetOrAdd(fieldName, (fieldName) =>
 | 
			
		||||
        {
 | 
			
		||||
            return LambdaExtensions.GetPropertyValueLambda<VariableRuntime, object?>(model, fieldName).Compile();
 | 
			
		||||
        })(model);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static string GetValue(VariableRuntime row, string fieldName)
 | 
			
		||||
    {
 | 
			
		||||
        switch (fieldName)
 | 
			
		||||
        {
 | 
			
		||||
            case nameof(VariableRuntime.Value):
 | 
			
		||||
             return row.Value?.ToSystemTextJsonString() ?? string.Empty;
 | 
			
		||||
            case nameof(VariableRuntime.RawValue):
 | 
			
		||||
             return row.RawValue?.ToSystemTextJsonString() ?? string.Empty;
 | 
			
		||||
            case nameof(VariableRuntime.LastSetValue):
 | 
			
		||||
             return row.LastSetValue?.ToSystemTextJsonString() ?? string.Empty;
 | 
			
		||||
            case nameof(VariableRuntime.ChangeTime):
 | 
			
		||||
                return row.ChangeTime.ToString("dd-HH:mm:ss.fff");
 | 
			
		||||
 | 
			
		||||
            case nameof(VariableRuntime.CollectTime):
 | 
			
		||||
                return row.CollectTime.ToString("dd-HH:mm:ss.fff");
 | 
			
		||||
 | 
			
		||||
            case nameof(VariableRuntime.IsOnline):
 | 
			
		||||
                return row.IsOnline.ToString();
 | 
			
		||||
 | 
			
		||||
            case nameof(VariableRuntime.LastErrorMessage):
 | 
			
		||||
              return row.LastErrorMessage;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            case nameof(VariableRuntime.RuntimeType):
 | 
			
		||||
              return row.RuntimeType;
 | 
			
		||||
            default:
 | 
			
		||||
 | 
			
		||||
                var ret = VariableModelUtils.GetPropertyValue(row, fieldName);
 | 
			
		||||
 | 
			
		||||
                if (ret != null)
 | 
			
		||||
                {
 | 
			
		||||
                    var t = ret.GetType();
 | 
			
		||||
                    if (t.IsEnum)
 | 
			
		||||
                    {
 | 
			
		||||
                        // 如果是枚举这里返回 枚举的描述信息
 | 
			
		||||
                        var itemName = ret.ToString();
 | 
			
		||||
                        if (!string.IsNullOrEmpty(itemName))
 | 
			
		||||
                        {
 | 
			
		||||
                            ret = Utility.GetDisplayName(t, itemName);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return  ret is string str ? str : ret?.ToString() ?? string.Empty;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Alignment GetAlign(this ITableColumn col) => col.Align ?? Alignment.None;
 | 
			
		||||
    internal static bool GetTextWrap(this ITableColumn col) => col.TextWrap ?? false;
 | 
			
		||||
    internal static bool GetShowTips(this ITableColumn col) => col.ShowTips ?? false;
 | 
			
		||||
 | 
			
		||||
    internal static bool GetTextEllipsis(this ITableColumn col) => col.TextEllipsis ?? false;
 | 
			
		||||
}
 | 
			
		||||
@@ -9,11 +9,18 @@
 | 
			
		||||
 | 
			
		||||
@foreach (var col in RowContent.Columns)
 | 
			
		||||
{
 | 
			
		||||
    <td class="@GetFixedCellClassString(col)" style="@GetFixedCellStyleString(col)">
 | 
			
		||||
        <DynamicElement TagName="div" TriggerClick="@false"
 | 
			
		||||
                        StopPropagation="false"
 | 
			
		||||
                        class="@GetCellClassString(col, false, false)">
 | 
			
		||||
            @GetValue(col, RowContent.Row)
 | 
			
		||||
        </DynamicElement>
 | 
			
		||||
    <td class="@GetFixedCellClassString(col)" style="@GetFixedCellStyleString(col)" @key=col>
 | 
			
		||||
        <div class="@GetCellClassString(col, false, false)" @key=col>
 | 
			
		||||
            @if(col.GetShowTips())
 | 
			
		||||
            {
 | 
			
		||||
                <Tooltip @key=col Title="@VariableModelUtils.GetValue(RowContent.Row, col.GetFieldName())" class="text-truncate d-block">
 | 
			
		||||
                    @VariableModelUtils.GetValue(RowContent.Row, col.GetFieldName())
 | 
			
		||||
                </Tooltip>
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                @VariableModelUtils.GetValue(RowContent.Row, col.GetFieldName())
 | 
			
		||||
            }
 | 
			
		||||
        </div>
 | 
			
		||||
    </td>
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,40 +10,36 @@
 | 
			
		||||
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.NewLife.Threading;
 | 
			
		||||
 | 
			
		||||
using TouchSocket.Core;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Gateway.Razor;
 | 
			
		||||
 | 
			
		||||
public partial class VariableRow : IDisposable
 | 
			
		||||
public partial class VariableRow
 | 
			
		||||
{
 | 
			
		||||
    [Parameter]
 | 
			
		||||
    public TableRowContext<VariableRuntime>? RowContent { get; set; }
 | 
			
		||||
    private bool Disposed;
 | 
			
		||||
    public void Dispose()
 | 
			
		||||
    {
 | 
			
		||||
        Disposed = true;
 | 
			
		||||
        timer?.SafeDispose();
 | 
			
		||||
        GC.SuppressFinalize(this);
 | 
			
		||||
    }
 | 
			
		||||
    TimerX? timer;
 | 
			
		||||
    protected override void OnAfterRender(bool firstRender)
 | 
			
		||||
    {
 | 
			
		||||
        if (firstRender)
 | 
			
		||||
        {
 | 
			
		||||
            timer = new TimerX(Refresh, null, 1000, 1000, "VariableRow");
 | 
			
		||||
        }
 | 
			
		||||
        base.OnAfterRender(firstRender);
 | 
			
		||||
    }
 | 
			
		||||
    //private bool Disposed;
 | 
			
		||||
    //public void Dispose()
 | 
			
		||||
    //{
 | 
			
		||||
    //    Disposed = true;
 | 
			
		||||
    //    timer?.SafeDispose();
 | 
			
		||||
    //    GC.SuppressFinalize(this);
 | 
			
		||||
    //}
 | 
			
		||||
    //TimerX? timer;
 | 
			
		||||
    //protected override void OnAfterRender(bool firstRender)
 | 
			
		||||
    //{
 | 
			
		||||
    //    if (firstRender)
 | 
			
		||||
    //    {
 | 
			
		||||
    //        timer = new TimerX(Refresh, null, 1000, 1000, "VariableRow");
 | 
			
		||||
    //    }
 | 
			
		||||
    //    base.OnAfterRender(firstRender);
 | 
			
		||||
    //}
 | 
			
		||||
 | 
			
		||||
    private Task Refresh(object? state)
 | 
			
		||||
    {
 | 
			
		||||
        if (!Disposed)
 | 
			
		||||
            return InvokeAsync(StateHasChanged);
 | 
			
		||||
        else
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
    }
 | 
			
		||||
    //private Task Refresh(object? state)
 | 
			
		||||
    //{
 | 
			
		||||
    //    if (!Disposed)
 | 
			
		||||
    //        return InvokeAsync(StateHasChanged);
 | 
			
		||||
    //    else
 | 
			
		||||
    //        return Task.CompletedTask;
 | 
			
		||||
    //}
 | 
			
		||||
 | 
			
		||||
    protected override void OnParametersSet()
 | 
			
		||||
    {
 | 
			
		||||
@@ -51,32 +47,6 @@ public partial class VariableRow : IDisposable
 | 
			
		||||
        CellClassStringCache?.Clear();
 | 
			
		||||
        base.OnParametersSet();
 | 
			
		||||
    }
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获得 指定单元格数据方法
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="col"></param>
 | 
			
		||||
    /// <param name="item"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    protected static RenderFragment GetValue(ITableColumn col, VariableRuntime item) => builder =>
 | 
			
		||||
    {
 | 
			
		||||
        if (col.Template != null)
 | 
			
		||||
        {
 | 
			
		||||
            builder.AddContent(0, col.Template(item));
 | 
			
		||||
        }
 | 
			
		||||
        else if (col.ComponentType == typeof(ColorPicker))
 | 
			
		||||
        {
 | 
			
		||||
            // 自动化处理 ColorPicker 组件
 | 
			
		||||
            builder.AddContent(10, col.RenderColor(item));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            builder.AddContent(20, col.RenderValue(item));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //    internal static string? GetDoubleClickCellClassString(bool trigger) => CssBuilder.Default()
 | 
			
		||||
    //.AddClass("is-dbcell", trigger)
 | 
			
		||||
    //.Build();
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获得指定列头固定列样式
 | 
			
		||||
@@ -209,7 +179,7 @@ public partial class VariableRow : IDisposable
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return FixedCellClassStringCache.GetOrAdd(col, col => CssBuilder.Default()
 | 
			
		||||
            return FixedCellClassStringCache.GetOrAdd(col, col => CssBuilder.Default(col.GetFieldName())
 | 
			
		||||
    .AddClass("fixed", col.Fixed)
 | 
			
		||||
    .AddClass("fixed-right", col.Fixed && IsTail(col))
 | 
			
		||||
    .AddClass("fr", IsLastColumn(col))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
//  此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
 | 
			
		||||
//  此代码版权(除特别声明外的代码)归作者本人Diego所有
 | 
			
		||||
//  源代码使用协议遵循本仓库的开源协议及附加协议
 | 
			
		||||
//  Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
 | 
			
		||||
//  Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
 | 
			
		||||
//  使用文档:https://thingsgateway.cn/
 | 
			
		||||
//  QQ群:605534569
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Gateway.Razor;
 | 
			
		||||
 | 
			
		||||
internal static class VariableRowHelpers
 | 
			
		||||
{
 | 
			
		||||
    internal static Alignment GetAlign(this ITableColumn col) => col.Align ?? Alignment.None;
 | 
			
		||||
    internal static bool GetTextWrap(this ITableColumn col) => col.TextWrap ?? false;
 | 
			
		||||
    internal static bool GetShowTips(this ITableColumn col) => col.ShowTips ?? false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    internal static RenderFragment RenderColor<TItem>(this ITableColumn col, TItem item) => builder =>
 | 
			
		||||
    {
 | 
			
		||||
        var val = GetItemValue(col, item);
 | 
			
		||||
        var v = val?.ToString() ?? "#000";
 | 
			
		||||
        var style = $"background-color: {v};";
 | 
			
		||||
        builder.OpenElement(0, "div");
 | 
			
		||||
        builder.AddAttribute(1, "class", "is-color");
 | 
			
		||||
        builder.AddAttribute(2, "style", style);
 | 
			
		||||
        builder.CloseElement();
 | 
			
		||||
    };
 | 
			
		||||
    internal static object? GetItemValue<TItem>(this ITableColumn col, TItem item)
 | 
			
		||||
    {
 | 
			
		||||
        var fieldName = col.GetFieldName();
 | 
			
		||||
        object? ret;
 | 
			
		||||
        if (item is IDynamicObject dynamicObject)
 | 
			
		||||
        {
 | 
			
		||||
            ret = dynamicObject.GetValue(fieldName);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            ret = Utility.GetPropertyValue<TItem, object?>(item, fieldName);
 | 
			
		||||
 | 
			
		||||
            if (ret != null)
 | 
			
		||||
            {
 | 
			
		||||
                var t = ret.GetType();
 | 
			
		||||
                if (t.IsEnum)
 | 
			
		||||
                {
 | 
			
		||||
                    // 如果是枚举这里返回 枚举的描述信息
 | 
			
		||||
                    var itemName = ret.ToString();
 | 
			
		||||
                    if (!string.IsNullOrEmpty(itemName))
 | 
			
		||||
                    {
 | 
			
		||||
                        ret = Utility.GetDisplayName(t, itemName);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    internal static bool GetTextEllipsis(this ITableColumn col) => col.TextEllipsis ?? false;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -4,10 +4,16 @@
 | 
			
		||||
@using ThingsGateway.Admin.Application
 | 
			
		||||
@using ThingsGateway.Admin.Razor
 | 
			
		||||
@using ThingsGateway.Gateway.Application
 | 
			
		||||
@inherits ComponentDefault
 | 
			
		||||
@attribute [JSModuleAutoLoader("Pages/GatewayMonitorPage/Variable/VariableRuntimeInfo.razor.js", AutoInvokeInit = true, AutoInvokeDispose = false, JSObjectReference = true)]
 | 
			
		||||
@inherits ThingsGatewayModuleComponentBase
 | 
			
		||||
 | 
			
		||||
<AdminTable @ref=table BeforeShowEditDialogCallback="BeforeShowEditDialogCallback"
 | 
			
		||||
@* RenderMode="TableRenderMode.Table"
 | 
			
		||||
      ShowCardView=false *@
 | 
			
		||||
 | 
			
		||||
<AdminTable Id=@Id @ref=table BeforeShowEditDialogCallback="BeforeShowEditDialogCallback"
 | 
			
		||||
            TItem="VariableRuntime"
 | 
			
		||||
            RenderMode="TableRenderMode.Table"
 | 
			
		||||
            ShowCardView=false
 | 
			
		||||
            EditDialogSize="Size.ExtraLarge"
 | 
			
		||||
            AutoGenerateColumns="true"
 | 
			
		||||
            ShowAdvancedSearch=false
 | 
			
		||||
@@ -15,13 +21,13 @@
 | 
			
		||||
            AllowResizing="true"
 | 
			
		||||
            OnAdd="OnAdd"
 | 
			
		||||
            IsFixedHeader=true
 | 
			
		||||
            ShowCardView=false
 | 
			
		||||
            IsMultipleSelect=true
 | 
			
		||||
            SearchMode=SearchMode.Top
 | 
			
		||||
            ShowExtendButtons=true
 | 
			
		||||
            ShowToolbar="true"
 | 
			
		||||
            ShowExportButton
 | 
			
		||||
            RenderMode="TableRenderMode.Table"
 | 
			
		||||
            OnColumnCreating="OnColumnCreating"
 | 
			
		||||
            OnColumnVisibleChanged=OnColumnVisibleChanged
 | 
			
		||||
            ShowDefaultButtons=true
 | 
			
		||||
            ShowSearch=false
 | 
			
		||||
            ExtendButtonColumnWidth=220
 | 
			
		||||
@@ -40,8 +46,8 @@
 | 
			
		||||
        <TableColumn @bind-Field="@context.RpcWriteCheck" ShowTips=true Filterable=true Sortable=true Visible=false />
 | 
			
		||||
 | 
			
		||||
        <TableColumn @bind-Field="@context.Enable" Filterable=true Sortable=true Visible="false" />
 | 
			
		||||
        <TableColumn Field="@context.ChangeTime" ShowTips=true FieldExpression=@(() => context.ChangeTime) Filterable=true Sortable=true Visible=false />
 | 
			
		||||
        <TableColumn Field="@context.CollectTime" ShowTips=true FieldExpression=@(() => context.CollectTime) Filterable=true Sortable=true Visible=true />
 | 
			
		||||
        <TableColumn Field="@context.ChangeTime" Width=120 ShowTips=true FieldExpression=@(() => context.ChangeTime) Filterable=true Sortable=true Visible=false />
 | 
			
		||||
        <TableColumn Field="@context.CollectTime" Width=120 ShowTips =true FieldExpression=@(() => context.CollectTime) Filterable=true Sortable=true Visible=true />
 | 
			
		||||
        <TableColumn Field="@context.IsOnline" FieldExpression=@(() => context.IsOnline) Filterable=true Sortable=true Visible=true />
 | 
			
		||||
        <TableColumn Field="@context.LastErrorMessage" ShowTips=true FieldExpression=@(() => context.LastErrorMessage) Filterable=true Sortable=true Visible=false />
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Components.Forms;
 | 
			
		||||
using Microsoft.Extensions.Options;
 | 
			
		||||
using Microsoft.JSInterop;
 | 
			
		||||
 | 
			
		||||
using ThingsGateway.Admin.Application;
 | 
			
		||||
using ThingsGateway.Admin.Razor;
 | 
			
		||||
@@ -19,11 +20,107 @@ using ThingsGateway.NewLife.Json.Extension;
 | 
			
		||||
 | 
			
		||||
namespace ThingsGateway.Gateway.Razor;
 | 
			
		||||
 | 
			
		||||
public partial class VariableRuntimeInfo : IDisposable
 | 
			
		||||
public partial class VariableRuntimeInfo
 | 
			
		||||
{
 | 
			
		||||
    public List<ITableColumn> ColumnsFunc()
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    protected BlazorAppContext? AppContext { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    private NavigationManager? NavigationManager { get; set; }
 | 
			
		||||
 | 
			
		||||
    public string RouteName => NavigationManager.ToBaseRelativePath(NavigationManager.Uri);
 | 
			
		||||
 | 
			
		||||
    protected bool AuthorizeButton(string operate)
 | 
			
		||||
    {
 | 
			
		||||
        return table?.Columns;
 | 
			
		||||
        return AppContext.IsHasButtonWithRole(RouteName, operate);
 | 
			
		||||
    }
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    public IStringLocalizer<ThingsGateway.Razor._Imports>? RazorLocalizer { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    public IStringLocalizer<ThingsGateway.Admin.Razor._Imports>? AdminLocalizer { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    public DialogService? DialogService { get; set; }
 | 
			
		||||
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    public IStringLocalizer? Localizer { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    public IStringLocalizer<OperDescAttribute>? OperDescLocalizer { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Inject]
 | 
			
		||||
    [NotNull]
 | 
			
		||||
    public ToastService? ToastService { get; set; }
 | 
			
		||||
 | 
			
		||||
    #region js
 | 
			
		||||
    private List<ITableColumn> ColumnsFunc()
 | 
			
		||||
    {
 | 
			
		||||
        return table.Columns;
 | 
			
		||||
    }
 | 
			
		||||
    protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new { Method = nameof(TriggerStateChanged) });
 | 
			
		||||
 | 
			
		||||
    private Task OnColumnVisibleChanged(string name, bool visible)
 | 
			
		||||
    {
 | 
			
		||||
        _cachedFields = table.GetVisibleColumns.ToArray();
 | 
			
		||||
        return Task.CompletedTask;
 | 
			
		||||
    }
 | 
			
		||||
    private Task OnColumnCreating(List<ITableColumn> columns)
 | 
			
		||||
    {
 | 
			
		||||
        foreach (var column in columns)
 | 
			
		||||
        {
 | 
			
		||||
            column.OnCellRender = a =>
 | 
			
		||||
            {
 | 
			
		||||
                a.Class = $"{column.GetFieldName()}";
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        return Task.CompletedTask;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ITableColumn[] _cachedFields = Array.Empty<ITableColumn>();
 | 
			
		||||
 | 
			
		||||
    [JSInvokable]
 | 
			
		||||
    public List<CellValue> TriggerStateChanged(int rowIndex)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            if (table == null) return null;
 | 
			
		||||
            var row = table.Rows[rowIndex];
 | 
			
		||||
            if (_cachedFields.Length == 0) _cachedFields = table.GetVisibleColumns.ToArray();
 | 
			
		||||
            var list = new List<CellValue>(_cachedFields.Length);
 | 
			
		||||
            foreach (var col in _cachedFields)
 | 
			
		||||
            {
 | 
			
		||||
                var fieldName = col.GetFieldName();
 | 
			
		||||
                list.Add(new(fieldName, VariableModelUtils.GetValue(row,fieldName)));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return list;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception)
 | 
			
		||||
        {
 | 
			
		||||
            return new();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    #endregion
 | 
			
		||||
 | 
			
		||||
    protected override void OnAfterRender(bool firstRender)
 | 
			
		||||
    {
 | 
			
		||||
        if (firstRender || _cachedFields.Length == 0)
 | 
			
		||||
        {
 | 
			
		||||
            _cachedFields = table.GetVisibleColumns.ToArray();
 | 
			
		||||
        }
 | 
			
		||||
        base.OnAfterRender(firstRender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if !Management
 | 
			
		||||
@@ -43,17 +140,16 @@ public partial class VariableRuntimeInfo : IDisposable
 | 
			
		||||
    [Inject]
 | 
			
		||||
    private IOptions<WebsiteOptions>? WebsiteOption { get; set; }
 | 
			
		||||
    public bool Disposed { get; set; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void Dispose()
 | 
			
		||||
    protected override ValueTask DisposeAsync(bool disposing)
 | 
			
		||||
    {
 | 
			
		||||
        Disposed = true;
 | 
			
		||||
        VariableRuntimeDispatchService.UnSubscribe(Refresh);
 | 
			
		||||
        GC.SuppressFinalize(this);
 | 
			
		||||
        return base.DisposeAsync(disposing);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialized()
 | 
			
		||||
    {
 | 
			
		||||
        Localizer = App.CreateLocalizerByType(GetType());
 | 
			
		||||
        VariableRuntimeDispatchService.Subscribe(Refresh);
 | 
			
		||||
 | 
			
		||||
        scheduler = new SmartTriggerScheduler(Notify, TimeSpan.FromMilliseconds(1000));
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
export function init(id, invoke, options) {
 | 
			
		||||
    function getCellByClass(row, className) {
 | 
			
		||||
        // 直接用 querySelector 精确查找
 | 
			
		||||
        return row.querySelector(`td.${className}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var variableHandler = setInterval(async () => {
 | 
			
		||||
        var admintable = document.getElementById(id);
 | 
			
		||||
 | 
			
		||||
        var tables = admintable.getElementsByTagName('table');
 | 
			
		||||
 | 
			
		||||
        if (!tables || tables.length === 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var table = tables[tables.length - 1];
 | 
			
		||||
 | 
			
		||||
        if (!table) {
 | 
			
		||||
            clearInterval(variableHandler)
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        var rowCount = table.rows.length;
 | 
			
		||||
        var { method } = options;
 | 
			
		||||
 | 
			
		||||
        for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var row = table.rows[rowIndex];
 | 
			
		||||
            if (!row) continue;
 | 
			
		||||
 | 
			
		||||
            var vals = await invoke.invokeMethodAsync(method, rowIndex);
 | 
			
		||||
            if (vals == null) continue;
 | 
			
		||||
 | 
			
		||||
            for (let i = 0; i < vals.length; i++) {
 | 
			
		||||
                const cellName = vals[i].field;
 | 
			
		||||
                const cellValue = vals[i].value;
 | 
			
		||||
                if (cellValue == null) continue;
 | 
			
		||||
 | 
			
		||||
                var cell = getCellByClass(row, cellName)
 | 
			
		||||
 | 
			
		||||
                if (!cell) continue;
 | 
			
		||||
 | 
			
		||||
                // 查找 tooltip span
 | 
			
		||||
                var cellDiv = cell.querySelector('.table-cell');
 | 
			
		||||
                if (cellDiv) {
 | 
			
		||||
                    var tooltipSpan = cell.querySelector('.bb-tooltip');
 | 
			
		||||
                    if (tooltipSpan) {
 | 
			
		||||
 | 
			
		||||
                        tooltipSpan.innerText = cellValue ?? '';      // 更新显示文字
 | 
			
		||||
                        tooltipSpan.setAttribute('data-bs-original-title', cellValue ?? '');  // 同步 tooltip 提示
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        cellDiv.innerText = cellValue ?? '';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //// 查找 switch
 | 
			
		||||
                //var switchDiv = cell.querySelector('.switch');
 | 
			
		||||
                //if (switchDiv) {
 | 
			
		||||
                //    if (cellValue === true || cellValue === "on" || cellValue === "True" || cellValue === "true") {
 | 
			
		||||
                //        switchDiv.classList.add('is-checked');
 | 
			
		||||
                //        switchDiv.classList.add('enable');
 | 
			
		||||
                //        switchDiv.classList.remove('is-unchecked');
 | 
			
		||||
                //        switchDiv.classList.remove('disabled');
 | 
			
		||||
 | 
			
		||||
                //        switchDiv.querySelectorAll('span')[0].classList.add('border-success');
 | 
			
		||||
                //        switchDiv.querySelectorAll('span')[0].classList.add('bg-success');
 | 
			
		||||
 | 
			
		||||
                //    } else {
 | 
			
		||||
                //        switchDiv.classList.remove('is-checked');
 | 
			
		||||
                //        switchDiv.classList.remove('enable');
 | 
			
		||||
                //        switchDiv.classList.add('is-unchecked');
 | 
			
		||||
                //        switchDiv.classList.add('disabled');
 | 
			
		||||
 | 
			
		||||
                //        switchDiv.querySelectorAll('span')[0].classList.remove('border-success');
 | 
			
		||||
                //        switchDiv.querySelectorAll('span')[0].classList.remove('bg-success');
 | 
			
		||||
                //    }
 | 
			
		||||
                //    continue;
 | 
			
		||||
                //}
 | 
			
		||||
                //// 默认情况(普通单元格)
 | 
			
		||||
                //getCellByClass(row, cellName).innerText = cellValue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
        , 500) //1000ms刷新一次
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user