feat: 网关监控变量在线状态醒目显示

This commit is contained in:
2248356998 qq.com
2025-10-17 12:30:05 +08:00
parent 00c24d06a3
commit c26898b49d
6 changed files with 62 additions and 322 deletions

View File

@@ -11,7 +11,7 @@ namespace ThingsGateway.Gateway.Razor;
public static class VariableModelUtils public static class VariableModelUtils
{ {
static MemoryCache MemoryCache = new(); static MemoryCache MemoryCache = new();
public static object GetPropertyValue(VariableRuntime model, string fieldName) private static object GetPropertyValue(VariableRuntime model, string fieldName)
{ {
if (model == null) if (model == null)
{ {
@@ -31,6 +31,7 @@ public static class VariableModelUtils
return ret; return ret;
} }
} }
/// <summary> /// <summary>
/// 获取属性方法 Lambda 表达式 /// 获取属性方法 Lambda 表达式
/// </summary> /// </summary>
@@ -38,7 +39,7 @@ public static class VariableModelUtils
/// <typeparam name="TResult"></typeparam> /// <typeparam name="TResult"></typeparam>
/// <param name="propertyName"></param> /// <param name="propertyName"></param>
/// <returns></returns> /// <returns></returns>
public static Expression<Func<TModel, TResult>> GetPropertyValueLambda<TModel, TResult>(string propertyName) where TModel : class, new() private static Expression<Func<TModel, TResult>> GetPropertyValueLambda<TModel, TResult>(string propertyName) where TModel : class, new()
{ {
var type = typeof(TModel); var type = typeof(TModel);
@@ -99,26 +100,26 @@ public static class VariableModelUtils
switch (fieldName) switch (fieldName)
{ {
case nameof(VariableRuntime.Value): case nameof(VariableRuntime.Value):
return row.Value?.ToSystemTextJsonString(false) ?? string.Empty; return row.Value?.ToSystemTextJsonString(false) ?? string.Empty;
case nameof(VariableRuntime.RawValue): case nameof(VariableRuntime.RawValue):
return row.RawValue?.ToSystemTextJsonString(false) ?? string.Empty; return row.RawValue?.ToSystemTextJsonString(false) ?? string.Empty;
case nameof(VariableRuntime.LastSetValue): case nameof(VariableRuntime.LastSetValue):
return row.LastSetValue?.ToSystemTextJsonString(false) ?? string.Empty; return row.LastSetValue?.ToSystemTextJsonString(false) ?? string.Empty;
case nameof(VariableRuntime.ChangeTime): case nameof(VariableRuntime.ChangeTime):
return row.ChangeTime.ToString("dd-HH:mm:ss.fff"); return row.ChangeTime.ToString("MM-dd HH:mm:ss.fff");
case nameof(VariableRuntime.CollectTime): case nameof(VariableRuntime.CollectTime):
return row.CollectTime.ToString("dd-HH:mm:ss.fff"); return row.CollectTime.ToString("MM-dd HH:mm:ss.fff");
case nameof(VariableRuntime.IsOnline): case nameof(VariableRuntime.IsOnline):
return row.IsOnline.ToString(); return row.IsOnline ? "Online" : "Offline";
case nameof(VariableRuntime.LastErrorMessage): case nameof(VariableRuntime.LastErrorMessage):
return row.LastErrorMessage; return row.LastErrorMessage;
case nameof(VariableRuntime.RuntimeType): case nameof(VariableRuntime.RuntimeType):
return row.RuntimeType; return row.RuntimeType;
default: default:
var ret = VariableModelUtils.GetPropertyValue(row, fieldName); var ret = VariableModelUtils.GetPropertyValue(row, fieldName);
@@ -136,7 +137,7 @@ public static class VariableModelUtils
} }
} }
} }
return ret is string str ? str : ret?.ToString() ?? string.Empty; return ret is string str ? str : ret?.ToString() ?? string.Empty;
} }
} }

View File

@@ -1,26 +0,0 @@
@namespace ThingsGateway.Gateway.Razor
@using System.Text.Json.Nodes
@using Microsoft.Extensions.Hosting
@using ThingsGateway.Admin.Application
@using ThingsGateway.Admin.Razor
@using ThingsGateway.Gateway.Application
@inherits ComponentDefault
@foreach (var col in RowContent.Columns)
{
<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>
}

View File

@@ -1,249 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
namespace ThingsGateway.Gateway.Razor;
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 Task Refresh(object? state)
//{
// if (!Disposed)
// return InvokeAsync(StateHasChanged);
// else
// return Task.CompletedTask;
//}
protected override void OnParametersSet()
{
FixedCellClassStringCache?.Clear();
CellClassStringCache?.Clear();
base.OnParametersSet();
}
/// <summary>
/// 获得指定列头固定列样式
/// </summary>
/// <param name="col"></param>
/// <param name="margin"></param>
/// <returns></returns>
protected string? GetFixedCellStyleString(ITableColumn col, int margin = 0)
{
string? ret = null;
if (col.Fixed)
{
ret = IsTail(col) ? GetRightStyle(col, margin) : GetLeftStyle(col);
}
return ret;
}
private string? GetLeftStyle(ITableColumn col)
{
var columns = RowContent.Columns.ToList();
var defaultWidth = 200;
var width = 0;
var start = 0;
var index = columns.IndexOf(col);
//if (GetFixedDetailRowHeaderColumn)
//{
// width += DetailColumnWidth;
//}
//if (GetFixedMultipleSelectColumn)
//{
// width += MultiColumnWidth;
//}
if (GetFixedLineNoColumn)
{
width += LineNoColumnWidth;
}
while (index > start)
{
var column = columns[start++];
width += column.Width ?? defaultWidth;
}
return $"left: {width}px;";
}
private bool GetFixedLineNoColumn = false;
private string? GetRightStyle(ITableColumn col, int margin)
{
var columns = RowContent.Columns.ToList();
var defaultWidth = 200;
var width = 0;
var index = columns.IndexOf(col);
// after
while (index + 1 < columns.Count)
{
var column = columns[index++];
width += column.Width ?? defaultWidth;
}
//if (ShowExtendButtons && FixedExtendButtonsColumn)
{
width += ExtendButtonColumnWidth;
}
// 如果是固定表头时增加滚动条位置
if (IsFixedHeader && (index + 1) == columns.Count)
{
width += margin;
}
return $"right: {width}px;";
}
private bool IsFixedHeader = true;
public int LineNoColumnWidth { get; set; } = 60;
public int ExtendButtonColumnWidth { get; set; } = 220;
private bool IsTail(ITableColumn col)
{
var middle = Math.Floor(RowContent.Columns.Count() * 1.0 / 2);
var index = Columns.IndexOf(col);
return middle < index;
}
private NonBlockingDictionary<ITableColumn, string> CellClassStringCache { get; } = new(ReferenceEqualityComparer.Instance);
/// <summary>
/// 获得 Cell 文字样式
/// </summary>
/// <param name="col"></param>
/// <param name="hasChildren"></param>
/// <param name="inCell"></param>
/// <returns></returns>
protected string? GetCellClassString(ITableColumn col, bool hasChildren, bool inCell)
{
if (CellClassStringCache.TryGetValue(col, out var cached))
{
return cached;
}
else
{
bool trigger = false;
return CellClassStringCache.GetOrAdd(col, col => CssBuilder.Default("table-cell")
.AddClass(col.GetAlign().ToDescriptionString(), col.Align == Alignment.Center || col.Align == Alignment.Right)
.AddClass("is-wrap", col.GetTextWrap())
.AddClass("is-ellips", col.GetTextEllipsis())
.AddClass("is-tips", col.GetShowTips())
.AddClass("is-resizable", AllowResizing)
.AddClass("is-tree", IsTree && hasChildren)
.AddClass("is-incell", inCell)
.AddClass("is-dbcell", trigger)
.AddClass(col.CssClass)
.Build());
}
}
private bool AllowResizing = true;
private bool IsTree = false;
private NonBlockingDictionary<ITableColumn, string> FixedCellClassStringCache { get; } = new(ReferenceEqualityComparer.Instance);
/// <summary>
/// 获得指定列头固定列样式
/// </summary>
/// <param name="col"></param>
/// <returns></returns>
protected string? GetFixedCellClassString(ITableColumn col)
{
if (FixedCellClassStringCache.TryGetValue(col, out var cached))
{
return cached;
}
else
{
return FixedCellClassStringCache.GetOrAdd(col, col => CssBuilder.Default()
.AddClass("fixed", col.Fixed)
.AddClass("fixed-right", col.Fixed && IsTail(col))
.AddClass("fr", IsLastColumn(col))
.AddClass("fl", IsFirstColumn(col))
.Build());
}
}
[Parameter]
public Func<List<ITableColumn>> ColumnsFunc { get; set; }
public List<ITableColumn> Columns => ColumnsFunc();
private NonBlockingDictionary<ITableColumn, bool> LastFixedColumnCache { get; } = new(ReferenceEqualityComparer.Instance);
private bool IsLastColumn(ITableColumn col)
{
if (LastFixedColumnCache.TryGetValue(col, out var cached))
{
return cached;
}
else
{
return LastFixedColumnCache.GetOrAdd(col, col =>
{
var ret = false;
if (col.Fixed && !IsTail(col))
{
var index = Columns.IndexOf(col) + 1;
ret = index < Columns.Count && Columns[index].Fixed == false;
}
return ret;
});
}
}
private NonBlockingDictionary<ITableColumn, bool> FirstFixedColumnCache { get; } = new(ReferenceEqualityComparer.Instance);
private bool IsFirstColumn(ITableColumn col)
{
if (FirstFixedColumnCache.TryGetValue(col, out var cached))
{
return cached;
}
else
{
return FirstFixedColumnCache.GetOrAdd(col, col =>
{
var ret = false;
if (col.Fixed && IsTail(col))
{
// 查找前一列是否固定
var index = Columns.IndexOf(col) - 1;
if (index > 0)
{
ret = !Columns[index].Fixed;
}
}
return ret;
});
}
}
}

View File

@@ -97,16 +97,20 @@
@foreach (var col in context.Columns) @foreach (var col in context.Columns)
{ {
<td class="@GetFixedCellClassString(col, context)" style="@GetFixedCellStyleString(col, context)" @key=col> <td class="@GetFixedCellClassString(col, context)" style="@GetFixedCellStyleString(col, context)" @key=col>
<div class="@GetCellClassString(col, false, false)" @key=col> @{
var name = col.GetFieldName();
var data = VariableModelUtils.GetValue(context.Row, name);
}
<div class="@GetCellClassString(col, data, false, false)" @key=col>
@if (col.GetShowTips()) @if (col.GetShowTips())
{ {
<Tooltip @key=col Title="@VariableModelUtils.GetValue(context.Row, col.GetFieldName())" class="text-truncate d-block"> <Tooltip @key=col Title="@VariableModelUtils.GetValue(context.Row, name)" class="text-truncate d-block">
@VariableModelUtils.GetValue(context.Row, col.GetFieldName()) @data
</Tooltip> </Tooltip>
} }
else else
{ {
@VariableModelUtils.GetValue(context.Row, col.GetFieldName()) @data
} }
</div> </div>
</td> </td>

View File

@@ -71,7 +71,7 @@ public partial class VariableRuntimeInfo
string? ret = null; string? ret = null;
if (col.Fixed) if (col.Fixed)
{ {
ret = IsTail(col,row) ? GetRightStyle(col,row, margin) : GetLeftStyle(col, row); ret = IsTail(col, row) ? GetRightStyle(col, row, margin) : GetLeftStyle(col, row);
} }
return ret; return ret;
} }
@@ -135,7 +135,7 @@ public partial class VariableRuntimeInfo
public int ExtendButtonColumnWidth { get; set; } = 220; public int ExtendButtonColumnWidth { get; set; } = 220;
private bool IsTail(ITableColumn col,TableRowContext<VariableRuntime> row) private bool IsTail(ITableColumn col, TableRowContext<VariableRuntime> row)
{ {
var middle = Math.Floor(row.Columns.Count() * 1.0 / 2); var middle = Math.Floor(row.Columns.Count() * 1.0 / 2);
var index = Columns.IndexOf(col); var index = Columns.IndexOf(col);
@@ -145,16 +145,13 @@ public partial class VariableRuntimeInfo
/// <summary> /// <summary>
/// 获得 Cell 文字样式 /// 获得 Cell 文字样式
/// </summary> /// </summary>
/// <param name="col"></param> protected string? GetCellClassString(ITableColumn col, string data, bool hasChildren, bool inCell)
/// <param name="hasChildren"></param>
/// <param name="inCell"></param>
/// <returns></returns>
protected string? GetCellClassString(ITableColumn col, bool hasChildren, bool inCell)
{ {
bool trigger = false;
bool trigger = false;
return CssBuilder.Default("table-cell") return CssBuilder.Default("table-cell")
.AddClass(col.GetAlign().ToDescriptionString(), col.Align == Alignment.Center || col.Align == Alignment.Right) .AddClass(col.GetAlign().ToDescriptionString(), col.Align == Alignment.Center || col.Align == Alignment.Right)
.AddClass("green--text", data == "Online")
.AddClass("red--text", data == "Offline")
.AddClass("is-wrap", col.GetTextWrap()) .AddClass("is-wrap", col.GetTextWrap())
.AddClass("is-ellips", col.GetTextEllipsis()) .AddClass("is-ellips", col.GetTextEllipsis())
.AddClass("is-tips", col.GetShowTips()) .AddClass("is-tips", col.GetShowTips())
@@ -177,46 +174,46 @@ public partial class VariableRuntimeInfo
{ {
return CssBuilder.Default() return CssBuilder.Default()
.AddClass("fixed", col.Fixed) .AddClass("fixed", col.Fixed)
.AddClass("fixed-right", col.Fixed && IsTail(col,row)) .AddClass("fixed-right", col.Fixed && IsTail(col, row))
.AddClass("fr", IsLastColumn(col, row)) .AddClass("fr", IsLastColumn(col, row))
.AddClass("fl", IsFirstColumn(col, row)) .AddClass("fl", IsFirstColumn(col, row))
.Build(); .Build();
} }
public List<ITableColumn> Columns=> table?.Columns; public List<ITableColumn> Columns => table?.Columns;
private bool IsLastColumn(ITableColumn col, TableRowContext<VariableRuntime> row) private bool IsLastColumn(ITableColumn col, TableRowContext<VariableRuntime> row)
{ {
var ret = false; var ret = false;
if (col.Fixed && !IsTail(col, row)) if (col.Fixed && !IsTail(col, row))
{ {
var index = Columns.IndexOf(col) + 1; var index = Columns.IndexOf(col) + 1;
ret = index < Columns.Count && Columns[index].Fixed == false; ret = index < Columns.Count && Columns[index].Fixed == false;
} }
return ret; return ret;
} }
private bool IsFirstColumn(ITableColumn col, TableRowContext<VariableRuntime> row) private bool IsFirstColumn(ITableColumn col, TableRowContext<VariableRuntime> row)
{ {
var ret = false; var ret = false;
if (col.Fixed && IsTail(col, row)) if (col.Fixed && IsTail(col, row))
{ {
// 查找前一列是否固定 // 查找前一列是否固定
var index = Columns.IndexOf(col) - 1; var index = Columns.IndexOf(col) - 1;
if (index > 0) if (index > 0)
{ {
ret = !Columns[index].Fixed; ret = !Columns[index].Fixed;
} }
} }
return ret; return ret;
} }
#endregion #endregion
#region js #region js
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new { Method = nameof(TriggerStateChanged) }); protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new { Method = nameof(TriggerStateChanged) });
private Task OnColumnVisibleChanged(string name, bool visible) private Task OnColumnVisibleChanged(string name, bool visible)

View File

@@ -72,6 +72,19 @@ export function init(id, invoke, options) {
cellDiv.innerText = cellValue ?? ''; cellDiv.innerText = cellValue ?? '';
} }
} }
if (cellValue == "Online") {
cellDiv.classList.remove('red--text');
cellDiv.classList.add('green--text');
}
else if (cellValue == "Offline") {
cellDiv.classList.remove('green--text');
cellDiv.classList.add('red--text');
}
else {
cellDiv.classList.remove('red--text');
cellDiv.classList.remove('green--text');
}
} }
//// 查找 switch //// 查找 switch