diff --git a/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor b/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor index 7542f14d124..41682c8d957 100644 --- a/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor +++ b/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor @@ -1,50 +1,10 @@ @inherits FilterBase - +@if (IsHeaderRow) +{ -@code { - private int Value = 10; - - /// - /// OnInitialized 方法 - /// - protected override void OnInitialized() - { - base.OnInitialized(); - - if (TableFilter != null) TableFilter.ShowMoreButton = false; - - Items = new SelectedItem[] - { - new SelectedItem { Value = "10", Text = "大于 10" }, - new SelectedItem { Value = "50", Text = "大于 50" }, - new SelectedItem { Value = "100", Text = "大于 100" } - }; - } - - /// - /// 重置过滤条件方法 - /// - public override void Reset() - { - Value = 10; - - StateHasChanged(); - } - - /// - /// 生成过滤条件方法 - /// - /// - public override FilterKeyValueAction GetFilterConditions() - { - var filter = new FilterKeyValueAction() { Filters = new() }; - filter.Filters.Add(new FilterKeyValueAction() - { - FieldKey = FieldKey, - FieldValue = Value, - FilterAction = FilterAction.GreaterThan - }); - return filter; - } +} +else +{ + } diff --git a/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor.cs b/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor.cs new file mode 100644 index 00000000000..fe073eeccd3 --- /dev/null +++ b/src/BootstrapBlazor.Server/Components/Components/CustomerFilter.razor.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Server.Components.Components; + +/// +/// +/// +public partial class CustomerFilter +{ + private int? Value; + + private readonly IEnumerable _items = new SelectedItem[] + { + new() { Value = "", Text = "请选择 ..." }, + new() { Value = "10", Text = "大于 10" }, + new() { Value = "50", Text = "大于 50" }, + new() { Value = "80", Text = "大于 80" } + }; + + /// + /// 重置过滤条件方法 + /// + public override void Reset() + { + Value = null; + StateHasChanged(); + } + + /// + /// 生成过滤条件方法 + /// + /// + public override FilterKeyValueAction GetFilterConditions() + { + var filter = new FilterKeyValueAction(); + if (Value != null) + { + filter.Filters.Add(new FilterKeyValueAction() + { + FieldKey = FieldKey, + FieldValue = Value.Value, + FilterAction = FilterAction.GreaterThan + }); + } + return filter; + } +} diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor index 65fee59e62a..d061f3129c6 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor @@ -46,7 +46,7 @@ + Introduction="@Localizer["FilterTemplateIntro"]" Name="CustomFilter">
@((MarkupString)Localizer["TablesFilterTemplateDescription", ComponentSourceCodeUrl].Value)
- + @@ -81,12 +81,12 @@ ShowSkeleton="true" ShowFilterHeader="true" OnQueryAsync="@OnQueryAsync"> - - - + + + - +
@@ -211,22 +211,22 @@ - + - + - + - + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor.cs index 502f5c74077..218df0223b0 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor.cs @@ -29,7 +29,10 @@ public partial class TablesFilter [NotNull] private Table? TableSetFilter { get; set; } - private IEnumerable _nameMultiFilterItems = default!; + private readonly Dictionary _multiFilterParameter1 = new(); + private readonly Dictionary _multiFilterParameter2 = new(); + private readonly Dictionary _multiFilterParameter3 = new(); + private readonly Dictionary _multiFilterParameter4 = new(); /// /// OnInitialized 方法 @@ -39,7 +42,18 @@ protected override void OnInitialized() base.OnInitialized(); Items = Foo.GenerateFoo(FooLocalizer); - _nameMultiFilterItems = Items.Select(i => new SelectedItem(i.Name!, i.Name!)).DistinctBy(i => i.Value); + var items1 = Items.Select(i => new SelectedItem(i.Name!, i.Name!)).DistinctBy(i => i.Value); + _multiFilterParameter1.Add(nameof(MultiFilter.Items), items1); + + _multiFilterParameter2.Add(nameof(MultiFilter.OnGetItemsAsync), new Func>>(OnGetAddressItemsAsync)); + + var items3 = Items.Select(i => new SelectedItem(i.Complete.ToString(), i.Complete.ToString())).DistinctBy(i => i.Value); + _multiFilterParameter3.Add(nameof(MultiFilter.Items), items3); + _multiFilterParameter3.Add(nameof(MultiFilter.ShowSearch), false); + + var items4 = Items.Select(i => new SelectedItem(i.Education.ToString()!, i.Education.ToString()!)).DistinctBy(i => i.Value); + _multiFilterParameter4.Add(nameof(MultiFilter.Items), items4); + _multiFilterParameter4.Add(nameof(MultiFilter.ShowSearch), false); } private async Task> OnGetAddressItemsAsync() diff --git a/src/BootstrapBlazor/Components/Filters/BoolFilter.razor b/src/BootstrapBlazor/Components/Filters/BoolFilter.razor index 4b340ef8257..32caaa79745 100644 --- a/src/BootstrapBlazor/Components/Filters/BoolFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/BoolFilter.razor @@ -3,9 +3,10 @@ @if (IsHeaderRow) { - + } else { - + } diff --git a/src/BootstrapBlazor/Components/Filters/BoolFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/BoolFilter.razor.cs index 495963c477d..fadc3330db0 100644 --- a/src/BootstrapBlazor/Components/Filters/BoolFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/BoolFilter.razor.cs @@ -3,33 +3,20 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.Extensions.Localization; - namespace BootstrapBlazor.Components; /// -/// 布尔类型过滤条件 +/// BoolFilter component is used for boolean value filtering in table column. /// public partial class BoolFilter { - private string Value { get; set; } = ""; - - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } - /// - /// + /// Gets or sets the filter candidate items. It is recommended to use static data to avoid performance loss. /// - protected override void OnInitialized() - { - base.OnInitialized(); + [Parameter] + public IEnumerable? Items { get; set; } - if (TableFilter != null) - { - TableFilter.ShowMoreButton = false; - } - } + private string? _value; /// /// @@ -38,12 +25,12 @@ protected override void OnParametersSet() { base.OnParametersSet(); - Items ??= new SelectedItem[] - { - new("", Localizer["BoolFilter.AllText"].Value), - new("true", Localizer["BoolFilter.TrueText"].Value), - new("false", Localizer["BoolFilter.FalseText"].Value) - }; + Items ??= + [ + new SelectedItem("", Localizer["BoolFilter.AllText"].Value), + new SelectedItem("true", Localizer["BoolFilter.TrueText"].Value), + new SelectedItem("false", Localizer["BoolFilter.FalseText"].Value) + ]; } /// @@ -51,7 +38,7 @@ protected override void OnParametersSet() /// public override void Reset() { - Value = ""; + _value = null; StateHasChanged(); } @@ -61,13 +48,13 @@ public override void Reset() /// public override FilterKeyValueAction GetFilterConditions() { - var filter = new FilterKeyValueAction() { Filters = [] }; - if (!string.IsNullOrEmpty(Value)) + var filter = new FilterKeyValueAction(); + if (!string.IsNullOrEmpty(_value)) { - filter.Filters.Add(new FilterKeyValueAction() + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, - FieldValue = Value == "true", + FieldValue = _value == "true", FilterAction = FilterAction.Equal }); } @@ -79,14 +66,10 @@ public override FilterKeyValueAction GetFilterConditions() /// public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - var first = filter.Filters?.FirstOrDefault() ?? filter; + var first = filter.Filters.FirstOrDefault() ?? filter; if (first.FieldValue is bool value) { - Value = value ? "true" : "false"; - } - else if (first.FieldValue is null) - { - Value = ""; + _value = value ? "true" : "false"; } await base.SetFilterConditionsAsync(filter); } diff --git a/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor b/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor index 68d693bfd37..d436ed9db2a 100644 --- a/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor @@ -1,25 +1,23 @@ @namespace BootstrapBlazor.Components -@inherits FilterBase +@inherits MultipleFilterBase @if (IsHeaderRow) {
- - + +
} else { - - - + + @if (Count > 0) { - - - - + + } } diff --git a/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor.cs index 6c2a70f4802..104933e26a7 100644 --- a/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/DateTimeFilter.razor.cs @@ -3,26 +3,27 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.Extensions.Localization; - namespace BootstrapBlazor.Components; /// -/// 时间类型过滤条件 +/// /// public partial class DateTimeFilter { - private DateTime? Value1 { get; set; } - - private FilterAction Action1 { get; set; } = FilterAction.GreaterThanOrEqual; + private DateTime? _value1; + private FilterAction _action1 = FilterAction.GreaterThanOrEqual; + private DateTime? _value2; + private FilterAction _action2 = FilterAction.LessThanOrEqual; - private DateTime? Value2 { get; set; } + private string? FilterRowClassString => CssBuilder.Default("filter-row") + .AddClass("active", TableColumnFilter.HasFilter()) + .Build(); - private FilterAction Action2 { get; set; } = FilterAction.LessThanOrEqual; - - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } + /// + /// Gets or sets the filter candidate items. It is recommended to use static data to avoid performance loss. + /// + [Parameter] + public IEnumerable? Items { get; set; } /// /// @@ -31,26 +32,26 @@ protected override void OnParametersSet() { base.OnParametersSet(); - Items ??= new SelectedItem[] - { - new("GreaterThanOrEqual", Localizer["GreaterThanOrEqual"].Value), - new("LessThanOrEqual", Localizer["LessThanOrEqual"].Value), - new("GreaterThan", Localizer["GreaterThan"].Value), - new("LessThan", Localizer["LessThan"].Value), - new("Equal", Localizer["Equal"].Value), - new("NotEqual", Localizer["NotEqual"].Value ) - }; + Items ??= + [ + new SelectedItem("GreaterThanOrEqual", Localizer["GreaterThanOrEqual"].Value), + new SelectedItem("LessThanOrEqual", Localizer["LessThanOrEqual"].Value), + new SelectedItem("GreaterThan", Localizer["GreaterThan"].Value), + new SelectedItem("LessThan", Localizer["LessThan"].Value), + new SelectedItem("Equal", Localizer["Equal"].Value), + new SelectedItem("NotEqual", Localizer["NotEqual"].Value) + ]; } /// - /// + /// /// public override void Reset() { - Value1 = null; - Value2 = null; - Action1 = FilterAction.GreaterThanOrEqual; - Action2 = FilterAction.LessThanOrEqual; + _value1 = null; + _value2 = null; + _action1 = FilterAction.GreaterThanOrEqual; + _action2 = FilterAction.LessThanOrEqual; Count = 0; Logic = FilterLogic.And; StateHasChanged(); @@ -62,24 +63,24 @@ public override void Reset() /// public override FilterKeyValueAction GetFilterConditions() { - var filter = new FilterKeyValueAction() { Filters = [] }; - if (Value1 != null) + var filter = new FilterKeyValueAction(); + if (_value1 != null) { filter.Filters.Add(new FilterKeyValueAction() { FieldKey = FieldKey, - FieldValue = Value1, - FilterAction = Action1 + FieldValue = _value1, + FilterAction = _action1 }); } - if (Count > 0 && Value2 != null) + if (Count > 0 && _value2 != null) { - filter.Filters.Add(new FilterKeyValueAction() + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, - FieldValue = Value2, - FilterAction = Action2, + FieldValue = _value2, + FilterAction = _action2, }); filter.FilterLogic = Logic; } @@ -91,30 +92,30 @@ public override FilterKeyValueAction GetFilterConditions() /// public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - var first = filter.Filters?.FirstOrDefault() ?? filter; + var first = filter.Filters.FirstOrDefault() ?? filter; if (first.FieldValue is DateTime value) { - Value1 = value; + _value1 = value; } else { - Value1 = null; + _value1 = null; } - Action1 = first.FilterAction; + _action1 = first.FilterAction; - if (filter.Filters != null && filter.Filters.Count == 2) + if (filter.Filters.Count > 1) { Count = 1; FilterKeyValueAction second = filter.Filters[1]; if (second.FieldValue is DateTime value2) { - Value2 = value2; + _value2 = value2; } else { - Value2 = null; + _value2 = null; } - Action2 = second.FilterAction; + _action2 = second.FilterAction; Logic = filter.FilterLogic; } await base.SetFilterConditionsAsync(filter); diff --git a/src/BootstrapBlazor/Components/Filters/EnumFilter.razor b/src/BootstrapBlazor/Components/Filters/EnumFilter.razor index bcc53220ddc..1e7a88e8f62 100644 --- a/src/BootstrapBlazor/Components/Filters/EnumFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/EnumFilter.razor @@ -1,18 +1,17 @@ @namespace BootstrapBlazor.Components -@inherits FilterBase +@inherits MultipleFilterBase @if (IsHeaderRow) { - + } else { - - + @if (Count > 0) { - - + } } diff --git a/src/BootstrapBlazor/Components/Filters/EnumFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/EnumFilter.razor.cs index b8d1117ce3a..c2ce00f5954 100644 --- a/src/BootstrapBlazor/Components/Filters/EnumFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/EnumFilter.razor.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.Extensions.Localization; - namespace BootstrapBlazor.Components; /// @@ -12,10 +10,6 @@ namespace BootstrapBlazor.Components; /// public partial class EnumFilter { - private string? Value { get; set; } - - private string? Value2 { get; set; } - /// /// 内部使用 /// @@ -25,28 +19,18 @@ public partial class EnumFilter /// /// 获得/设置 相关枚举类型 /// -#if NET6_0_OR_GREATER - [EditorRequired] -#endif [Parameter] [NotNull] public Type? Type { get; set; } - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } - /// - /// + /// Gets or sets the filter candidate items. It is recommended to use static data to avoid performance loss. /// - protected override void OnInitialized() - { - base.OnInitialized(); - - if (Type == null) throw new InvalidOperationException("the Parameter Type must be set."); + [Parameter] + public IEnumerable? Items { get; set; } - EnumType = Nullable.GetUnderlyingType(Type) ?? Type; - } + private string? _value1; + private string? _value2; /// /// @@ -55,6 +39,10 @@ protected override void OnParametersSet() { base.OnParametersSet(); + Type ??= TableColumnFilter?.Column.PropertyType; + if (Type == null) throw new InvalidOperationException("the Parameter Type must be set."); + + EnumType = Nullable.GetUnderlyingType(Type) ?? Type; Items ??= EnumType.ToSelectList(new SelectedItem("", Localizer["EnumFilter.AllText"].Value)); } @@ -63,7 +51,9 @@ protected override void OnParametersSet() /// public override void Reset() { - Value = ""; + _value1 = null; + _value2 = null; + Count = 0; StateHasChanged(); } @@ -73,8 +63,8 @@ public override void Reset() /// public override FilterKeyValueAction GetFilterConditions() { - var filter = new FilterKeyValueAction() { Filters = [] }; - if (!string.IsNullOrEmpty(Value) && Enum.TryParse(EnumType, Value, out var val)) + var filter = new FilterKeyValueAction(); + if (!string.IsNullOrEmpty(_value1) && Enum.TryParse(EnumType, _value1, out var val)) { filter.Filters.Add(new FilterKeyValueAction() { @@ -84,7 +74,7 @@ public override FilterKeyValueAction GetFilterConditions() }); } - if (Count > 0 && Enum.TryParse(EnumType, Value2, out var val2)) + if (Count > 0 && Enum.TryParse(EnumType, _value2, out var val2)) { filter.Filters.Add(new FilterKeyValueAction() { @@ -102,28 +92,28 @@ public override FilterKeyValueAction GetFilterConditions() ///
public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - var first = filter.Filters?.FirstOrDefault() ?? filter; + var first = filter.Filters.FirstOrDefault() ?? filter; var type = Nullable.GetUnderlyingType(Type) ?? Type; if (first.FieldValue != null && first.FieldValue.GetType() == type) { - Value = first.FieldValue.ToString(); + _value1 = first.FieldValue.ToString(); } else { - Value = ""; + _value1 = null; } - if (filter.Filters != null && filter.Filters.Count == 2) + if (filter.Filters.Count > 1) { Count = 1; FilterKeyValueAction second = filter.Filters[1]; if (second.FieldValue != null && second.FieldValue.GetType() == type) { - Value2 = second.FieldValue.ToString(); + _value2 = second.FieldValue.ToString(); } else { - Value2 = ""; + _value2 = null; } Logic = filter.FilterLogic; } diff --git a/src/BootstrapBlazor/Components/Filters/Filter.razor b/src/BootstrapBlazor/Components/Filters/Filter.razor new file mode 100644 index 00000000000..e987fe3ed0b --- /dev/null +++ b/src/BootstrapBlazor/Components/Filters/Filter.razor @@ -0,0 +1,28 @@ +@namespace BootstrapBlazor.Components +@inherits ComponentBase +@typeparam TFilter + +@if (_isHeaderRow) +{ + @RenderFilter() +} +else +{ +
+
@Title
+
+ @RenderFilter() +
+ +
+} diff --git a/src/BootstrapBlazor/Components/Filters/Filter.razor.cs b/src/BootstrapBlazor/Components/Filters/Filter.razor.cs new file mode 100644 index 00000000000..46eaa79235d --- /dev/null +++ b/src/BootstrapBlazor/Components/Filters/Filter.razor.cs @@ -0,0 +1,166 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.Extensions.Localization; + +namespace BootstrapBlazor.Components; + +/// +/// Filter 组件 +/// +public partial class Filter where TFilter : IComponent +{ + /// + /// 获得/设置 过滤器组件参数集合 Default is null + /// + [Parameter] + public IDictionary? FilterParameters { get; set; } + + /// + /// 获得/设置 重置按钮文本 + /// + [Parameter] + [NotNull] + public string? ClearButtonText { get; set; } + + /// + /// 获得/设置 过滤按钮文本 + /// + [Parameter] + [NotNull] + public string? FilterButtonText { get; set; } + + /// + /// 获得/设置 增加过滤条件图标 + /// + [Parameter] + public string? PlusIcon { get; set; } + + /// + /// 获得/设置 减少过滤条件图标 + /// + [Parameter] + public string? MinusIcon { get; set; } + + /// + /// Gets or sets whether show the more button. Default is false. + /// + [Parameter] + public bool ShowMoreButton { get; set; } + + /// + /// Gets or sets the filter title. Default is null. + /// + public string? Title { get; set; } + + [CascadingParameter] + private TableColumnFilter? TableColumnFilter { get; set; } + + [Inject] + [NotNull] + private IStringLocalizer? Localizer { get; set; } + + [Inject] + [NotNull] + private IIconTheme? IconTheme { get; set; } + + private int _count; + private string? _fieldKey; + private bool _isHeaderRow = false; + + /// + /// + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + + PlusIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableFilterPlusIcon); + MinusIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableFilterMinusIcon); + + FilterButtonText ??= Localizer[nameof(FilterButtonText)]; + ClearButtonText ??= Localizer[nameof(ClearButtonText)]; + + Title ??= TableColumnFilter.GetFilterTitle(); + + _isHeaderRow = TableColumnFilter.IsHeaderRow(); + _fieldKey = TableColumnFilter.GetFieldKey(); + } + + /// + /// 点击重置按钮时回调此方法 + /// + /// + private async Task OnClickReset() + { + _count = 0; + if (TableColumnFilter != null) + { + await TableColumnFilter.Reset(); + } + StateHasChanged(); + } + + /// + /// 点击确认时回调此方法 + /// + /// + protected async Task OnClickConfirm() + { + if (TableColumnFilter != null) + { + await TableColumnFilter.OnFilterAsync(); + } + } + + /// + /// 点击增加按钮时回调此方法 + /// + /// + private void OnClickPlus() + { + if (_count == 0) + { + _count++; + } + } + + /// + /// 点击减少按钮时回调此方法 + /// + /// + private void OnClickMinus() + { + if (_count == 1) + { + _count--; + } + } + + /// + /// 渲染自定义过滤器方法 + /// + /// + protected virtual RenderFragment RenderFilter() => builder => + { + var filterType = typeof(TFilter); + builder.OpenComponent(0); + if (filterType.IsSubclassOf(typeof(FilterBase))) + { + builder.AddAttribute(1, nameof(FilterBase.FieldKey), _fieldKey); + builder.AddAttribute(2, nameof(FilterBase.IsHeaderRow), _isHeaderRow); + } + if (filterType.IsSubclassOf(typeof(MultipleFilterBase))) + { + builder.AddAttribute(10, nameof(MultipleFilterBase.Count), _count); + } + + if (FilterParameters != null) + { + builder.AddMultipleAttributes(100, FilterParameters); + } + builder.CloseComponent(); + }; +} diff --git a/src/BootstrapBlazor/Components/Filters/FilterBase.cs b/src/BootstrapBlazor/Components/Filters/FilterBase.cs index 1d91551d046..6dd3345a20c 100644 --- a/src/BootstrapBlazor/Components/Filters/FilterBase.cs +++ b/src/BootstrapBlazor/Components/Filters/FilterBase.cs @@ -3,112 +3,96 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using Microsoft.Extensions.Localization; + namespace BootstrapBlazor.Components; /// -/// 类型过滤器基类 -/// /// +/// 过滤器基类 +/// public abstract class FilterBase : BootstrapModuleComponentBase, IFilterAction { /// - /// - /// - protected string? FilterRowClassString => CssBuilder.Default("filter-row") - .AddClass("active", HasFilter) - .Build(); - - /// - /// + /// 获得/设置 实例 /// - protected virtual FilterLogic Logic { get; set; } + [Inject] + [NotNull] + protected IStringLocalizer? Localizer { get; set; } /// /// 获得/设置 相关 Field 字段名称 /// - protected string? FieldKey { get; set; } - - /// - /// 获得 是否为 HeaderRow 呈现模式 默认为 false - /// - protected bool IsHeaderRow => TableFilter?.IsHeaderRow ?? false; - - /// - /// 获得 当前过滤条件是否激活 - /// - protected bool HasFilter => TableFilter?.HasFilter ?? false; // IsHeaderRow 为真时使用 TableFilter 不为空 - - /// - /// 获得/设置 条件数量 - /// [Parameter] - public int Count { get; set; } + [NotNull] + public string? FieldKey { get; set; } /// - /// 获得/设置 条件候选项 请尽量使用静态数据 避免组件性能损失 + /// 获得/设置 是否为 HeaderRow 模式 默认 false /// [Parameter] - public IEnumerable? Items { get; set; } + public bool IsHeaderRow { get; set; } /// /// 获得/设置 所属 TableFilter 实例 /// - [CascadingParameter] - protected TableFilter? TableFilter { get; set; } + [CascadingParameter, NotNull] + protected TableColumnFilter? TableColumnFilter { get; set; } /// - /// OnInitialized 方法 + /// /// protected override void OnInitialized() { base.OnInitialized(); - if (TableFilter != null) + if (TableColumnFilter != null) { - TableFilter.FilterAction = this; - FieldKey = TableFilter.FieldKey; + TableColumnFilter.FilterAction = this; } } /// - /// 重置过滤条件方法 - /// - public abstract void Reset(); - - /// - /// 获得过滤窗口的所有条件方法 + /// 重置按钮回调方法 /// /// - public abstract FilterKeyValueAction GetFilterConditions(); + protected virtual async Task OnClearFilter() + { + if (TableColumnFilter != null) + { + await TableColumnFilter.Reset(); + } - /// - /// 设置过滤集合方法 - /// - /// - public virtual Task SetFilterConditionsAsync(FilterKeyValueAction filter) => OnFilterValueChanged(); + StateHasChanged(); + } /// /// 过滤按钮回调方法 /// /// - protected async Task OnFilterValueChanged() + protected virtual async Task OnFilterAsync() { - if (TableFilter != null) + if (TableColumnFilter != null) { - await TableFilter.OnFilterAsync(); - StateHasChanged(); + await TableColumnFilter.OnFilterAsync(); } + + StateHasChanged(); } /// - /// 重置按钮回调方法 + /// 重置过滤条件方法 + /// + public abstract void Reset(); + + /// + /// 获得过滤窗口的所有条件方法 /// /// - protected async Task OnClearFilter() - { - if (TableFilter != null) - { - Reset(); - await TableFilter.OnFilterAsync(); - } - } + public abstract FilterKeyValueAction GetFilterConditions(); + + /// + /// 设置过滤集合方法 + /// + /// + public virtual Task SetFilterConditionsAsync(FilterKeyValueAction filter) => OnFilterAsync(); } diff --git a/src/BootstrapBlazor/Components/Filters/FilterKeyValueAction.cs b/src/BootstrapBlazor/Components/Filters/FilterKeyValueAction.cs index fb3c62e2332..6586227bc66 100644 --- a/src/BootstrapBlazor/Components/Filters/FilterKeyValueAction.cs +++ b/src/BootstrapBlazor/Components/Filters/FilterKeyValueAction.cs @@ -37,5 +37,5 @@ public class FilterKeyValueAction /// /// 获得/设置 子过滤条件集合 /// - public List? Filters { get; set; } + public List Filters { get; set; } = []; } diff --git a/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor b/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor index 401e49ec240..b3893c6a648 100644 --- a/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor +++ b/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor @@ -1,3 +1,3 @@ @namespace BootstrapBlazor.Components - + diff --git a/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor.cs b/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor.cs index ed85b4c36f1..90cd4d0729a 100644 --- a/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/FilterLogicItem.razor.cs @@ -8,54 +8,48 @@ namespace BootstrapBlazor.Components; /// -/// +/// FilterLogicItem 组件用于选择过滤条件的逻辑运算符 /// public partial class FilterLogicItem { - private FilterLogic _value; - private FilterLogic Value - { - get - { - _value = Logic; - return _value; - } - set - { - _value = value; - if (LogicChanged.HasDelegate) LogicChanged.InvokeAsync(value); - } - } - /// - /// + /// 获得/设置 逻辑运算符 /// [Parameter] public FilterLogic Logic { get; set; } /// - /// + /// 获得/设置 逻辑运算符改变回调方法 /// [Parameter] public EventCallback LogicChanged { get; set; } - private IEnumerable? Items { get; set; } - [Inject] [NotNull] private IStringLocalizer? Localizer { get; set; } + private readonly List _items = []; + /// - /// + /// /// protected override void OnInitialized() { base.OnInitialized(); - Items = new List() - { + _items.AddRange( + [ new SelectedItem("And",Localizer["And"].Value), new SelectedItem("Or",Localizer["Or"].Value) - }; + ]); + } + + private async Task OnValueChanged(FilterLogic val) + { + Logic = val; + if (LogicChanged.HasDelegate) + { + await LogicChanged.InvokeAsync(Logic); + } } } diff --git a/src/BootstrapBlazor/Components/Filters/IFilterAction.cs b/src/BootstrapBlazor/Components/Filters/IFilterAction.cs index b0e421ac692..c2420aa3dde 100644 --- a/src/BootstrapBlazor/Components/Filters/IFilterAction.cs +++ b/src/BootstrapBlazor/Components/Filters/IFilterAction.cs @@ -14,15 +14,15 @@ namespace BootstrapBlazor.Components; public interface IFilterAction { /// - /// 获得 IFilter 实例中的过滤条件集合 + /// 重置过滤条件方法 /// - /// - FilterKeyValueAction GetFilterConditions(); + void Reset(); /// - /// 重置过滤条件方法 + /// 获得 IFilter 实例中的过滤条件集合 /// - void Reset(); + /// + FilterKeyValueAction GetFilterConditions(); /// /// Override existing filter conditions diff --git a/src/BootstrapBlazor/Components/Filters/LookupFilter.razor b/src/BootstrapBlazor/Components/Filters/LookupFilter.razor index 9d089c46b8e..313f90a1852 100644 --- a/src/BootstrapBlazor/Components/Filters/LookupFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/LookupFilter.razor @@ -1,14 +1,18 @@ @namespace BootstrapBlazor.Components @inherits FilterBase -@if(Items != null) +@if (IsHeaderRow) { - if (IsHeaderRow) - { - - } - else - { - - } + +} +else +{ + } diff --git a/src/BootstrapBlazor/Components/Filters/LookupFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/LookupFilter.razor.cs index c378a3e2f86..28a1228fc16 100644 --- a/src/BootstrapBlazor/Components/Filters/LookupFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/LookupFilter.razor.cs @@ -3,112 +3,32 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.Extensions.Localization; - namespace BootstrapBlazor.Components; /// -/// 枚举类型过滤组件 +/// Lookup 过滤器 /// -public partial class LookupFilter : ILookup +public partial class LookupFilter { - private string? Value { get; set; } - - /// - /// - /// - [Parameter] - public IEnumerable? Lookup { get; set; } - - /// - /// - /// - [Parameter] - public ILookupService? LookupService { get; set; } + private Type _type = null!; + private string? _value; + private bool _isShowSearch; + private ILookup _lookup = null!; /// /// /// - [Parameter] - public string? LookupServiceKey { get; set; } - - /// - /// - /// - [Parameter] - public object? LookupServiceData { get; set; } - - /// - /// - /// - [Parameter] - public StringComparison LookupStringComparison { get; set; } = StringComparison.OrdinalIgnoreCase; - - /// - /// 获得/设置 相关枚举类型 - /// - [EditorRequired] - [Parameter] - [NotNull] - public Type? Type { get; set; } - - /// - /// 获得 是否为 ShowSearch 呈现模式 默认为 false - /// - [Parameter] - public bool IsShowSearch { get; set; } - - /// - /// 获得 是否为 ShowSearch 呈现模式 默认为 false - /// - [Parameter] - [ExcludeFromCodeCoverage] - [Obsolete("已弃用,请删除;Deprecated, please delete")] - public bool IsFixedSearch { get; set; } - - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } - - [Inject] - [NotNull] - private ILookupService? InjectLookupService { get; set; } - - /// - /// - /// - protected override void OnInitialized() - { - base.OnInitialized(); - - if (Type == null) - { - throw new InvalidOperationException("the Parameter Type must be set."); - } - - if (TableFilter != null) - { - TableFilter.ShowMoreButton = false; - } - } - - /// - /// - /// - protected override async Task OnParametersSetAsync() + protected override void OnParametersSet() { - await base.OnParametersSetAsync(); + base.OnParametersSet(); - var items = new List - { - new("", Localizer["EnumFilter.AllText"].Value) - }; - var lookup = await this.GetItemsAsync(InjectLookupService, LookupServiceKey, LookupServiceData); - if (lookup != null) + if (TableColumnFilter != null) { - items.AddRange(lookup); + var column = TableColumnFilter.Column; + _isShowSearch = column.ShowSearchWhenSelect; + _type = column.PropertyType; + _lookup = column; } - Items = items; } /// @@ -116,7 +36,7 @@ protected override async Task OnParametersSetAsync() /// public override void Reset() { - Value = ""; + _value = null; StateHasChanged(); } @@ -126,12 +46,12 @@ public override void Reset() /// public override FilterKeyValueAction GetFilterConditions() { - var filter = new FilterKeyValueAction() { Filters = [] }; - if (!string.IsNullOrEmpty(Value)) + var filter = new FilterKeyValueAction(); + if (!string.IsNullOrEmpty(_value)) { - var type = Nullable.GetUnderlyingType(Type) ?? Type; - var val = Convert.ChangeType(Value, type); - filter.Filters.Add(new FilterKeyValueAction() + var type = Nullable.GetUnderlyingType(_type) ?? _type; + var val = Convert.ChangeType(_value, type); + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, FieldValue = val, @@ -146,15 +66,15 @@ public override FilterKeyValueAction GetFilterConditions() /// public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - var first = filter.Filters?.FirstOrDefault() ?? filter; - var type = Nullable.GetUnderlyingType(Type) ?? Type; + var first = filter.Filters.FirstOrDefault() ?? filter; + var type = Nullable.GetUnderlyingType(_type) ?? _type; if (first.FieldValue != null && first.FieldValue.GetType() == type) { - Value = first.FieldValue.ToString(); + _value = first.FieldValue.ToString(); } else { - Value = ""; + _value = null; } await base.SetFilterConditionsAsync(filter); } diff --git a/src/BootstrapBlazor/Components/Filters/MultiFilter.razor b/src/BootstrapBlazor/Components/Filters/MultiFilter.razor index 96a0e96438a..df3a9cd937a 100644 --- a/src/BootstrapBlazor/Components/Filters/MultiFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/MultiFilter.razor @@ -1,41 +1,48 @@ -@using Microsoft.Extensions.Localization -@namespace BootstrapBlazor.Components +@namespace BootstrapBlazor.Components @inherits FilterBase -@inject IStringLocalizer Localizer @attribute [BootstrapModuleAutoLoader("Filters/MultiFilter.razor.js", JSObjectReference = true)] -
- @if (ShowSearch) - { - - } -
-
- -
-
- @foreach (var item in GetItems()) - { -
- -
- } +@if (IsHeaderRow) +{ + +} +else +{ +
+ @if (ShowSearch) + { + + } +
+
+ +
+
+ @foreach (var item in GetItems()) + { +
+ +
+ } +
+ @if (_source == null) + { +
+ @if (LoadingTemplate != null) + { + @LoadingTemplate + } + else + { + + } +
+ }
- @if (_source == null) - { -
- @if (LoadingTemplate != null) - { - @LoadingTemplate - } - else - { - - } -
- } -
+} diff --git a/src/BootstrapBlazor/Components/Filters/MultiFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/MultiFilter.razor.cs index 9b0af82c035..6062bc8ed4a 100644 --- a/src/BootstrapBlazor/Components/Filters/MultiFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/MultiFilter.razor.cs @@ -6,7 +6,7 @@ namespace BootstrapBlazor.Components; /// -/// 表格过滤菜单组件 +/// 多选过滤器组件 /// public partial class MultiFilter { @@ -53,23 +53,14 @@ public partial class MultiFilter public StringComparison StringComparison { get; set; } = StringComparison.OrdinalIgnoreCase; private string? _searchText; - private List? _source; - private List? _items; /// - /// + /// Gets or sets the filter candidate items. It is recommended to use static data to avoid performance loss. /// - protected override void OnInitialized() - { - base.OnInitialized(); - - if (TableFilter != null) - { - TableFilter.ShowMoreButton = false; - } - } + [Parameter] + public IEnumerable? Items { get; set; } /// /// @@ -89,7 +80,7 @@ protected override void OnParametersSet() if (Items != null) { var selectedItems = _source?.Where(x => x.Active).ToList(); - _source = Items.ToList(); + _source = [.. Items]; ResetActiveItems(_source, selectedItems); } } @@ -117,45 +108,13 @@ protected override async Task InvokeInitAsync() { if (OnGetItemsAsync != null) { - await InvokeVoidAsync("init", Id, new { Invoker = Interop, Callback = nameof(TriggerGetItemsCallback), AlwaysTrigger = AlwaysTriggerGetItems }); - } - } - - /// - /// 重置过滤条件方法 - /// - public override void Reset() - { - _searchText = string.Empty; - if (_source != null) - { - foreach (var item in _source) - { - item.Active = false; - } - } - _items = null; - StateHasChanged(); - } - - /// - /// 生成过滤条件方法 - /// - /// - public override FilterKeyValueAction GetFilterConditions() - { - var filter = new FilterKeyValueAction() { Filters = [], FilterLogic = FilterLogic.Or }; - - foreach (var item in GetItems().Where(i => i.Active)) - { - filter.Filters.Add(new FilterKeyValueAction() + await InvokeVoidAsync("init", Id, new { - FieldKey = FieldKey, - FieldValue = item.Value, - FilterAction = FilterAction.Equal + Invoker = Interop, + Callback = nameof(TriggerGetItemsCallback), + AlwaysTrigger = AlwaysTriggerGetItems }); } - return filter; } /// @@ -244,4 +203,63 @@ private Task OnSearchValueChanged(string? val) } private List GetItems() => _items ?? _source ?? []; + + /// + /// 重置过滤条件方法 + /// + public override void Reset() + { + _searchText = null; + if (_source != null) + { + foreach (var item in _source) + { + item.Active = false; + } + } + _items = null; + StateHasChanged(); + } + + /// + /// 生成过滤条件方法 + /// + /// + public override FilterKeyValueAction GetFilterConditions() + { + var filter = new FilterKeyValueAction { FilterLogic = FilterLogic.Or }; + foreach (var item in GetItems().Where(i => i.Active)) + { + filter.Filters.Add(new FilterKeyValueAction + { + FieldKey = FieldKey, + FieldValue = item.Value, + FilterAction = FilterAction.Equal + }); + } + return filter; + } + + /// + /// + /// + /// + /// + public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) + { + var items = GetItems(); + if (items.Count > 0) + { + foreach (var f in filter.Filters) + { + var val = f.FieldValue?.ToString(); + var item = items.Find(i => i.Value == val); + if (item != null) + { + item.Active = true; + } + } + } + await base.SetFilterConditionsAsync(filter); + } } diff --git a/src/BootstrapBlazor/Components/Filters/MultipleFilterBase.cs b/src/BootstrapBlazor/Components/Filters/MultipleFilterBase.cs new file mode 100644 index 00000000000..637a798c327 --- /dev/null +++ b/src/BootstrapBlazor/Components/Filters/MultipleFilterBase.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +/// +/// 多条件过滤器基类 +/// +public abstract class MultipleFilterBase : FilterBase +{ + /// + /// 获得/设置 条件数量 + /// + [Parameter] + public int Count { get; set; } + + /// + /// 获得/设置 多个条件逻辑关系符号 + /// + protected FilterLogic Logic { get; set; } +} diff --git a/src/BootstrapBlazor/Components/Filters/NumberFilter.razor b/src/BootstrapBlazor/Components/Filters/NumberFilter.razor index cab746c65a2..4ca28e1a2a4 100644 --- a/src/BootstrapBlazor/Components/Filters/NumberFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/NumberFilter.razor @@ -1,47 +1,24 @@ @namespace BootstrapBlazor.Components @typeparam TType -@inherits FilterBase +@inherits MultipleFilterBase @if (IsHeaderRow) {
- @if (typeof(TType).IsNumber()) - { - - } - else - { - - } - + +
} else { - - - @if (typeof(TType).IsNumber()) - { - - } - else - { - - } - + + @if (Count > 0) { - - - - @if (typeof(TType).IsNumber()) - { - - } - else - { - - } + + } } diff --git a/src/BootstrapBlazor/Components/Filters/NumberFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/NumberFilter.razor.cs index c74e30f69cf..f664d801d49 100644 --- a/src/BootstrapBlazor/Components/Filters/NumberFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/NumberFilter.razor.cs @@ -3,32 +3,28 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.Extensions.Localization; - namespace BootstrapBlazor.Components; /// -/// 数字类型过滤条件 +/// NumberFilter 组件 /// public partial class NumberFilter { - private TType? Value1 { get; set; } - - private FilterAction Action1 { get; set; } = FilterAction.GreaterThanOrEqual; - - private TType? Value2 { get; set; } + private TType? _value1; + private FilterAction _action1 = FilterAction.GreaterThanOrEqual; + private TType? _value2; + private FilterAction _action2 = FilterAction.LessThanOrEqual; + private string? _step; - private FilterAction Action2 { get; set; } = FilterAction.LessThanOrEqual; - - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } + private string? FilterRowClassString => CssBuilder.Default("filter-row") + .AddClass("active", TableColumnFilter.HasFilter()) + .Build(); /// - /// 获得/设置 步长 默认 0.01 + /// Gets or sets the filter candidate items. It is recommended to use static data to avoid performance loss. /// [Parameter] - public string Step { get; set; } = "0.01"; + public IEnumerable? Items { get; set; } /// /// @@ -37,15 +33,16 @@ protected override void OnParametersSet() { base.OnParametersSet(); - Items ??= new SelectedItem[] - { - new("GreaterThanOrEqual", Localizer["GreaterThanOrEqual"].Value), - new("LessThanOrEqual", Localizer["LessThanOrEqual"].Value), - new("GreaterThan", Localizer["GreaterThan"].Value), - new("LessThan", Localizer["LessThan"].Value), - new("Equal", Localizer["Equal"].Value), - new("NotEqual", Localizer["NotEqual"].Value) - }; + Items ??= + [ + new SelectedItem("GreaterThanOrEqual", Localizer["GreaterThanOrEqual"].Value), + new SelectedItem("LessThanOrEqual", Localizer["LessThanOrEqual"].Value), + new SelectedItem("GreaterThan", Localizer["GreaterThan"].Value), + new SelectedItem("LessThan", Localizer["LessThan"].Value), + new SelectedItem("Equal", Localizer["Equal"].Value), + new SelectedItem("NotEqual", Localizer["NotEqual"].Value) + ]; + _step = TableColumnFilter?.Column.Step; } /// @@ -53,10 +50,10 @@ protected override void OnParametersSet() /// public override void Reset() { - Value1 = default; - Value2 = default; - Action1 = FilterAction.GreaterThanOrEqual; - Action2 = FilterAction.LessThanOrEqual; + _value1 = default; + _value2 = default; + _action1 = FilterAction.GreaterThanOrEqual; + _action2 = FilterAction.LessThanOrEqual; Count = 0; Logic = FilterLogic.And; StateHasChanged(); @@ -68,24 +65,24 @@ public override void Reset() /// public override FilterKeyValueAction GetFilterConditions() { - var filter = new FilterKeyValueAction() { Filters = [] }; - if (Value1 != null) + var filter = new FilterKeyValueAction(); + if (_value1 != null) { - filter.Filters.Add(new FilterKeyValueAction() + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, - FieldValue = Value1, - FilterAction = Action1 + FieldValue = _value1, + FilterAction = _action1 }); } - if (Count > 0 && Value2 != null) + if (Count > 0 && _value2 != null) { - filter.Filters.Add(new FilterKeyValueAction() + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, - FieldValue = Value2, - FilterAction = Action2, + FieldValue = _value2, + FilterAction = _action2, }); filter.FilterLogic = Logic; } @@ -97,30 +94,30 @@ public override FilterKeyValueAction GetFilterConditions() /// public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - var first = filter.Filters?.FirstOrDefault() ?? filter; + var first = filter.Filters.FirstOrDefault() ?? filter; if (first.FieldValue is TType value) { - Value1 = value; + _value1 = value; } else { - Value1 = default; + _value1 = default; } - Action1 = first.FilterAction; + _action1 = first.FilterAction; - if (filter.Filters != null && filter.Filters.Count == 2) + if (filter.Filters.Count > 1) { Count = 1; FilterKeyValueAction second = filter.Filters[1]; if (second.FieldValue is TType value2) { - Value2 = value2; + _value2 = value2; } else { - Value2 = default; + _value2 = default; } - Action2 = second.FilterAction; + _action2 = second.FilterAction; Logic = filter.FilterLogic; } await base.SetFilterConditionsAsync(filter); diff --git a/src/BootstrapBlazor/Components/Filters/SearchFilterAction.cs b/src/BootstrapBlazor/Components/Filters/SearchFilterAction.cs index 9cb238e7cfe..64a8e534b97 100644 --- a/src/BootstrapBlazor/Components/Filters/SearchFilterAction.cs +++ b/src/BootstrapBlazor/Components/Filters/SearchFilterAction.cs @@ -43,7 +43,7 @@ public void Reset() /// public Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - var first = filter.Filters?.FirstOrDefault() ?? filter; + var first = filter.Filters.FirstOrDefault() ?? filter; if (first.FieldKey == Name) { Value = first.FieldValue; diff --git a/src/BootstrapBlazor/Components/Filters/StringFilter.razor b/src/BootstrapBlazor/Components/Filters/StringFilter.razor index 3084487b92c..9252ea1bb8b 100644 --- a/src/BootstrapBlazor/Components/Filters/StringFilter.razor +++ b/src/BootstrapBlazor/Components/Filters/StringFilter.razor @@ -1,25 +1,21 @@ @namespace BootstrapBlazor.Components -@inherits FilterBase +@inherits MultipleFilterBase @if (IsHeaderRow) {
- - + +
} else { - - - - + + @if (Count > 0) { - - - - + + } } diff --git a/src/BootstrapBlazor/Components/Filters/StringFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/StringFilter.razor.cs index 8e07b5c6b77..6d39ccfff5f 100644 --- a/src/BootstrapBlazor/Components/Filters/StringFilter.razor.cs +++ b/src/BootstrapBlazor/Components/Filters/StringFilter.razor.cs @@ -3,31 +3,37 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone -using Microsoft.Extensions.Localization; - namespace BootstrapBlazor.Components; /// -/// 字符串类型过滤条件 +/// StringFilter 组件 /// public partial class StringFilter { - private string Value1 { get; set; } = ""; - - private FilterAction Action1 { get; set; } = FilterAction.Contains; - - private string Value2 { get; set; } = ""; + /// + /// Gets or sets the filter candidate items. It is recommended to use static data to avoid performance loss. + /// + [Parameter] + public IEnumerable? Items { get; set; } - private FilterAction Action2 { get; set; } = FilterAction.Equal; + private string? _value1; + private FilterAction _action1 = FilterAction.Contains; + private string? _value2; + private FilterAction _action2 = FilterAction.Contains; - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } + private string? FilterRowClassString => CssBuilder.Default("filter-row") + .AddClass("active", TableColumnFilter.HasFilter()) + .Build(); /// /// /// - protected override FilterLogic Logic { get; set; } = FilterLogic.Or; + protected override void OnInitialized() + { + base.OnInitialized(); + + Logic = FilterLogic.Or; + } /// /// @@ -36,13 +42,13 @@ protected override void OnParametersSet() { base.OnParametersSet(); - Items ??= new SelectedItem[] - { - new("Contains", Localizer["Contains"].Value), - new("Equal", Localizer["Equal"].Value), - new("NotEqual", Localizer["NotEqual"].Value), - new("NotContains", Localizer["NotContains"].Value) - }; + Items ??= + [ + new SelectedItem("Contains", Localizer["Contains"].Value), + new SelectedItem("Equal", Localizer["Equal"].Value), + new SelectedItem("NotEqual", Localizer["NotEqual"].Value), + new SelectedItem("NotContains", Localizer["NotContains"].Value) + ]; } /// @@ -50,10 +56,10 @@ protected override void OnParametersSet() /// public override void Reset() { - Value1 = ""; - Value2 = ""; - Action1 = FilterAction.Contains; - Action2 = FilterAction.Contains; + _value1 = null; + _value2 = null; + _action1 = FilterAction.Contains; + _action2 = FilterAction.Contains; Logic = FilterLogic.Or; Count = 0; StateHasChanged(); @@ -65,24 +71,24 @@ public override void Reset() /// public override FilterKeyValueAction GetFilterConditions() { - var filter = new FilterKeyValueAction() { Filters = [] }; - if (!string.IsNullOrEmpty(Value1)) + var filter = new FilterKeyValueAction(); + if (!string.IsNullOrEmpty(_value1)) { - filter.Filters.Add(new FilterKeyValueAction() + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, - FieldValue = Value1, - FilterAction = Action1 + FieldValue = _value1, + FilterAction = _action1 }); } - if (Count > 0 && !string.IsNullOrEmpty(Value2)) + if (Count > 0 && !string.IsNullOrEmpty(_value2)) { - filter.Filters.Add(new FilterKeyValueAction() + filter.Filters.Add(new FilterKeyValueAction { FieldKey = FieldKey, - FieldValue = Value2, - FilterAction = Action2, + FieldValue = _value2, + FilterAction = _action2, }); filter.FilterLogic = Logic; } @@ -94,30 +100,30 @@ public override FilterKeyValueAction GetFilterConditions() /// public override async Task SetFilterConditionsAsync(FilterKeyValueAction filter) { - FilterKeyValueAction first = filter.Filters?.FirstOrDefault() ?? filter; + FilterKeyValueAction first = filter.Filters.FirstOrDefault() ?? filter; if (first.FieldValue is string value) { - Value1 = value; + _value1 = value; } else { - Value1 = ""; + _value1 = null; } - Action1 = first.FilterAction; + _action1 = first.FilterAction; - if (filter.Filters != null && filter.Filters.Count == 2) + if (filter.Filters.Count > 1) { Count = 1; FilterKeyValueAction second = filter.Filters[1]; if (second.FieldValue is string value2) { - Value2 = value2; + _value2 = value2; } else { - Value2 = ""; + _value2 = null; } - Action2 = second.FilterAction; + _action2 = second.FilterAction; Logic = second.FilterLogic; } await base.SetFilterConditionsAsync(filter); diff --git a/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor b/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor new file mode 100644 index 00000000000..35e63ed3615 --- /dev/null +++ b/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor @@ -0,0 +1,75 @@ +@namespace BootstrapBlazor.Components +@inherits BootstrapModuleComponentBase +@attribute [BootstrapModuleAutoLoader("Filters/TableColumnFilter.razor.js")] + +@if (IsHeaderRow) +{ + @RenderFilter(Column) +} +else +{ + + + + @RenderFilter(Column) + +} + +@code { + RenderFragment RenderFilter => Column => + @ + @if (Column.FilterTemplate != null) + { + @Column.FilterTemplate + } + else + { + @if (Column.PropertyType.IsEnum()) + { + + } + else if (Column.IsLookup()) + { + + } + else + { + var fieldType = Nullable.GetUnderlyingType(Column.PropertyType) ?? Column.PropertyType; + switch (fieldType.Name) + { + case nameof(String): + + break; + case nameof(Boolean): + + break; + case nameof(DateTime): + + break; + case nameof(Int16): + + break; + case nameof(Int32): + + break; + case nameof(Int64): + + break; + case nameof(Single): + + break; + case nameof(Double): + + break; + case nameof(Decimal): + + break; + default: +
@NotSupportedMessage
+ break; + } + } + } +
; +} diff --git a/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.cs new file mode 100644 index 00000000000..d0d6238c524 --- /dev/null +++ b/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.Extensions.Localization; + +namespace BootstrapBlazor.Components; + +/// +/// TableFilter component +/// +public partial class TableColumnFilter : IFilter +{ + /// + /// 获得/设置 是否 active + /// + [Parameter] + public bool IsActive { get; set; } + + /// + /// 获得/设置 过滤图标 + /// + [Parameter] + public string? Icon { get; set; } + + /// + /// 获得/设置 不支持过滤类型提示信息 默认 null 读取资源文件内容 + /// + [Parameter] + public string? NotSupportedMessage { get; set; } + + /// + /// 获得 相关联 ITableColumn 实例 + /// + [Parameter] + [NotNull] + public ITableColumn? Column { get; set; } + + /// + /// 获得/设置 是否为 HeaderRow 模式 默认 false + /// + [Parameter] + public bool IsHeaderRow { get; set; } + + /// + /// 获得/设置 ITable 实例 + /// + [Parameter] + [NotNull] + public ITable? Table { get; set; } + + [Inject] + [NotNull] + private IStringLocalizer? Localizer { get; set; } + + /// + /// 获得 过滤小图标样式 + /// + private string? FilterClassString => CssBuilder.Default(Icon) + .AddClass("active", IsActive) + .Build(); + + /// + /// 获得 样式 + /// + private string? ClassString => CssBuilder.Default("filter-icon") + .AddClassFromAttributes(AdditionalAttributes) + .Build(); + + /// + /// 获得/设置 过滤条件 IFilterAction 接口 + /// + [NotNull] + public IFilterAction? FilterAction { get; set; } + + private string _fieldKey = ""; + + /// + /// + /// + protected override void OnInitialized() + { + base.OnInitialized(); + + Column.Filter = this; + _fieldKey = Column.GetFieldName(); + } + + /// + /// + /// + protected override void OnParametersSet() + { + base.OnParametersSet(); + + NotSupportedMessage ??= Localizer[nameof(NotSupportedMessage)]; + } + + /// + /// + /// + /// + protected override async Task InvokeInitAsync() + { + if (!IsHeaderRow) + { + await base.InvokeInitAsync(); + } + } + + /// + /// Reset filter method + /// + public async Task Reset() + { + FilterAction.Reset(); + await OnFilterAsync(); + } + + /// + /// Filter method + /// + /// + public async Task OnFilterAsync() + { + if (Table.OnFilterAsync == null) + { + return; + } + + var action = FilterAction.GetFilterConditions(); + if (action.Filters.Count > 0) + { + Table.Filters[_fieldKey] = FilterAction; + } + else + { + Table.Filters.Remove(_fieldKey); + } + + await Table.OnFilterAsync(); + } +} diff --git a/src/BootstrapBlazor/Components/Filters/TableFilter.razor.js b/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.js similarity index 100% rename from src/BootstrapBlazor/Components/Filters/TableFilter.razor.js rename to src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.js diff --git a/src/BootstrapBlazor/Components/Filters/TableFilter.razor.scss b/src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.scss similarity index 100% rename from src/BootstrapBlazor/Components/Filters/TableFilter.razor.scss rename to src/BootstrapBlazor/Components/Filters/TableColumnFilter.razor.scss diff --git a/src/BootstrapBlazor/Components/Filters/TableFilter.razor b/src/BootstrapBlazor/Components/Filters/TableFilter.razor deleted file mode 100644 index ec94e845dbf..00000000000 --- a/src/BootstrapBlazor/Components/Filters/TableFilter.razor +++ /dev/null @@ -1,91 +0,0 @@ -@namespace BootstrapBlazor.Components -@inherits BootstrapModuleComponentBase -@attribute [BootstrapModuleAutoLoader("Filters/TableFilter.razor.js")] - -@if (IsHeaderRow) -{ - @RenderFilter(Column) -} -else -{ - - - -
-
@_title
-
- @RenderFilter(Column) -
- -
-
-} - -@code { - RenderFragment RenderFilter => Column => - @ - @if (Column.FilterTemplate != null) - { - @Column.FilterTemplate - } - else if (Column.PropertyType.IsEnum()) - { - - } - else if (Column.IsLookup()) - { - - } - else - { - var fieldType = Nullable.GetUnderlyingType(Column.PropertyType) ?? Column.PropertyType; - switch (fieldType.Name) - { - case nameof(Boolean): - - break; - case nameof(DateTime): - - break; - case nameof(Int16): - - break; - case nameof(Int32): - - break; - case nameof(Int64): - - break; - case nameof(Single): - - break; - case nameof(Double): - - break; - case nameof(Decimal): - - break; - case nameof(String): - - break; - default: -
@NotSupportedMessage
- break; - }; - } -
; -} diff --git a/src/BootstrapBlazor/Components/Filters/TableFilter.razor.cs b/src/BootstrapBlazor/Components/Filters/TableFilter.razor.cs deleted file mode 100644 index 66d99990879..00000000000 --- a/src/BootstrapBlazor/Components/Filters/TableFilter.razor.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using Microsoft.Extensions.Localization; - -namespace BootstrapBlazor.Components; - -/// -/// TableFilter 基类 -/// -public partial class TableFilter : IFilter -{ - /// - /// 获得 过滤小图标样式 - /// - private string? FilterClassString => CssBuilder.Default(Icon) - .AddClass("active", IsActive) - .Build(); - - /// - /// 获得 样式 - /// - private string? ClassString => CssBuilder.Default("filter-icon") - .AddClassFromAttributes(AdditionalAttributes) - .Build(); - - /// - /// 获得/设置 是否 active - /// - [Parameter] - public bool IsActive { get; set; } - - /// - /// 获得/设置 过滤图标 - /// - [Parameter] - public string? Icon { get; set; } - - /// - /// 获得/设置 增加过滤条件图标 - /// - [Parameter] - public string? PlusIcon { get; set; } - - /// - /// 获得/设置 减少过滤条件图标 - /// - [Parameter] - public string? MinusIcon { get; set; } - - /// - /// 获得/设置 不支持过滤类型提示信息 默认 null 读取资源文件内容 - /// - [Parameter] - public string? NotSupportedMessage { get; set; } - - /// - /// 获得/设置 Header 显示文字 - /// - private string? _title; - - /// - /// 获得/设置 相关 Field 字段名称 - /// - [NotNull] - internal string? FieldKey { get; set; } - - /// - /// 获得/设置 条件数量 - /// - private int _count; - - /// - /// 获得/设置 是否显示增加减少条件按钮 - /// - public bool ShowMoreButton { get; set; } = true; - - /// - /// 获得/设置 过滤条件 IFilterAction 接口 - /// - [NotNull] - public IFilterAction? FilterAction { get; set; } - - /// - /// 获得 当前过滤条件是否激活 - /// - internal bool HasFilter => (Table != null) && Table.Filters.ContainsKey(Column.GetFieldName()); - - /// - /// 获得 相关联 ITableColumn 实例 - /// - [Parameter] - [NotNull] - [EditorRequired] - public ITableColumn? Column { get; set; } - - /// - /// 重置按钮文本 - /// - [Parameter] - [NotNull] - public string? ClearButtonText { get; set; } - - /// - /// 获得/设置 是否为 HeaderRow 模式 默认 false - /// - [Parameter] - public bool IsHeaderRow { get; set; } - - /// - /// 过滤按钮文本 - /// - [Parameter] - [NotNull] - public string? FilterButtonText { get; set; } - - /// - /// 获得/设置 ITable 实例 - /// - [Parameter] - public ITable? Table { get; set; } - - [Inject] - [NotNull] - private IStringLocalizer? Localizer { get; set; } - - [Inject] - [NotNull] - private IIconTheme? IconTheme { get; set; } - - /// - /// 组件步长 - /// - private string? _step; - - /// - /// - /// - protected override void OnInitialized() - { - base.OnInitialized(); - - _title = Column.GetDisplayName(); - FieldKey = Column.GetFieldName(); - Column.Filter = this; - _step = Column.Step; - } - - /// - /// - /// - protected override void OnParametersSet() - { - base.OnParametersSet(); - - FilterButtonText ??= Localizer[nameof(FilterButtonText)]; - ClearButtonText ??= Localizer[nameof(ClearButtonText)]; - NotSupportedMessage ??= Localizer[nameof(NotSupportedMessage)]; - - PlusIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableFilterPlusIcon); - MinusIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableFilterMinusIcon); - - if (Table != null && Table.Filters.TryGetValue(Column.GetFieldName(), out var action)) - { - var filter = action.GetFilterConditions(); - if (filter.Filters?.Count > 1) - { - _count = 1; - } - } - } - - /// - /// - /// - /// - protected override async Task InvokeInitAsync() - { - if (!IsHeaderRow) - { - await base.InvokeInitAsync(); - } - } - - /// - /// 点击重置按钮时回调此方法 - /// - /// - private async Task OnClickReset() - { - _count = 0; - - if (Table != null) - { - Table.Filters.Remove(FieldKey); - FilterAction.Reset(); - if (Table.OnFilterAsync != null) - { - await Table.OnFilterAsync(); - } - } - } - - /// - /// 点击确认时回调此方法 - /// - /// - private Task OnClickConfirm() => OnFilterAsync(); - - /// - /// 过滤数据方法 - /// - /// - internal async Task OnFilterAsync() - { - if (Table != null) - { - var f = FilterAction.GetFilterConditions(); - if (f.Filters != null && f.Filters.Count > 0) - { - Table.Filters[FieldKey] = FilterAction; - } - else - { - Table.Filters.Remove(FieldKey); - } - if (Table.OnFilterAsync != null) - { - await Table.OnFilterAsync(); - } - } - } - - /// - /// 点击增加按钮时回调此方法 - /// - /// - private void OnClickPlus() - { - if (_count == 0) - { - _count++; - } - } - - /// - /// 点击减少按钮时回调此方法 - /// - /// - private void OnClickMinus() - { - if (_count == 1) - { - _count--; - } - } -} diff --git a/src/BootstrapBlazor/Components/QueryBuilder/GroupFilterKeyValueAction.cs b/src/BootstrapBlazor/Components/QueryBuilder/GroupFilterKeyValueAction.cs new file mode 100644 index 00000000000..c2e2c49f1ec --- /dev/null +++ b/src/BootstrapBlazor/Components/QueryBuilder/GroupFilterKeyValueAction.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +class GroupFilterKeyValueAction : FilterKeyValueAction +{ + public GroupFilterKeyValueAction() + { + FilterLogic = FilterLogic.Or; + } +} diff --git a/src/BootstrapBlazor/Components/QueryBuilder/QueryBuilder.razor b/src/BootstrapBlazor/Components/QueryBuilder/QueryBuilder.razor index 1bb183833ce..eaaa8491fb8 100644 --- a/src/BootstrapBlazor/Components/QueryBuilder/QueryBuilder.razor +++ b/src/BootstrapBlazor/Components/QueryBuilder/QueryBuilder.razor @@ -6,7 +6,7 @@ @ChildContent?.Invoke(new TModel()) - @if (!Value.HasFilters() && ShowHeader) + @if (ShowHeader && Value.Filters.Count == 0) { @RenderHeader(null, Value) } @@ -17,6 +17,29 @@
@code { + RenderFragment RenderFilters(FilterKeyValueAction? parent, FilterKeyValueAction filter) => + @
    + @if (IsShowHeader(filter)) + { +
  • + @RenderHeader(parent, filter) +
  • + } + @foreach (var f in filter.Filters) + { +
  • + @if (IsGroup(f)) + { + @RenderFilters(filter, f) + } + else + { + @RenderFilter(filter, f) + } +
  • + } +
; + RenderFragment RenderFilter(FilterKeyValueAction parent, FilterKeyValueAction filter) => @