mirror of
https://gitee.com/blazorcomponent/MASA.Blazor.git
synced 2025-12-06 10:19:23 +08:00
feat(templatetable): update ui classes and query for table (#2549)
* feat:添加参数控制部分功能显示和内部显示样式;支持表格自定义列展示;修复cubejs模式下的查询排序条件拼接和解析问题 * feat: update custom cols render
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
namespace Masa.Blazor.Components.TemplateTable.Contracts;
|
||||
|
||||
public static class TemplateTableEnumTypeConvert
|
||||
{
|
||||
public static ExpectedType ConvertToExpectedType(this ColumnType columnType)
|
||||
{
|
||||
return columnType switch
|
||||
{
|
||||
ColumnType.Date => ExpectedType.DateTime,
|
||||
ColumnType.Progress => ExpectedType.Float,
|
||||
ColumnType.Number => ExpectedType.Float,
|
||||
ColumnType.Rating => ExpectedType.Float,
|
||||
ColumnType.Switch => ExpectedType.Boolean,
|
||||
ColumnType.Checkbox => ExpectedType.Boolean,
|
||||
ColumnType.RowSelect => ExpectedType.Boolean,
|
||||
_ => ExpectedType.String,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using GraphQL;
|
||||
using GraphQL;
|
||||
using GraphQL.Client.Abstractions.Utilities;
|
||||
using GraphQL.Client.Http;
|
||||
using Masa.Blazor.Components.TemplateTable.Abstractions;
|
||||
using Masa.Blazor.Components.TemplateTable.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GraphQLClient = GraphQL.Client.Abstractions.IGraphQLClient;
|
||||
|
||||
[assembly: InternalsVisibleTo("Masa.Blazor.Components.TemplateTable.Test")]
|
||||
|
||||
namespace Masa.Blazor.Components.TemplateTable.Cubejs.GraphQL;
|
||||
|
||||
public class CubejsGraphQLClient(GraphQLHttpClient httpClient) : IGraphQLClient
|
||||
public class CubejsGraphQLClient(GraphQLClient httpClient) : IGraphQLClient
|
||||
{
|
||||
public async Task<QueryResult> QueryAsync(QueryRequest request)
|
||||
{
|
||||
@@ -187,6 +187,11 @@ public class CubejsGraphQLClient(GraphQLHttpClient httpClient) : IGraphQLClient
|
||||
expected = "false";
|
||||
type = ExpectedType.Boolean;
|
||||
break;
|
||||
case StandardFilter.Set:
|
||||
filter = CubejsFilter.Set;
|
||||
expected = "true";
|
||||
type = ExpectedType.Boolean;
|
||||
break;
|
||||
case StandardFilter.True:
|
||||
filter = CubejsFilter.Equals;
|
||||
expected = "true";
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
input = @<NumberConfigInput Value="@_column.Config" OnUpdate="HandleOnConfigUpdate"/>;
|
||||
break;
|
||||
case ColumnType.Link:
|
||||
input = @<LInkConfigInput Value="@_column.Config" OnUpdate="HandleOnConfigUpdate"/>;
|
||||
input = @<LinkConfigInput Value="@_column.Config" OnUpdate="HandleOnConfigUpdate"/>;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Masa.Blazor.Components.TemplateTable;
|
||||
|
||||
public record CustomCellContext(string ColumnId, JsonElement Value, IReadOnlyDictionary<string, JsonElement> Data);
|
||||
public record CustomCellContext(string ColumnId, JsonElement Value, IReadOnlyDictionary<string, JsonElement> Data, RenderFragment @Default);
|
||||
@@ -5,14 +5,60 @@ public static class IReadOnlyDictionaryExtensions
|
||||
public static bool TryGetValueWithCaseInsensitiveKey(this IReadOnlyDictionary<string, JsonElement> dict, string key,
|
||||
out string? value)
|
||||
{
|
||||
var k = dict.Keys.FirstOrDefault(u => u.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
if (k == null)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = dict[k].GetString();
|
||||
if (!key.Contains('.'))
|
||||
{
|
||||
var k = dict.Keys.FirstOrDefault(u => u.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (k == null)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = dict[k].GetString();
|
||||
}
|
||||
else
|
||||
{
|
||||
value = GetNestedValue(dict, key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string? GetNestedValue(IReadOnlyDictionary<string, JsonElement> dict, string key)
|
||||
{
|
||||
var parts = key.Split('.');
|
||||
var index = 0;
|
||||
JsonElement? temp = null;
|
||||
do
|
||||
{
|
||||
string? k;
|
||||
if (temp.HasValue)
|
||||
{
|
||||
(k, temp) = GetObjectValue(parts[index], temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
k = dict.Keys.FirstOrDefault(u => u.Equals(parts[index], StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.IsNullOrEmpty(k))
|
||||
temp = dict[k];
|
||||
}
|
||||
if (k == null)
|
||||
return null;
|
||||
index++;
|
||||
}
|
||||
while (parts.Length - index > 0);
|
||||
return temp?.GetString();
|
||||
}
|
||||
|
||||
private static (string?, JsonElement?) GetObjectValue(string key, JsonElement? value)
|
||||
{
|
||||
if (value == null || value.Value.ValueKind != JsonValueKind.Object)
|
||||
return (null, null);
|
||||
|
||||
var item = value.Value.EnumerateObject()
|
||||
.FirstOrDefault(i => i.Name.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return item.Name != null ? (item.Name, item.Value) : (null, null);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,27 @@
|
||||
@namespace Masa.Blazor.Components.TemplateTable.FilterDialogs
|
||||
@inject I18n i18N;
|
||||
|
||||
<PModal @bind-Value="dialog"
|
||||
Width="668"
|
||||
<PModal @bind-Value="Show"
|
||||
Width="@Width"
|
||||
BodyStyle="min-height: 180px"
|
||||
Title="Filters"
|
||||
Title="@i18N.T("Filters")"
|
||||
Persistent
|
||||
OnCancel="@HandleOnCancel"
|
||||
OnSave="HandleOnSave">
|
||||
|
||||
@for (int i = 0; i < _filters.Count; i++)
|
||||
{
|
||||
var index = i;
|
||||
var filter = _filters[index];
|
||||
|
||||
if (filter.Persistent) continue;
|
||||
<div class="d-flex align-center mb-2">
|
||||
<div style="width: 86px; flex: none;"
|
||||
class="mr-2 text-right">
|
||||
@if (index == 0)
|
||||
{
|
||||
<span>When</span>
|
||||
<span>@i18N.T("When")</span>
|
||||
}
|
||||
else if (index == 1)
|
||||
@* else if (index == 1)
|
||||
{
|
||||
<MSelect @bind-Value="@_operator"
|
||||
Items="@Operators"
|
||||
@@ -30,18 +32,19 @@
|
||||
Outlined
|
||||
HideDetails="@true">
|
||||
</MSelect>
|
||||
}
|
||||
} *@
|
||||
else
|
||||
{
|
||||
<span>@_operator</span>
|
||||
<span>@i18N.T(@_operator)</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<MSelect @bind-Value="@filter.ColumnId"
|
||||
Placeholder="@i18N.T("ColumnId")"
|
||||
Items="_computedColumns"
|
||||
ItemText="u => u.Name"
|
||||
ItemValue="u => u.Id"
|
||||
Label="Field"
|
||||
Label="@i18N.T("ColumnId")"
|
||||
TItem="ColumnInfo"
|
||||
TItemValue="string"
|
||||
TValue="string"
|
||||
@@ -50,65 +53,92 @@
|
||||
Dense
|
||||
Filled
|
||||
HideDetails="@true"
|
||||
Readonly="filter.Persistent"
|
||||
OnSelect="@filter.OnSelect">
|
||||
</MSelect>
|
||||
<MSelect @bind-Value="@filter.Func"
|
||||
<MSelect @bind-Value="@filter.Func" Placeholder="@i18N.T("Func")"
|
||||
Items="@filter.FuncList"
|
||||
ItemText="u => u.ToString()"
|
||||
ItemText="@(u => i18N.T($"SDF_{u}"))"
|
||||
ItemValue="u => u"
|
||||
Label="Func"
|
||||
Label="@i18N.T("Func")"
|
||||
Class="mr-2"
|
||||
Style="max-width: 150px"
|
||||
Dense
|
||||
Filled
|
||||
Readonly="filter.Persistent"
|
||||
HideDetails="@true">
|
||||
</MSelect>
|
||||
@if ((filter.Func is StandardFilter.Equals or StandardFilter.NotEquals) && filter.SelectOptions is not null)
|
||||
@if ((filter.Func is StandardFilter.Equals or StandardFilter.NotEquals or StandardFilter.Contains or StandardFilter.NotContains) && filter.SelectOptions is not null)
|
||||
{
|
||||
<MSelect @bind-Value="@filter.Expected"
|
||||
Items="@filter.SelectOptions"
|
||||
ItemText="u => u.Label"
|
||||
ItemValue="u => u.Value"
|
||||
Label="Expected"
|
||||
Class="mr-2"
|
||||
Style="max-width: 150px"
|
||||
Dense
|
||||
Filled
|
||||
HideDetails="@true">
|
||||
</MSelect>
|
||||
}
|
||||
else if (!_noExpectedFuncs.Contains(filter.Func))
|
||||
{
|
||||
if (filter.Type == ExpectedType.DateTime)
|
||||
bool isList = filter.Func is StandardFilter.Contains or StandardFilter.NotContains;
|
||||
if (isList)
|
||||
{
|
||||
DateTime? date = DateTime.TryParse(filter.Expected, out var dt) ? dt : null;
|
||||
|
||||
<PDateDigitalClockPicker Value="@date"
|
||||
ValueChanged="@(v => filter.Expected = (v.ToString() ?? string.Empty))"
|
||||
TValue="DateTime?"
|
||||
ViewType="DateTimePickerViewType.Desktop"
|
||||
TimeFormat="TimeFormat.Hr24"
|
||||
MultiSection
|
||||
UseSeconds>
|
||||
<PDefaultDateTimePickerActivator Label="Expected"
|
||||
Filled
|
||||
Format="yyyy-MM-dd HH:mm:ss"/>
|
||||
</PDateDigitalClockPicker>
|
||||
List<string> values = [.. filter.Expected.Replace('[', ' ').Replace(']', ' ').Replace('"', ' ').Split(',').Select(s => s.Trim())];
|
||||
<MAutocomplete Value="values"
|
||||
ValueChanged="(List<string> values) => ValueChange(index, values)"
|
||||
Clearable
|
||||
Multiple
|
||||
Items="@filter.SelectOptions"
|
||||
ItemText="u => u.Label"
|
||||
ItemValue="u => u.Value"
|
||||
Label="@i18N.T("Expected")"
|
||||
Placeholder="@i18N.T("Expected")"
|
||||
Color="primary"
|
||||
Class="mr-2 m-input--dense-48"
|
||||
Style="max-width: 150px"
|
||||
Dense
|
||||
Filled
|
||||
Readonly="filter.Persistent"
|
||||
HideDetails="@("auto")">
|
||||
</MAutocomplete>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MTextField @bind-Value="@filter.Expected"
|
||||
Label="Expected"
|
||||
Class="mr-2"
|
||||
Style="max-width: 150px"
|
||||
Filled
|
||||
Dense
|
||||
HideDetails="@true">
|
||||
</MTextField>
|
||||
<MAutocomplete @bind-Value="@filter.Expected"
|
||||
Placeholder="@i18N.T("Expected")"
|
||||
Items="@filter.SelectOptions"
|
||||
ItemText="u => u.Label"
|
||||
ItemValue="u => u.Value"
|
||||
Label="@i18N.T("Expected")"
|
||||
Class="mr-2 m-input--dense-48"
|
||||
Style="max-width: 150px"
|
||||
Dense
|
||||
Filled
|
||||
Readonly="filter.Persistent"
|
||||
HideDetails="@("auto")">
|
||||
</MAutocomplete>
|
||||
}
|
||||
}
|
||||
else if (filter.Type == ExpectedType.DateTime && (filter.Func is not StandardFilter.Set && filter.Func is not StandardFilter.NotSet))
|
||||
{
|
||||
DateTime? date = DateTime.TryParse(filter.Expected, out var dt) ? dt : null;
|
||||
<PDateDigitalClockPicker Value="@date"
|
||||
ValueChanged="@(v => filter.Expected = (v.ToString() ?? string.Empty))"
|
||||
TValue="DateTime?"
|
||||
ViewType="DateTimePickerViewType.Desktop"
|
||||
TimeFormat="TimeFormat.Hr24"
|
||||
MultiSection
|
||||
UseSeconds>
|
||||
<PDefaultDateTimePickerActivator Label="Expected"
|
||||
Filled
|
||||
Format="yyyy-MM-dd HH:mm:ss" />
|
||||
</PDateDigitalClockPicker>
|
||||
}
|
||||
else if (!_noExpectedFuncs.Contains(filter.Func))
|
||||
{
|
||||
<MTextField @bind-Value="@filter.Expected"
|
||||
Placeholder="@i18N.T("Expected")"
|
||||
Readonly="filter.Persistent"
|
||||
Label="@i18N.T("Expected")"
|
||||
Class="mr-2 m-input--dense-48"
|
||||
Style="max-width: 150px"
|
||||
Filled
|
||||
Dense
|
||||
HideDetails="@("auto")">
|
||||
</MTextField>
|
||||
}
|
||||
|
||||
<MSpacer/>
|
||||
<MSpacer />
|
||||
|
||||
@if (filter.Persistent)
|
||||
{
|
||||
@@ -127,9 +157,7 @@
|
||||
<MButton Text
|
||||
LeftIconName="mdi-plus"
|
||||
Color="primary"
|
||||
OnClick="@AddNewFilter">
|
||||
Add filter
|
||||
</MButton>
|
||||
OnClick="@AddNewFilter">@i18N.T("Add")</MButton>
|
||||
</div>
|
||||
</PModal>
|
||||
|
||||
@@ -138,6 +166,7 @@
|
||||
[Parameter] public IList<ColumnInfo> Columns { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Use this to filter out hidden columns when selecting columns.
|
||||
/// </summary>
|
||||
[Parameter] public HashSet<string> HiddenColumnIds { get; set; } = [];
|
||||
@@ -146,6 +175,16 @@
|
||||
|
||||
[Parameter] public EventCallback<Filter> OnSave { get; set; }
|
||||
|
||||
[Parameter] public Filter Filter { get; set; } = new();
|
||||
|
||||
[Parameter] public EventCallback<Filter> FilterChanged { get; set; }
|
||||
|
||||
[Parameter] public StringNumber Width { get; set; } = 720;
|
||||
|
||||
[Parameter] public bool Show { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<bool> ShowChanged { get; set; }
|
||||
|
||||
private static readonly IList<string> Operators = ["and", "or"];
|
||||
|
||||
private static readonly HashSet<StandardFilter> _noExpectedFuncs =
|
||||
@@ -179,7 +218,9 @@
|
||||
_filters.Clear();
|
||||
foreach (var option in ActiveView.Filter.Options)
|
||||
{
|
||||
var column = Columns.FirstOrDefault(u => u.Id == option.ColumnId);
|
||||
var columnName = option.ColumnId;
|
||||
var column = Columns.FirstOrDefault(u => u.Id == option.ColumnId || option.Type == ExpectedType.DateTime && u.Id.StartsWith(option.ColumnId));
|
||||
|
||||
if (column is null)
|
||||
{
|
||||
continue;
|
||||
@@ -199,13 +240,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
private bool dialog;
|
||||
|
||||
private readonly List<FilterModel> _filters = [];
|
||||
|
||||
internal void Open()
|
||||
{
|
||||
dialog = true;
|
||||
Show = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -216,7 +255,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var filter = new FilterModel(Columns.First());
|
||||
var filter = new FilterModel(Columns[0]);
|
||||
|
||||
_filters.Add(filter);
|
||||
}
|
||||
@@ -236,17 +275,38 @@
|
||||
filter.Expected = "{ in: [" + string.Join(", ", filter.MultiSelect.Select(u => $"\"{u}\"")) + "]}";
|
||||
}
|
||||
|
||||
private void HandleOnSave()
|
||||
private async Task HandleOnSave()
|
||||
{
|
||||
dialog = false;
|
||||
await HandleOnCancel();
|
||||
|
||||
var request = new Filter
|
||||
Filter.Options = _filters.Select(u =>
|
||||
{
|
||||
Options = _filters.Select(u => u.ToFilterOption()).ToList(),
|
||||
Operator = _operator == "and" ? FilterOperator.And : FilterOperator.Or
|
||||
};
|
||||
u.UpdateType();
|
||||
return u.ToFilterOption();
|
||||
}).ToList();
|
||||
Filter.Operator = _operator == "and" ? FilterOperator.And : FilterOperator.Or;
|
||||
|
||||
OnSave.InvokeAsync(request);
|
||||
if (FilterChanged.HasDelegate)
|
||||
await FilterChanged.InvokeAsync(Filter);
|
||||
}
|
||||
|
||||
private async Task HandleOnCancel()
|
||||
{
|
||||
Show = false;
|
||||
if (ShowChanged.HasDelegate)
|
||||
await ShowChanged.InvokeAsync(Show);
|
||||
}
|
||||
|
||||
private void TimeChange(int index, DateTime time)
|
||||
{
|
||||
var filter = _filters[index];
|
||||
filter.Expected = time.ToString();
|
||||
}
|
||||
|
||||
private void ValueChange(int index, List<string> values)
|
||||
{
|
||||
var filter = _filters[index];
|
||||
var tt = $"[\"{string.Join(""",""", values)}\"]";
|
||||
filter.Expected = values.Count == 0 ? "[]" : tt;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ public class FilterModel : FilterOption
|
||||
{
|
||||
Column = column;
|
||||
ColumnId = column.Id;
|
||||
|
||||
UpdateOperator();
|
||||
}
|
||||
|
||||
@@ -61,7 +60,7 @@ public class FilterModel : FilterOption
|
||||
case ColumnType.Select:
|
||||
FuncList = SupportedFilter.SupportedSelectFilters;
|
||||
Func = FuncList[0];
|
||||
Type = ExpectedType.String;
|
||||
Type = Func == StandardFilter.Contains || Func == StandardFilter.NotContains ? ExpectedType.Expression : ExpectedType.String;
|
||||
SelectOptions = (Column.ConfigObject as SelectConfig)?.Options;
|
||||
break;
|
||||
case ColumnType.Date:
|
||||
@@ -71,4 +70,22 @@ public class FilterModel : FilterOption
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateType()
|
||||
{
|
||||
if (Type == ExpectedType.Expression)
|
||||
{
|
||||
if (Func is StandardFilter.Contains or StandardFilter.NotContains)
|
||||
return;
|
||||
|
||||
Type = ExpectedType.String;
|
||||
}
|
||||
else if (Func is StandardFilter.Contains or StandardFilter.NotContains)
|
||||
{
|
||||
if (Type == ExpectedType.Expression)
|
||||
return;
|
||||
|
||||
Type = ExpectedType.Expression;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ public static class SupportedFilter
|
||||
|
||||
public static readonly StandardFilter[] SupportedSelectFilters =
|
||||
[
|
||||
StandardFilter.Contains,
|
||||
StandardFilter.NotContains,
|
||||
StandardFilter.Equals,
|
||||
StandardFilter.NotEquals,
|
||||
StandardFilter.Set,
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
{
|
||||
<div class="m-template-table">
|
||||
<Toolbar DefaultViewId="@_sheet.DefaultViewId"
|
||||
ShowToolbar="@ShowToolbar"
|
||||
ShowToolbarActions="@ShowToolbarActions"
|
||||
ShowToolbarViews="@ShowToolbarViews"
|
||||
Role="@Role"
|
||||
ActiveView="@_sheet.ActiveViewId"
|
||||
ActiveViewChanged="@HandleOnActiveViewChanged"
|
||||
@@ -49,14 +52,20 @@
|
||||
OnSortClick="@(() => _sortDialog?.Open())"
|
||||
OnRowRemove="@Remove"
|
||||
OnSearch="@Search"
|
||||
OnSave="@SaveSheet"/>
|
||||
OnSave="@SaveSheet" />
|
||||
|
||||
<Viewer ViewColumns="@_sheet.ActiveView.Columns"
|
||||
HiddenColumnIds="@_sheet.ActiveViewHiddenColumnIds"
|
||||
ColumnOrder="@_sheet.ActiveView.Order"
|
||||
ColumnOrderChanged="@HandleOnColumnOrderChanged"
|
||||
Editable="@Editable"
|
||||
Class="@TableClass"
|
||||
Loading="@_loading"
|
||||
TableStripeClass="@StripeClass"
|
||||
TableBodyTdClass="@BodyTdClass"
|
||||
TableBodyTrClass="@BodyTrClass"
|
||||
TableHeaderThClass="@HeaderThClass"
|
||||
TableHeaderClass="@HeaderClass"
|
||||
RowHeight="@_rowHeight"
|
||||
Rows="@_rows"
|
||||
Sort="@_sheet.ActiveView.Value.Sort"
|
||||
@@ -98,21 +107,26 @@
|
||||
</ColumnDialog>
|
||||
|
||||
<FilterDialog @ref="_filterDialog"
|
||||
Show=ShowFilter
|
||||
ShowChanged="ShowFilterChanged"
|
||||
ActiveView="@_sheet.ActiveView.Value"
|
||||
Columns="@_sheet.Columns"
|
||||
OnSave="@SaveFilter">
|
||||
Filter=" _sheet!.ActiveView.Value.Filter"
|
||||
FilterChanged="SaveFilter">
|
||||
</FilterDialog>
|
||||
|
||||
<SortDialog @ref="_sortDialog"
|
||||
Show=ShowSort
|
||||
ShowChanged="ShowSortChanged"
|
||||
ActiveView="@_sheet.ActiveView.Value"
|
||||
Columns="@_sheet.Columns"
|
||||
HiddenColumnIds="@_sheet.ActiveViewHiddenColumnIds"
|
||||
OnSave="@SortUpdate">
|
||||
</SortDialog>
|
||||
|
||||
<ImageViewer @ref="_imageViewer"/>
|
||||
<ImageViewer @ref="_imageViewer" />
|
||||
|
||||
<DetailDialog @ref="_detailDialog" OnImagePreview="@OpenImageViewer"/>
|
||||
<DetailDialog @ref="_detailDialog" OnImagePreview="@OpenImageViewer" />
|
||||
|
||||
</div>
|
||||
}
|
||||
@@ -191,11 +205,12 @@
|
||||
EnsureActiveViewActionsColumnWidthCorrectly();
|
||||
|
||||
ResetSheet();
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task ResetView()
|
||||
{
|
||||
foreach (var column in _sheet.ActiveView.Columns.Where(u => !Preset.InternalColumnIds.Contains(u.ColumnId)))
|
||||
foreach (var column in _sheet!.ActiveView.Columns.Where(u => !Preset.InternalColumnIds.Contains(u.ColumnId)))
|
||||
{
|
||||
column.Hidden = false;
|
||||
column.Width = 0;
|
||||
@@ -251,7 +266,7 @@
|
||||
|
||||
if (_sheet.ActiveViewId == view.Value.Id)
|
||||
{
|
||||
_sheet.SetActiveView(_sheet.Views.First().Value.Id);
|
||||
_sheet.SetActiveView(_sheet.Views[0].Value.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +291,7 @@
|
||||
private async Task HandleOnActiveViewChanged(Guid viewId)
|
||||
{
|
||||
_sheet!.SetActiveView(viewId);
|
||||
|
||||
|
||||
_viewActionsContext = new ViewActionsContext();
|
||||
|
||||
ResetSheet();
|
||||
@@ -304,7 +319,7 @@
|
||||
|
||||
private void HandleOnColumnOrderChanged(List<string> columnOrder)
|
||||
{
|
||||
_sheet.ActiveView.Order = columnOrder;
|
||||
_sheet!.ActiveView.Order = columnOrder;
|
||||
|
||||
if (!_sheet.ActiveView.Order.Contains(Preset.ActionsColumnId))
|
||||
{
|
||||
@@ -336,7 +351,7 @@
|
||||
if (!pageSizeOptions.Contains(_sheet.ActiveView.PageSize))
|
||||
{
|
||||
_sheet.ActiveView.PageIndex = 1;
|
||||
_sheet.ActiveView.PageSize = pageSizeOptions.First();
|
||||
_sheet.ActiveView.PageSize = pageSizeOptions[0];
|
||||
|
||||
await RefreshItemsAsync(GetItemsProviderRequest());
|
||||
}
|
||||
@@ -362,7 +377,7 @@
|
||||
|
||||
private void OpenColumnEditDialog(Column column)
|
||||
{
|
||||
var viewColumn = _sheet.ActiveView.Columns.First(u => u.ColumnId == column.Id);
|
||||
var viewColumn = _sheet!.ActiveView.Columns.First(u => u.ColumnId == column.Id);
|
||||
_columnEditDialog?.Open(column, viewColumn.Fixed);
|
||||
}
|
||||
|
||||
@@ -410,9 +425,9 @@
|
||||
{
|
||||
_sheet.ActiveView.Selection[item] = selected;
|
||||
}
|
||||
|
||||
|
||||
_viewActionsContext = new ViewActionsContext(_sheet.ActiveView.Selection);
|
||||
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -483,4 +498,13 @@
|
||||
|
||||
await OnSave.InvokeAsync(sheet);
|
||||
}
|
||||
|
||||
public async Task ReloadAsync(int? page = default, int? pageSize = default)
|
||||
{
|
||||
if (page.HasValue && page > 0)
|
||||
_sheet!.ActiveView.PageIndex = page.Value;
|
||||
if (pageSize.HasValue && pageSize > 0)
|
||||
_sheet!.ActiveView.PageSize = pageSize.Value;
|
||||
await RefreshItemsAsync(GetItemsProviderRequest());
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,11 @@ public partial class MTemplateTable
|
||||
|
||||
[Inject] private IGraphQLClient GraphQLClient { get; set; } = null!;
|
||||
|
||||
[Parameter] [EditorRequired] public Sheet? Sheet { get; set; }
|
||||
[Parameter] public string Class { get; set; } = default!;
|
||||
|
||||
[Parameter] public bool Dense { get; set; } = false;
|
||||
|
||||
[Parameter][EditorRequired] public Sheet? Sheet { get; set; }
|
||||
|
||||
[Parameter] public IList<View>? UserViews { get; set; }
|
||||
|
||||
@@ -31,14 +35,48 @@ public partial class MTemplateTable
|
||||
|
||||
[Parameter] public RenderFragment<ViewActionsContext>? ViewActionsContent { get; set; }
|
||||
|
||||
[Parameter] public bool ShowToolbarViews { get; set; }
|
||||
|
||||
[Parameter] public bool ShowToolbar { get; set; }
|
||||
|
||||
[Parameter] public bool ShowToolbarActions { get; set; }
|
||||
|
||||
[Parameter] public RenderFragment<CustomCellContext>? CustomCellContent { get; set; }
|
||||
|
||||
[Parameter] public Role Role { get; set; }
|
||||
|
||||
[Parameter] public int DefaultPageSize { get; set; } = 10;
|
||||
|
||||
[Parameter] public bool ShowFilter { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<bool> ShowFilterChanged { get; set; }
|
||||
|
||||
[Parameter] public bool ShowSort { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<bool> ShowSortChanged { get; set; }
|
||||
|
||||
[Parameter] public bool Stripe { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string TableClass { get; set; } = default!;
|
||||
|
||||
[Parameter]
|
||||
public string HeaderClass { get; set; } = "m-data-table-header";
|
||||
|
||||
[Parameter]
|
||||
public string HeaderThClass { get; set; } = "sortable text-start";
|
||||
|
||||
[Parameter]
|
||||
public string BodyTrClass { get; set; } = default!;
|
||||
|
||||
[Parameter]
|
||||
public string BodyTdClass { get; set; } = "text-start";
|
||||
|
||||
[Parameter]
|
||||
public string StripeClass { get; set; } = default!;
|
||||
|
||||
private SheetInfo? _sheet = null;
|
||||
private bool _init;
|
||||
|
||||
private ViewActionsContext _viewActionsContext = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -57,7 +95,7 @@ public partial class MTemplateTable
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
// base.OnParametersSetAsync();
|
||||
await base.OnParametersSetAsync();
|
||||
|
||||
if (_prevSheet != Sheet)
|
||||
{
|
||||
@@ -77,12 +115,21 @@ public partial class MTemplateTable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ShowFilter)
|
||||
{
|
||||
_filterDialog?.Open();
|
||||
}
|
||||
if (ShowSort)
|
||||
{
|
||||
_sortDialog?.Open();
|
||||
}
|
||||
}
|
||||
|
||||
private void FormatSheet()
|
||||
{
|
||||
_sheet = SheetInfo.From(Sheet);
|
||||
_allColumns = [Preset.CreateSelectColumn(), .._sheet.Columns, Preset.CreateActionsColumn()];
|
||||
_allColumns = [Preset.CreateSelectColumn(), .. _sheet.Columns, Preset.CreateActionsColumn()];
|
||||
|
||||
UpdateStateOfActiveView();
|
||||
}
|
||||
@@ -174,7 +221,7 @@ public partial class MTemplateTable
|
||||
{
|
||||
Operator = _sheet!.ActiveView.Value.Filter.Operator,
|
||||
Search = _sheet.ActiveView.Value.Filter.Search,
|
||||
Options = [.._sheet.ActiveView.Value.Filter.Options]
|
||||
Options = [.. _sheet.ActiveView.Value.Filter.Options]
|
||||
};
|
||||
|
||||
return new QueryRequest(_sheet.QueryBody, _sheet.CountField, filterRequest,
|
||||
|
||||
@@ -7,15 +7,27 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser"/>
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.7"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Masa.Blazor.Components.TemplateTable.Abstractions\Masa.Blazor.Components.TemplateTable.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\i18n\en-US.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\i18n\supportedCultures.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\i18n\zh-CN.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
Options="@_options"
|
||||
ItemsPerPageOptions="@_itemsPerPageOptions"
|
||||
ShowItemsPerPageOptionsEvenIfOne
|
||||
OnOptionsUpdate="@HandleOnOptionsUpdate"
|
||||
></MDataFooter>
|
||||
Class="white"
|
||||
OnOptionsUpdate="@HandleOnOptionsUpdate"></MDataFooter>
|
||||
|
||||
@code {
|
||||
[Parameter] public int PageIndex { get; set; }
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System.Net.Http.Headers;
|
||||
using GraphQL.Client.Http;
|
||||
using GraphQL.Client.Serializer.SystemTextJson;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
@@ -16,7 +12,7 @@ public static class ServiceCollectionExtensions
|
||||
public static IMasaBlazorBuilder AddGraphQLClientForTemplateTable(this IMasaBlazorBuilder builder, string endPoint,
|
||||
string? bearerToken = null)
|
||||
{
|
||||
builder.Services.AddScoped<GraphQLHttpClient>(_ =>
|
||||
builder.Services.AddScoped<GraphQL.Client.Abstractions.IGraphQLClient>(_ =>
|
||||
{
|
||||
var client = new GraphQLHttpClient(endPoint,
|
||||
new SystemTextJsonSerializer(new JsonSerializerOptions(JsonSerializerDefaults.Web)));
|
||||
@@ -27,9 +23,23 @@ public static class ServiceCollectionExtensions
|
||||
new AuthenticationHeaderValue("Bearer", bearerToken);
|
||||
}
|
||||
|
||||
return client;
|
||||
return (GraphQL.Client.Abstractions.IGraphQLClient)client;
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IMasaBlazorBuilder AddGraphQLClientForTemplateTable(this IMasaBlazorBuilder builder, Func<IServiceProvider, GraphQL.Client.Abstractions.IGraphQLClient> func)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(func);
|
||||
builder.Services.AddScoped(func);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Task<IMasaBlazorBuilder> AddTemplateTableI18nAsync(this IMasaBlazorBuilder builder, string hostPath)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(hostPath);
|
||||
var i18nPath = $"{hostPath}/_content/Masa.Blazor.Components.TemplateTable/i18n";
|
||||
return builder.AddI18nForWasmAsync(i18nPath);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
@namespace Masa.Blazor.Components.TemplateTable.SortDialogs
|
||||
@inject I18n i18N
|
||||
|
||||
<PModal @bind-Value="dialog"
|
||||
<PModal @bind-Value="Show"
|
||||
Width="640"
|
||||
Title="Sorting"
|
||||
Title="@i18N.T("Sorting")"
|
||||
Persistent
|
||||
BodyStyle="min-height: 180px"
|
||||
OnCancel="@HandleOnCancel"
|
||||
@@ -13,7 +14,7 @@
|
||||
var option = _sorts[index];
|
||||
<div class="d-flex align-center justify-end mb-2">
|
||||
<div class="mr-2 text-right">
|
||||
@(index == 0 ? "Sort by" : "Then by")
|
||||
@(index == 0 ? i18N.T("Sortby") : i18N.T("Thenby"))
|
||||
<span class="font-weight-bold">
|
||||
@($"{option.Column.Name}({option.ColumnId})")
|
||||
</span>
|
||||
@@ -22,7 +23,7 @@
|
||||
<MSelect @bind-Value="@option.OrderBy"
|
||||
Items="@_directions"
|
||||
ItemValue="u => u.Value"
|
||||
ItemText="u => u.Label"
|
||||
ItemText="@(u => i18N.T($"{u.Label}"))"
|
||||
Class="mr-2"
|
||||
Dense
|
||||
Filled
|
||||
@@ -48,7 +49,7 @@
|
||||
<div class="text-right" style="margin-right: 44px;">
|
||||
<SortBy Columns="@ComputedColumns"
|
||||
OnSelect="@AddSort">
|
||||
@(_sorts.Count == 0 ? "Sort by" : "Then by")
|
||||
@(_sorts.Count == 0 ? i18N.T("Sortby") : i18N.T("Add"))
|
||||
</SortBy>
|
||||
</div>
|
||||
}
|
||||
@@ -65,13 +66,16 @@
|
||||
|
||||
[Parameter] public EventCallback<Sort> OnSave { get; set; }
|
||||
|
||||
[Parameter] public bool Show { get; set; }
|
||||
|
||||
[Parameter] public EventCallback<bool> ShowChanged { get; set; }
|
||||
|
||||
private static (SortOrder Value, string Label)[] _directions =
|
||||
[
|
||||
(SortOrder.Asc, "ascending"),
|
||||
(SortOrder.Desc, "descending")
|
||||
];
|
||||
|
||||
private bool dialog;
|
||||
private IList<ColumnInfo> _computedColumns = [];
|
||||
|
||||
private IList<SortModel> _sorts = [];
|
||||
@@ -111,7 +115,7 @@
|
||||
internal void Open()
|
||||
{
|
||||
SetSorts();
|
||||
dialog = true;
|
||||
Show = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -126,25 +130,30 @@
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_sorts.Remove(model);
|
||||
}
|
||||
|
||||
private void HandleOnCancel()
|
||||
private async Task HandleOnCancel()
|
||||
{
|
||||
_sorts.Clear();
|
||||
dialog = false;
|
||||
Show = false;
|
||||
if (ShowChanged.HasDelegate)
|
||||
await ShowChanged.InvokeAsync(Show);
|
||||
}
|
||||
|
||||
private void HandleOnSave()
|
||||
private async Task HandleOnSave()
|
||||
{
|
||||
dialog = false;
|
||||
Show = false;
|
||||
if (ShowChanged.HasDelegate)
|
||||
await ShowChanged.InvokeAsync(Show);
|
||||
|
||||
var sort = new Sort()
|
||||
{
|
||||
Options = _sorts.Select(u => u.ToSortOption()).ToList()
|
||||
};
|
||||
|
||||
OnSave.InvokeAsync(sort);
|
||||
if (OnSave.HasDelegate)
|
||||
await OnSave.InvokeAsync(sort);
|
||||
}
|
||||
}
|
||||
@@ -1,199 +1,211 @@
|
||||
@using System.Globalization
|
||||
@inject IPopupService PopupService
|
||||
@inject I18n i18N;
|
||||
|
||||
<div class="masa-table__toolbar">
|
||||
<MRow Dense>
|
||||
<MCol Cols="12" Md="@(Role == Role.Manager ? 12 : 5)" Class="d-flex align-center">
|
||||
@{
|
||||
var firstUserView = Views.FirstOrDefault(u => u.IsUserView);
|
||||
}
|
||||
<MSelect Value="ActiveView"
|
||||
ValueChanged="ActiveViewChanged"
|
||||
Items="@Views"
|
||||
ItemText="v => v.Value.Name"
|
||||
ItemValue="v => v.Value.Id"
|
||||
Class="m-template-table__view-select mr-2"
|
||||
Label="View"
|
||||
Dense
|
||||
Outlined
|
||||
HideDetails="true"
|
||||
TItem="ViewInfo"
|
||||
TItemValue="Guid"
|
||||
TValue="Guid"
|
||||
OnSelect="@(tuple => OnActiveViewChanged(tuple.Item))">
|
||||
<SelectionContent>
|
||||
@GenModifiedChip(context.Item)
|
||||
</SelectionContent>
|
||||
<ItemContent>
|
||||
<div class="m-template-table__view-select-item">
|
||||
@if (context.Item == firstUserView)
|
||||
{
|
||||
<MDivider @key="@context.Item"/>
|
||||
}
|
||||
@GenModifiedChip(context.Item)
|
||||
</div>
|
||||
</ItemContent>
|
||||
</MSelect>
|
||||
|
||||
@if (_activeViewInfo is not null)
|
||||
{
|
||||
<ViewAction Loading="@_viewActionLoading"
|
||||
Role="@Role"
|
||||
ViewInfo="@_activeViewInfo"
|
||||
OnSaveAsNewView="@SaveAsNewView"
|
||||
OnViewDelete="@HandleOnDelete"
|
||||
OnViewRename="@UpdateViewName"
|
||||
OnViewSave="@HandleOnViewSave"/>
|
||||
}
|
||||
|
||||
@if (Role == Role.Manager)
|
||||
{
|
||||
<MTooltip Top>
|
||||
<ActivatorContent>
|
||||
<MButton Class="ml-1"
|
||||
Color="primary"
|
||||
OnClick="@OnSave"
|
||||
@attributes="@context.Attrs">
|
||||
保存
|
||||
</MButton>
|
||||
</ActivatorContent>
|
||||
<ChildContent>
|
||||
保存所有设置及视图
|
||||
</ChildContent>
|
||||
</MTooltip>
|
||||
}
|
||||
</MCol>
|
||||
@if (Role == Role.User)
|
||||
@if (ShowToolbar)
|
||||
{
|
||||
<div class="masa-table__toolbar">
|
||||
@if (ShowToolbarViews)
|
||||
{
|
||||
var searchableColumns = _activeViewInfo?.GetSearchableColumn();
|
||||
var hasSearch = searchableColumns?.Count > 0;
|
||||
if (hasSearch)
|
||||
{
|
||||
var placeholder = $"Search for {string.Join(", ", searchableColumns.Select(u => u.Column.Name))}";
|
||||
|
||||
<MCol Cols="12" Md="6" OffsetMd="1" Align="AlignTypes.Center">
|
||||
<MTextField @bind-Value="_activeViewInfo!.Value.Filter.Search"
|
||||
Placeholder="@placeholder"
|
||||
PersistentPlaceholder
|
||||
Outlined
|
||||
Clearable
|
||||
Dense
|
||||
HideDetails="true"
|
||||
OnEnter="@OnSearch"
|
||||
OnClearClick="@OnSearch">
|
||||
</MTextField>
|
||||
</MCol>
|
||||
}
|
||||
}
|
||||
</MRow>
|
||||
<MDivider Class="mt-2"/>
|
||||
<MRow Class="masa-table__toolbar-actions"
|
||||
NoGutters>
|
||||
<MCol Cols="12" Md="6" Align="AlignTypes.Center">
|
||||
@if (Editable)
|
||||
{
|
||||
<MButton LeftIconName="mdi-cog-outline" Text Small OnClick="@(() => _configDialog = true)">
|
||||
<MBadge Value="@HasCustom" Dot Color="red">
|
||||
表格配置
|
||||
</MBadge>
|
||||
</MButton>
|
||||
<MDivider Vertical Style="height: 1rem"/>
|
||||
}
|
||||
<MButton LeftIconName="mdi-filter-variant" Text Small OnClick="@OnFilterClick">
|
||||
<MBadge Value="@HasFilter" Dot Color="red">
|
||||
筛选
|
||||
</MBadge>
|
||||
</MButton>
|
||||
<MDivider Vertical Style="height: 1rem"/>
|
||||
<MButton LeftIconName="mdi-sort" Text Small OnClick="@OnSortClick">
|
||||
<MBadge Value="@HasSort" Dot Color="red">
|
||||
排序
|
||||
</MBadge>
|
||||
</MButton>
|
||||
<MDivider Vertical Style="height: 1rem"/>
|
||||
<MMenu MinWidth="160">
|
||||
<ActivatorContent>
|
||||
<MButton LeftIconName="mdi-format-line-spacing"
|
||||
Text Small
|
||||
@attributes="@context.Attrs">
|
||||
行高
|
||||
</MButton>
|
||||
</ActivatorContent>
|
||||
<ChildContent>
|
||||
<MList Slim Dense>
|
||||
<MListItemGroup Value="@((int)RowHeight)"
|
||||
ValueChanged="@((val) => RowHeightChanged.InvokeAsync((RowHeight)val.AsT1))"
|
||||
Mandatory
|
||||
Color="primary">
|
||||
<MListItem Value="0">
|
||||
<ItemContent>
|
||||
<MListItemAction>
|
||||
<FadeTransition>
|
||||
<MIcon Dense TransitionShow="@context.Active">mdi-check</MIcon>
|
||||
</FadeTransition>
|
||||
</MListItemAction>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
低
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
<MListItem Value="1">
|
||||
<ItemContent>
|
||||
<MListItemAction>
|
||||
<FadeTransition>
|
||||
<MIcon Dense TransitionShow="@context.Active">mdi-check</MIcon>
|
||||
</FadeTransition>
|
||||
</MListItemAction>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
中
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
<MListItem Value="2">
|
||||
<ItemContent>
|
||||
<MListItemAction>
|
||||
<FadeTransition>
|
||||
<MIcon Dense TransitionShow="@context.Active">mdi-check</MIcon>
|
||||
</FadeTransition>
|
||||
</MListItemAction>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
高
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
</MListItemGroup>
|
||||
</MList>
|
||||
</ChildContent>
|
||||
</MMenu>
|
||||
</MCol>
|
||||
<MCol Cols="12" Md="6" Class="m-template-table__toolbar-actions">
|
||||
<MDefaultsProvider Defaults="@_defaults">
|
||||
@ViewActionsContent
|
||||
@if (ShowBulkDelete && HasSelect)
|
||||
{
|
||||
<MButton Disabled="@(!HasSelectedKeys)"
|
||||
Color="error"
|
||||
<MRow Dense>
|
||||
<MCol Cols="12" Md="@(Role == Role.Manager ? 12 : 5)" Class="d-flex align-center">
|
||||
@{
|
||||
var firstUserView = Views.FirstOrDefault(u => u.IsUserView);
|
||||
}
|
||||
<MSelect Value="ActiveView"
|
||||
ValueChanged="ActiveViewChanged"
|
||||
Items="@Views"
|
||||
ItemText="v => v.Value.Name"
|
||||
ItemValue="v => v.Value.Id"
|
||||
Class="m-template-table__view-select mr-2"
|
||||
Label="View"
|
||||
Dense
|
||||
Outlined
|
||||
Loading="@_deleting"
|
||||
OnClick="@HandleOnBulkDelete">
|
||||
批量删除
|
||||
</MButton>
|
||||
HideDetails="true"
|
||||
TItem="ViewInfo"
|
||||
TItemValue="Guid"
|
||||
TValue="Guid"
|
||||
OnSelect="@(tuple => OnActiveViewChanged(tuple.Item))">
|
||||
<SelectionContent>
|
||||
@GenModifiedChip(context.Item)
|
||||
</SelectionContent>
|
||||
<ItemContent>
|
||||
<div class="m-template-table__view-select-item">
|
||||
@if (context.Item == firstUserView)
|
||||
{
|
||||
<MDivider @key="@context.Item" />
|
||||
}
|
||||
@GenModifiedChip(context.Item)
|
||||
</div>
|
||||
</ItemContent>
|
||||
</MSelect>
|
||||
|
||||
@if (_activeViewInfo is not null)
|
||||
{
|
||||
<ViewAction Loading="@_viewActionLoading"
|
||||
Role="@Role"
|
||||
ViewInfo="@_activeViewInfo"
|
||||
OnSaveAsNewView="@SaveAsNewView"
|
||||
OnViewDelete="@HandleOnDelete"
|
||||
OnViewRename="@UpdateViewName"
|
||||
OnViewSave="@HandleOnViewSave" />
|
||||
}
|
||||
|
||||
@if (Role == Role.Manager)
|
||||
{
|
||||
<MTooltip Top>
|
||||
<ActivatorContent>
|
||||
<MButton Class="ml-1"
|
||||
Color="primary"
|
||||
OnClick="@OnSave"
|
||||
@attributes="@context.Attrs">
|
||||
保存
|
||||
</MButton>
|
||||
</ActivatorContent>
|
||||
<ChildContent>
|
||||
保存所有设置及视图
|
||||
</ChildContent>
|
||||
</MTooltip>
|
||||
}
|
||||
</MCol>
|
||||
@if (Role == Role.User)
|
||||
{
|
||||
var searchableColumns = _activeViewInfo?.GetSearchableColumn();
|
||||
var hasSearch = searchableColumns?.Count > 0;
|
||||
if (hasSearch)
|
||||
{
|
||||
var placeholder = $"Search for {string.Join(", ", searchableColumns.Select(u => u.Column.Name))}";
|
||||
|
||||
<MCol Cols="12" Md="6" OffsetMd="1" Align="AlignTypes.Center">
|
||||
<MTextField @bind-Value="_activeViewInfo!.Value.Filter.Search"
|
||||
Placeholder="@placeholder"
|
||||
PersistentPlaceholder
|
||||
Outlined
|
||||
Clearable
|
||||
Dense
|
||||
HideDetails="true"
|
||||
OnEnter="@OnSearch"
|
||||
OnClearClick="@OnSearch">
|
||||
</MTextField>
|
||||
</MCol>
|
||||
}
|
||||
}
|
||||
<MButton Color="secondary"
|
||||
Outlined
|
||||
OnClick="@ResetView">
|
||||
重置
|
||||
</MButton>
|
||||
</MDefaultsProvider>
|
||||
</MCol>
|
||||
</MRow>
|
||||
</div>
|
||||
</MRow>
|
||||
}
|
||||
@if (ShowToolbarViews && ShowToolbarActions)
|
||||
{
|
||||
<MDivider Class="mt-2" />
|
||||
}
|
||||
@if (ShowToolbarActions)
|
||||
{
|
||||
<MRow Class="masa-table__toolbar-actions" NoGutters>
|
||||
<MCol Cols="12" Md="6" Align="AlignTypes.Center">
|
||||
@if (Editable)
|
||||
{
|
||||
<MButton LeftIconName="mdi-cog-outline" Text Small OnClick="@(() => _configDialog = true)">
|
||||
<MBadge Value="@HasCustom" Dot Color="red">
|
||||
表格配置
|
||||
</MBadge>
|
||||
</MButton>
|
||||
<MDivider Vertical Style="height: 1rem" />
|
||||
}
|
||||
<MButton LeftIconName="mdi-filter-variant" Text Small OnClick="@OnFilterClick">
|
||||
<MBadge Value="@HasFilter" Dot Color="red">
|
||||
筛选
|
||||
</MBadge>
|
||||
</MButton>
|
||||
<MDivider Vertical Style="height: 1rem" />
|
||||
<MButton LeftIconName="mdi-sort" Text Small OnClick="@OnSortClick">
|
||||
<MBadge Value="@HasSort" Dot Color="red">
|
||||
排序
|
||||
</MBadge>
|
||||
</MButton>
|
||||
<MDivider Vertical Style="height: 1rem" />
|
||||
<MMenu MinWidth="160">
|
||||
<ActivatorContent>
|
||||
<MButton LeftIconName="mdi-format-line-spacing"
|
||||
Text Small
|
||||
@attributes="@context.Attrs">
|
||||
行高
|
||||
</MButton>
|
||||
</ActivatorContent>
|
||||
<ChildContent>
|
||||
<MList Slim Dense>
|
||||
<MListItemGroup Value="@((int)RowHeight)"
|
||||
ValueChanged="@((val) => RowHeightChanged.InvokeAsync((RowHeight)val.AsT1))"
|
||||
Mandatory
|
||||
Color="primary">
|
||||
<MListItem Value="0">
|
||||
<ItemContent>
|
||||
<MListItemAction>
|
||||
<FadeTransition>
|
||||
<MIcon Dense TransitionShow="@context.Active">mdi-check</MIcon>
|
||||
</FadeTransition>
|
||||
</MListItemAction>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
低
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
<MListItem Value="1">
|
||||
<ItemContent>
|
||||
<MListItemAction>
|
||||
<FadeTransition>
|
||||
<MIcon Dense TransitionShow="@context.Active">mdi-check</MIcon>
|
||||
</FadeTransition>
|
||||
</MListItemAction>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
中
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
<MListItem Value="2">
|
||||
<ItemContent>
|
||||
<MListItemAction>
|
||||
<FadeTransition>
|
||||
<MIcon Dense TransitionShow="@context.Active">mdi-check</MIcon>
|
||||
</FadeTransition>
|
||||
</MListItemAction>
|
||||
<MListItemContent>
|
||||
<MListItemTitle>
|
||||
高
|
||||
</MListItemTitle>
|
||||
</MListItemContent>
|
||||
</ItemContent>
|
||||
</MListItem>
|
||||
</MListItemGroup>
|
||||
</MList>
|
||||
</ChildContent>
|
||||
</MMenu>
|
||||
</MCol>
|
||||
<MCol Cols="12" Md="6" Class="m-template-table__toolbar-actions">
|
||||
<MDefaultsProvider Defaults="@_defaults">
|
||||
@ViewActionsContent
|
||||
@if (ShowBulkDelete && HasSelect)
|
||||
{
|
||||
<MButton Disabled="@(!HasSelectedKeys)"
|
||||
Color="error"
|
||||
Outlined
|
||||
Loading="@_deleting"
|
||||
OnClick="@HandleOnBulkDelete">
|
||||
批量删除
|
||||
</MButton>
|
||||
}
|
||||
<MButton Color="secondary"
|
||||
Outlined
|
||||
OnClick="@ResetView">
|
||||
重置
|
||||
</MButton>
|
||||
</MDefaultsProvider>
|
||||
</MCol>
|
||||
</MRow>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<PDrawer @bind-Value="_configDialog"
|
||||
Title="表格配置"
|
||||
@@ -258,7 +270,7 @@
|
||||
Style="color: inherit"
|
||||
OnClick="@(() => OnColumnEditClick.InvokeAsync(sortContext.Item))">
|
||||
</MButton>
|
||||
<MDivider Vertical Length="16" Class="my-auto mx-1"/>
|
||||
<MDivider Vertical Length="16" Class="my-auto mx-1" />
|
||||
}
|
||||
<MToggle Value="@(!hidden)"
|
||||
DataOn="@("mdi-eye-outline")"
|
||||
@@ -267,7 +279,7 @@
|
||||
<MButton IconName="@context.Data"
|
||||
Small
|
||||
Style="color: inherit"
|
||||
OnClick="@(() => OnColumnToggle.InvokeAsync(sortContext.Item.Id))"/>
|
||||
OnClick="@(() => OnColumnToggle.InvokeAsync(sortContext.Item.Id))" />
|
||||
</MToggle>
|
||||
</MChip>
|
||||
</ItemContent>
|
||||
@@ -313,7 +325,7 @@
|
||||
|
||||
<MDialog @bind-Value="_filterDialog"
|
||||
MaxWidth="400">
|
||||
<MButton Outlined Block>Add filter</MButton>
|
||||
<MButton Outlined Block>@i18N.T("ADD_FILTER")</MButton>
|
||||
</MDialog>
|
||||
|
||||
@code {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Masa.Blazor.Components.TemplateTable.Actions;
|
||||
|
||||
namespace Masa.Blazor.Components.TemplateTable.Toolbars;
|
||||
namespace Masa.Blazor.Components.TemplateTable.Toolbars;
|
||||
|
||||
public partial class Toolbar
|
||||
{
|
||||
@@ -50,6 +48,12 @@ public partial class Toolbar
|
||||
|
||||
[Parameter] public EventCallback OnRowRemove { get; set; }
|
||||
|
||||
[Parameter] public bool ShowToolbarViews { get; set; } = true;
|
||||
|
||||
[Parameter] public bool ShowToolbar { get; set; } = true;
|
||||
|
||||
[Parameter] public bool ShowToolbarActions { get; set; } = true;
|
||||
|
||||
[Parameter] public bool HasSelectedKeys { get; set; }
|
||||
|
||||
[Parameter] public bool HasActions { get; set; }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<div @ref="_ref"
|
||||
class="masa-table-viewer__header-column-content @Class"
|
||||
class="masa-table-viewer__header-column-content d-flex px-4 @Class"
|
||||
@onclick="@HandleOnClick">
|
||||
@if (IsRowSelect)
|
||||
{
|
||||
@@ -9,12 +9,12 @@
|
||||
Indeterminate="@IsIndeterminate"
|
||||
Value="@IsSelectedAll"
|
||||
ValueChanged="@OnSelectAll"
|
||||
Color="@CheckboxColor"/>
|
||||
Color="@CheckboxColor" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@Templates.GenTypeIcon(Data.Type, true)
|
||||
<span class="text-truncate">@Data.Name</span>
|
||||
<span class="text-truncate px-2">@Data.Name</span>
|
||||
}
|
||||
|
||||
@if (!Internal)
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
@if (!Internal)
|
||||
{
|
||||
<Resizor/>
|
||||
<Resizor />
|
||||
}
|
||||
|
||||
@code {
|
||||
@@ -130,8 +130,8 @@
|
||||
{
|
||||
ColumnId = Data.Id,
|
||||
OrderBy = SortOrder.Asc,
|
||||
Index = sort.Options.MaxBy(u => u.Index)?.Index + 1 ?? 0,
|
||||
Type = Data.GetExpectedType()
|
||||
Type = Data.Type.ConvertToExpectedType(),
|
||||
Index = sort.Options.MaxBy(u => u.Index)?.Index + 1 ?? 0
|
||||
};
|
||||
|
||||
sort.Options.Add(sortOption);
|
||||
|
||||
@@ -4,141 +4,143 @@
|
||||
@using Masa.Blazor.Components.TemplateTable.Actions
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
|
||||
<MSimpleTable FixedHeader
|
||||
Class="@_modifierBuilder.Add(RowHeight.ToString()).Add(_sized).Build()"
|
||||
Style="@($"--mt-row-height: {RowHeightValue}")"
|
||||
<MSimpleTable FixedHeader Class="@Class"
|
||||
Height="@Height"
|
||||
@ref="_simpleTable">
|
||||
<thead>
|
||||
<tr @ref="_headerTrRef">
|
||||
<MSortableProvider Items="ViewColumns"
|
||||
ItemKey="@(u => u.ColumnId)"
|
||||
GhostClass="accent"
|
||||
ContainerRef="@_headerTrRef"
|
||||
ForceFallback
|
||||
Ignore=".ignore-elements"
|
||||
Order="@ColumnOrder"
|
||||
OrderChanged="@ColumnOrderChanged">
|
||||
<ItemContent Context="context">
|
||||
@{
|
||||
var (hidden, css, style) = GetHeaderColCss(context.Item);
|
||||
}
|
||||
|
||||
<th class="@css"
|
||||
style="@style"
|
||||
@key="@(context.Item.Column.Id)"
|
||||
@attributes="@context.Attrs">
|
||||
@if (!hidden)
|
||||
{
|
||||
<ColumnName Data="@context.Item.Column"
|
||||
Editable="@Editable"
|
||||
Sort="@Sort"
|
||||
OnClick="@OnSortUpdate"
|
||||
OnColumnToggle="@OnColumnToggle"
|
||||
OnColumnEditClick="@OnColumnEditClick"
|
||||
IsIndeterminate="@SelectionState.Indeterminate"
|
||||
IsSelectedAll="@SelectionState.AllSelected"
|
||||
OnSelectAll="@OnSelectAll"
|
||||
CheckboxColor="@CheckboxColor"/>
|
||||
<thead class="@TableHeaderClass">
|
||||
<tr @ref="_headerTrRef">
|
||||
<MSortableProvider Items="ViewColumns"
|
||||
ItemKey="@(u => u.ColumnId)"
|
||||
GhostClass="accent"
|
||||
ContainerRef="@_headerTrRef"
|
||||
ForceFallback
|
||||
Ignore=".ignore-elements"
|
||||
Order="@ColumnOrder"
|
||||
OrderChanged="@ColumnOrderChanged">
|
||||
<ItemContent Context="context">
|
||||
@{
|
||||
var (hidden, css, style) = GetHeaderColCss(context.Item);
|
||||
}
|
||||
</th>
|
||||
</ItemContent>
|
||||
</MSortableProvider>
|
||||
</tr>
|
||||
|
||||
<th class="@TableHeaderThClass @css"
|
||||
style="@style"
|
||||
@key="@(context.Item.Column.Id)"
|
||||
@attributes="@context.Attrs">
|
||||
@if (!hidden)
|
||||
{
|
||||
<ColumnName Data="@context.Item.Column"
|
||||
Editable="@Editable"
|
||||
Sort="@Sort"
|
||||
OnClick="@OnSortUpdate"
|
||||
OnColumnToggle="@OnColumnToggle"
|
||||
OnColumnEditClick="@OnColumnEditClick"
|
||||
IsIndeterminate="@SelectionState.Indeterminate"
|
||||
IsSelectedAll="@SelectionState.AllSelected"
|
||||
OnSelectAll="@OnSelectAll"
|
||||
CheckboxColor="@CheckboxColor" />
|
||||
}
|
||||
</th>
|
||||
</ItemContent>
|
||||
</MSortableProvider>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@if (Loading)
|
||||
{
|
||||
<thead>
|
||||
<tr class="m-data-table__progress">
|
||||
<th class="column" colspan="1000">
|
||||
@*TODO: 设置为正常的colspan*@
|
||||
<MProgressLinear Absolute Indeterminate Color="primary"></MProgressLinear>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="m-data-table__progress">
|
||||
<th class="column" colspan="1000">
|
||||
@*TODO: 设置为正常的colspan*@
|
||||
<MProgressLinear Absolute Indeterminate Color="primary"></MProgressLinear>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
}
|
||||
|
||||
@{
|
||||
int rowIndex = 1;
|
||||
}
|
||||
<tbody>
|
||||
<Virtualize Items="Rows"
|
||||
Context="item"
|
||||
ItemSize="RowHeightValue"
|
||||
OverscanCount="1">
|
||||
@{
|
||||
var isSelected = SelectedKeys.Contains(item.Key);
|
||||
}
|
||||
<Virtualize Items="Rows"
|
||||
Context="item"
|
||||
ItemSize="RowHeightValue"
|
||||
OverscanCount="1">
|
||||
@{
|
||||
var isSelected = SelectedKeys.Contains(item.Key);
|
||||
bool isStripe = rowIndex % 2 == 0;
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
<tr class="@_rowModifierBuilder.AddClass("m-data-table__selected", isSelected)">
|
||||
@foreach (var template in _orderedViewColumns)
|
||||
{
|
||||
var (hidden, css, style) = GetCss(template);
|
||||
<tr class="@_rowModifierBuilder.AddClass("m-data-table__selected", isSelected).AddClass(TableStripeClass, isStripe)">
|
||||
@foreach (var template in _orderedViewColumns)
|
||||
{
|
||||
var (hidden, css, style) = GetCss(template);
|
||||
|
||||
<td class="@css"
|
||||
style="@style"
|
||||
@key="template.Column.Id">
|
||||
@if (!hidden)
|
||||
{
|
||||
<div class="masa-table-viewer__cell">
|
||||
<div class="masa-table-viewer__cell-content">
|
||||
@if (template.Column.Type == ColumnType.Actions)
|
||||
{
|
||||
<MDefaultsProvider Defaults="@_actionsDefautls">
|
||||
@GenActionsCell(item.Data)
|
||||
</MDefaultsProvider>
|
||||
}
|
||||
else if (template.Column.Type == ColumnType.RowSelect)
|
||||
{
|
||||
@GenRowSelectCell(item, isSelected)
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonElement? value = null;
|
||||
|
||||
if (template.Column.IsNested)
|
||||
<td class="@TableBodyTdClass @css"
|
||||
style="@style"
|
||||
@key="template.Column.Id">
|
||||
@if (!hidden)
|
||||
{
|
||||
<div class="masa-table-viewer__cell">
|
||||
<div class="masa-table-viewer__cell-content">
|
||||
@if (template.Column.Type == ColumnType.Actions)
|
||||
{
|
||||
var tree = template.Column.Id.Split('.');
|
||||
var firstKey = tree[0];
|
||||
var key = item.Data.Keys.FirstOrDefault(u => string.Equals(u, firstKey, StringComparison.OrdinalIgnoreCase));
|
||||
if (key is not null)
|
||||
<MDefaultsProvider Defaults="@_actionsDefautls">
|
||||
@GenActionsCell(item.Data)
|
||||
</MDefaultsProvider>
|
||||
}
|
||||
else if (template.Column.Type == ColumnType.RowSelect)
|
||||
{
|
||||
@GenRowSelectCell(item, isSelected)
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonElement? value = null;
|
||||
|
||||
if (template.Column.IsNested)
|
||||
{
|
||||
value = item.Data[key];
|
||||
for (var i = 1; i < tree.Length; i++)
|
||||
var tree = template.Column.Id.Split('.');
|
||||
var firstKey = tree[0];
|
||||
var key = item.Data.Keys.FirstOrDefault(u => string.Equals(u, firstKey, StringComparison.OrdinalIgnoreCase));
|
||||
if (key is not null)
|
||||
{
|
||||
// 默认使用驼峰命名法
|
||||
value = value.Value.GetProperty(tree[i].ToCamelCase());
|
||||
value = item.Data[key];
|
||||
for (var i = 1; i < tree.Length; i++)
|
||||
{
|
||||
// 默认使用驼峰命名法
|
||||
value = value.Value.GetProperty(tree[i].ToCamelCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = item.Data.Keys.FirstOrDefault(u => string.Equals(u, template.ColumnId, StringComparison.OrdinalIgnoreCase));
|
||||
if (key is not null)
|
||||
else
|
||||
{
|
||||
value = item.Data[key];
|
||||
var key = item.Data.Keys.FirstOrDefault(u => string.Equals(u, template.ColumnId, StringComparison.OrdinalIgnoreCase));
|
||||
if (key is not null)
|
||||
{
|
||||
value = item.Data[key];
|
||||
}
|
||||
}
|
||||
if (value is null)
|
||||
{
|
||||
@GenNotFound(template.Column)
|
||||
}
|
||||
else if (CustomCellContent is not null)
|
||||
{
|
||||
CustomCellContext context = new(template.Column.Id, value.Value, item.Data, @GenCell(template.Column, value.Value));
|
||||
@CustomCellContent.Invoke(context)
|
||||
}
|
||||
else
|
||||
{
|
||||
@GenCell(template.Column, value.Value)
|
||||
}
|
||||
}
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
@GenNotFound(template.Column)
|
||||
}
|
||||
else if (template.Column.Type == ColumnType.Custom && CustomCellContent is not null)
|
||||
{
|
||||
CustomCellContext context = new(template.Column.Id, value.Value, item.Data);
|
||||
@CustomCellContent.Invoke(context)
|
||||
}
|
||||
else
|
||||
{
|
||||
@GenCell(template.Column, value.Value)
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
</Virtualize>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
</Virtualize>
|
||||
</tbody>
|
||||
</MSimpleTable>
|
||||
|
||||
@@ -205,13 +207,13 @@
|
||||
{
|
||||
var isChecked = value.GetBoolean();
|
||||
<MIcon Icon="@(isChecked ? "$checkboxOn" : "$checkboxOff")"
|
||||
Color="@(isChecked ? "primary" : "")"/>
|
||||
Color="@(isChecked ? "primary" : "")" />
|
||||
};
|
||||
|
||||
private static RenderFragment GenSwitchCell(JsonElement value) => __builder =>
|
||||
{
|
||||
var isChecked = value.GetBoolean();
|
||||
<MSwitch Value="@isChecked" Inset Disabled/>
|
||||
<MSwitch Value="@isChecked" Inset Disabled />
|
||||
};
|
||||
|
||||
private static RenderFragment GenTextCell(JsonElement value) => __builder =>
|
||||
@@ -364,7 +366,7 @@
|
||||
<div class="image-list" @onclick="@(() => OnImagePreview.InvokeAsync(urls))">
|
||||
@foreach (var url in urls)
|
||||
{
|
||||
<img src="@url" alt=""/>
|
||||
<img src="@url" alt="" />
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using BemIt;
|
||||
using Masa.Blazor.Components.TemplateTable.Actions;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
|
||||
namespace Masa.Blazor.Components.TemplateTable.Viewers;
|
||||
|
||||
@@ -11,6 +9,8 @@ public partial class Viewer : IAsyncDisposable
|
||||
|
||||
[Inject] private MasaBlazor MasaBlazor { get; set; } = default!;
|
||||
|
||||
[Parameter] public string Class { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// View columns without an order, that will be ordered by <see cref="ColumnOrder"/>.
|
||||
/// </summary>
|
||||
@@ -75,12 +75,22 @@ public partial class Viewer : IAsyncDisposable
|
||||
|
||||
[Parameter] public List<string> SelectedKeys { get; set; } = [];
|
||||
|
||||
// [Parameter] public List<string> SelectableKeys { get; set; } = [];
|
||||
|
||||
[Parameter] public Action<(Row Item, bool Selected)> OnSelect { get; set; } = default!;
|
||||
|
||||
[Parameter] public Action<bool> OnSelectAll { get; set; } = default!;
|
||||
|
||||
[Parameter] public string TableHeaderClass { get; set; } = default!;
|
||||
|
||||
[Parameter] public string TableHeaderThClass { get; set; } = default!;
|
||||
|
||||
[Parameter] public string TableBodyTrClass { get; set; } = default!;
|
||||
|
||||
[Parameter] public string TableBodyTdClass { get; set; } = default!;
|
||||
|
||||
[Parameter] public string TableStripeClass { get; set; } = default!;
|
||||
|
||||
[Parameter] public EventCallback<IReadOnlyCollection<Row>> OnRemove { get; set; }
|
||||
|
||||
private IDictionary<string, IDictionary<string, object?>> _actionsDefautls =
|
||||
new Dictionary<string, IDictionary<string, object?>>
|
||||
{
|
||||
@@ -303,6 +313,7 @@ public partial class Viewer : IAsyncDisposable
|
||||
if (width > 0)
|
||||
{
|
||||
styleBuilder.AddWidth(width);
|
||||
styleBuilder.AddMinWidth(width);
|
||||
}
|
||||
|
||||
if (fixedLeft)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
// Global using directives
|
||||
|
||||
global using System.Text.Json;
|
||||
global using System.Text.Json.Serialization;
|
||||
global using GraphQL.Client.Http;
|
||||
global using GraphQL.Client.Serializer.SystemTextJson;
|
||||
global using Masa.Blazor.Components.TemplateTable;
|
||||
global using Masa.Blazor.Components.TemplateTable.Abstractions;
|
||||
global using Masa.Blazor.Components.TemplateTable.ColumnConfigs;
|
||||
global using Masa.Blazor.Components.TemplateTable.Contracts;
|
||||
global using Masa.Blazor.Core;
|
||||
global using Masa.Blazor.Extensions;
|
||||
global using Microsoft.AspNetCore.Components;
|
||||
global using Microsoft.JSInterop;
|
||||
global using Microsoft.JSInterop;
|
||||
global using System.Net.Http.Headers;
|
||||
global using System.Text.Json;
|
||||
global using System.Text.Json.Serialization;
|
||||
global using Masa.Blazor.Components.TemplateTable.Actions;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"ADD_FILTER": "Add filter",
|
||||
"Filters": "Filters",
|
||||
"When": "When",
|
||||
"and": "and",
|
||||
"or": "or",
|
||||
"ColumnId": "Column",
|
||||
"Func": "Function",
|
||||
"Expected": "Expected",
|
||||
"SDF_Equals": "=",
|
||||
"SDF_NotEquals": "!=",
|
||||
"SDF_Contains": "in",
|
||||
"SDF_NotContains": "not in",
|
||||
"SDF_StartsWith": "left like",
|
||||
"SDF_NotStartsWith": "not left like",
|
||||
"SDF_EndsWith": "right like",
|
||||
"SDF_NotEndsWith": "not right like",
|
||||
"SDF_Set": "exists",
|
||||
"SDF_NotSet": "not exists",
|
||||
"SDF_Gt": ">",
|
||||
"SDF_Gte": ">=",
|
||||
"SDF_Lt": "<",
|
||||
"SDF_Lte": "<=",
|
||||
"SDF_BeforeDate": "<",
|
||||
"SDF_BeforeOrOnDate": "<=",
|
||||
"SDF_AfterDate": ">",
|
||||
"SDF_AfterOrOnDate": ">=",
|
||||
"SDF_True": "true",
|
||||
"SDF_False": "false",
|
||||
"SortBy": "Sort by",
|
||||
"ThenBy": "Then By",
|
||||
"Sorting": "Sorting",
|
||||
"ascending": "asc",
|
||||
"descending": "desc"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
[
|
||||
"zh-CN",
|
||||
"en-US"
|
||||
]
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"ADD_FILTER": "添加条件",
|
||||
"Filters": "筛选条件",
|
||||
"When": "当",
|
||||
"and": "并且",
|
||||
"or": "或",
|
||||
"ColumnId": "列",
|
||||
"Func": "运算符",
|
||||
"Expected": "值",
|
||||
"SDF_Equals": "=",
|
||||
"SDF_NotEquals": "!=",
|
||||
"SDF_Contains": "in",
|
||||
"SDF_NotContains": "not in",
|
||||
"SDF_StartsWith": "left like",
|
||||
"SDF_NotStartsWith": "not left like",
|
||||
"SDF_EndsWith": "right like",
|
||||
"SDF_NotEndsWith": "not right like",
|
||||
"SDF_Set": "存在",
|
||||
"SDF_NotSet": "不存在",
|
||||
"SDF_Gt": ">",
|
||||
"SDF_Gte": ">=",
|
||||
"SDF_Lt": "<",
|
||||
"SDF_Lte": "<=",
|
||||
"SDF_BeforeDate": "<",
|
||||
"SDF_BeforeOrOnDate": "<=",
|
||||
"SDF_AfterDate": ">",
|
||||
"SDF_AfterOrOnDate": ">=",
|
||||
"SDF_True": "true",
|
||||
"SDF_False": "false",
|
||||
"SortBy": "Sort by",
|
||||
"ThenBy": "Then By",
|
||||
"Sorting": "排序",
|
||||
"ascending": "asc",
|
||||
"descending": "desc"
|
||||
}
|
||||
Reference in New Issue
Block a user