build: 10.11.100
feat(VariablePage): 优化UI性能
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
DoubleClickToEdit="DoubleClickToEdit"
|
||||
OnDoubleClickCellCallback="OnDoubleClickCellCallback"
|
||||
OnDoubleClickRowCallback="OnDoubleClickRowCallback"
|
||||
RowContentTemplate="RowContentTemplate"
|
||||
OnClickRowCallback="OnClickRowCallback">
|
||||
</Table>
|
||||
</div>
|
||||
|
@@ -13,6 +13,10 @@ namespace ThingsGateway.Admin.Razor;
|
||||
[CascadingTypeParameter(nameof(TItem))]
|
||||
public partial class AdminTable<TItem> where TItem : class, new()
|
||||
{
|
||||
|
||||
public List<ITableColumn> Columns => Instance?.Columns;
|
||||
|
||||
|
||||
/// <inheritdoc cref="Table{TItem}.SelectedRowsChanged"/>
|
||||
[Parameter]
|
||||
public EventCallback<List<TItem>> SelectedRowsChanged { get; set; }
|
||||
@@ -40,6 +44,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; }
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<PluginVersion>10.11.99</PluginVersion>
|
||||
<ProPluginVersion>10.11.99</ProPluginVersion>
|
||||
<DefaultVersion>10.11.99</DefaultVersion>
|
||||
<PluginVersion>10.11.100</PluginVersion>
|
||||
<ProPluginVersion>10.11.100</ProPluginVersion>
|
||||
<DefaultVersion>10.11.100</DefaultVersion>
|
||||
<AuthenticationVersion>10.11.6</AuthenticationVersion>
|
||||
<SourceGeneratorVersion>10.11.6</SourceGeneratorVersion>
|
||||
<NET8Version>8.0.20</NET8Version>
|
||||
|
@@ -0,0 +1,26 @@
|
||||
@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
|
||||
@typeparam TItem
|
||||
|
||||
|
||||
@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)">
|
||||
@{
|
||||
<DynamicElement TagName="div" TriggerDoubleClick="false" GenerateElement="false"
|
||||
StopPropagation="true"
|
||||
class="@GetDoubleClickCellClassString(false)">
|
||||
@GetValue(col, RowContent.Row)
|
||||
</DynamicElement>
|
||||
}
|
||||
</DynamicElement>
|
||||
</td>
|
||||
}
|
@@ -0,0 +1,226 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://thingsgateway.cn/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.NewLife.Threading;
|
||||
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace ThingsGateway.Gateway.Razor;
|
||||
|
||||
public partial class VariableRow<TItem> : IDisposable
|
||||
{
|
||||
[Parameter]
|
||||
public TableRowContext<TItem>? RowContent { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
timer?.SafeDispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
TimerX? timer;
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
timer = new TimerX(Refresh, null, 1000, 1000, "VariableRow");
|
||||
base.OnInitialized();
|
||||
}
|
||||
private Task Refresh(object? state)
|
||||
{
|
||||
return InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
FixedCellClassStringCache?.Clear();
|
||||
CellClassStringCache?.Clear();
|
||||
base.OnParametersSet();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获得 指定单元格数据方法
|
||||
/// </summary>
|
||||
/// <param name="col"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
protected RenderFragment GetValue(ITableColumn col, TItem 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>
|
||||
/// 获得指定列头固定列样式
|
||||
/// </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 ConcurrentDictionary<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) => 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(col.CssClass)
|
||||
.Build());
|
||||
|
||||
private bool AllowResizing = true;
|
||||
private bool IsTree = false;
|
||||
|
||||
private ConcurrentDictionary<ITableColumn, string> FixedCellClassStringCache { get; } = new(ReferenceEqualityComparer.Instance);
|
||||
/// <summary>
|
||||
/// 获得指定列头固定列样式
|
||||
/// </summary>
|
||||
/// <param name="col"></param>
|
||||
/// <returns></returns>
|
||||
protected string? GetFixedCellClassString(ITableColumn col) => 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 ConcurrentDictionary<ITableColumn, bool> LastFixedColumnCache { get; } = new(ReferenceEqualityComparer.Instance);
|
||||
private bool IsLastColumn(ITableColumn col) => 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 ConcurrentDictionary<ITableColumn, bool> FirstFixedColumnCache { get; } = new(ReferenceEqualityComparer.Instance);
|
||||
private bool IsFirstColumn(ITableColumn col) => 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;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人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;
|
||||
|
||||
}
|
@@ -20,8 +20,7 @@
|
||||
ShowExtendButtons=true
|
||||
ShowToolbar="true"
|
||||
ShowExportButton
|
||||
IsAutoRefresh
|
||||
AutoRefreshInterval="1000"
|
||||
|
||||
ShowDefaultButtons=true
|
||||
ShowSearch=false
|
||||
ExtendButtonColumnWidth=220
|
||||
@@ -85,6 +84,11 @@
|
||||
<VariableEditComponent Model=@(context) AutoRestartThread="AutoRestartThread"></VariableEditComponent>
|
||||
</EditTemplate>
|
||||
|
||||
<RowContentTemplate Context="context">
|
||||
|
||||
<VariableRow RowContent="@context" ColumnsFunc="ColumnsFunc"></VariableRow>
|
||||
|
||||
</RowContentTemplate>
|
||||
|
||||
<ExportButtonDropdownTemplate Context="ExportContext">
|
||||
@if ((AuthorizeButton("导出")))
|
||||
|
@@ -15,13 +15,17 @@ using ThingsGateway.Admin.Application;
|
||||
using ThingsGateway.Admin.Razor;
|
||||
using ThingsGateway.DB;
|
||||
using ThingsGateway.Extension.Generic;
|
||||
using ThingsGateway.NewLife.Extension;
|
||||
using ThingsGateway.NewLife.Json.Extension;
|
||||
|
||||
namespace ThingsGateway.Gateway.Razor;
|
||||
|
||||
public partial class VariableRuntimeInfo : IDisposable
|
||||
{
|
||||
public List<ITableColumn> ColumnsFunc()
|
||||
{
|
||||
return table?.Columns;
|
||||
}
|
||||
|
||||
#if !Management
|
||||
[Parameter]
|
||||
public ChannelDeviceTreeItem SelectModel { get; set; }
|
||||
@@ -84,6 +88,12 @@ public partial class VariableRuntimeInfo : IDisposable
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
scheduler?.Trigger();
|
||||
}
|
||||
|
||||
private async Task Notify(CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return;
|
||||
|
Reference in New Issue
Block a user