feat(Table): add IsKeepSelectedRows parameter

* Merge remote-tracking branch 'origin/main' into dev-feature
* Merge branch 'dev-feature' of gitee.com:ljmay168/BootstrapBlazor into …
* 新增保持选择行时翻页的单元测试
* Merge branch 'dev-feature' of gitee.com:ljmay168/BootstrapBlazor into …
* 修正IsKeepSelectedRows属性注释错误
* Merge branch 'dev-feature' of gitee.com:ljmay168/BootstrapBlazor into …
* Table组件新增参数IsKeepSelectedRows,让用户决定是否保持表格的选中行,并在翻页后恢复选中行状态。
* Merge branch 'dev-feature' of gitee.com:ljmay168/BootstrapBlazor into …
* aaa
* Merge branch 'dev-feature' of gitee.com:ljmay168/BootstrapBlazor into …
* * fix: 修复Table组件数据加载功能在明细行包含Table组件时显示错误的bug
This commit is contained in:
ljmay168 2023-12-05 06:23:50 +00:00 committed by Argo
parent 9d90abe60b
commit 244c704167
6 changed files with 127 additions and 7 deletions

View File

@ -9,7 +9,11 @@
Introduction="@Localizer["TablesSelectionNormalIntro"]"
Name="Normal">
<div>
<Table TItem="Foo" @bind-SelectedRows="SelectedItems"
<div class="d-flex gap-5">
<div>保持选中行状态: <Switch @bind-Value="IsKeepSelectedRows" OnText="保持" OffText="不保持" class="d-inline" /></div>
<div>选中的行数:@SelectedItems.Count</div>
</div>
<Table TItem="Foo" @bind-SelectedRows="SelectedItems" IsKeepSelectedRows="IsKeepSelectedRows"
IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true" IsMultipleSelect="true"
ShowToolbar="true" ShowDefaultButtons="false" OnQueryAsync="@OnQueryAsync">

View File

@ -19,6 +19,9 @@ public partial class TablesSelection
[NotNull]
private List<Foo>? SelectedItems { get; set; }
private bool IsKeepSelectedRows;
private static IEnumerable<int> PageItemsSource => new int[]
{
4,

View File

@ -18,6 +18,26 @@ public partial class Table<TItem>
.AddClass(HeaderStyle.ToDescriptionString(), HeaderStyle != TableHeaderStyle.None)
.Build();
/// <summary>
/// <para>是否保持选择行,默认为否。</para>
/// 最少要有一种行对比的回落机制,否则重新获取数据后无法还原选中状态。
/// <para>保持行状态回落机制(优先级从高到低):</para>
/// <list type="number">
/// <item>
/// <term>ModelEqualityComparer</term>
/// </item>
/// <item>
/// <term>CustomKeyAttribute</term>
/// </item>
/// <item>
/// <term>IEqualityComparer&lt;TItem> Equals 重载方法</term>
/// </item>
/// </list>
/// </summary>
[Parameter]
public bool IsKeepSelectedRows { get; set; } = false;
/// <summary>
/// 获得 表头行是否选中状态
/// </summary>
@ -95,14 +115,16 @@ public partial class Table<TItem>
{
case CheckboxState.Checked:
// select all
SelectedRows.Clear();
SelectedRows.RemoveAll(x => Rows.Any(a => Equals(a, x)));
SelectedRows.AddRange(ShowRowCheckboxCallback == null ? Rows : Rows.Where(ShowRowCheckboxCallback));
await OnSelectedRowsChanged();
break;
case CheckboxState.UnChecked:
default:
// unselect all
SelectedRows.Clear();
SelectedRows.RemoveAll(x => Rows.Any(a => Equals(a, x)));
await OnSelectedRowsChanged();
break;
}

View File

@ -451,8 +451,11 @@ public partial class Table<TItem>
IsAdvanceSearch = queryData.IsAdvanceSearch;
QueryItems = queryData.Items ?? Enumerable.Empty<TItem>();
// 处理选中行逻辑
ResetSelectedRows(QueryItems);
if (!IsKeepSelectedRows)
{
// 处理选中行逻辑
ResetSelectedRows(QueryItems);
}
// 分页情况下内部不做处理防止页码错乱
ProcessData();

View File

@ -139,8 +139,11 @@ public partial class Table<TItem>
{
PageIndex = pageIndex;
// 清空选中行
SelectedRows.Clear();
if (!IsKeepSelectedRows)
{
// 清空选中行
SelectedRows.Clear();
}
// 无刷新查询数据
await QueryAsync(false);

View File

@ -4129,6 +4129,91 @@ public class TableTest : TableTestBase
Assert.Empty(checkboxs);
}
[Fact]
public async Task KeepSelectedRows_Ok()
{
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
var Items = Foo.GenerateFoo(localizer, 6);
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
{
pb.AddChildContent<Table<Foo>>(pb =>
{
pb.Add(a => a.RenderMode, TableRenderMode.Table);
pb.Add(a => a.IsMultipleSelect, true);
pb.Add(a => a.IsPagination, true);
pb.Add(a => a.IsKeepSelectedRows, true);
pb.Add(a => a.PageItemsSource, new int[] { 2 });
pb.Add(a => a.OnQueryAsync, options =>
{
var total = Items.Count;
var items = Items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList();
return Task.FromResult(new QueryData<Foo>() { Items = items, TotalCount = total, IsSorted = true, IsFiltered = true, IsSearch = true });
});
pb.Add(a => a.TableColumns, foo => builder =>
{
builder.OpenComponent<TableColumn<Foo, string>>(0);
builder.AddAttribute(1, "Field", "Name");
builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string)));
builder.CloseComponent();
});
});
});
var btn = cut.Find("tbody tr td input");
await cut.InvokeAsync(() => btn.Click());
var checkboxs = cut.FindAll(".is-checked");
Assert.Single(checkboxs);
//点击下页按钮翻页
var nextBtn = cut.Find(".fa-angle-right");
await cut.InvokeAsync(() => nextBtn.Click());
//选中行数为空
checkboxs = cut.FindAll(".is-checked");
Assert.Empty(checkboxs);
//点击下页按钮翻页
await cut.InvokeAsync(() => nextBtn.Click());
//点击表头CheckBox
btn = cut.Find("thead tr th input");
await cut.InvokeAsync(() => btn.Click());
//加上表头的复选框选中结果有3项
checkboxs = cut.FindAll(".is-checked");
Assert.Equal(3, checkboxs?.Count);
//点击向前按钮翻页
var prevBtn = cut.Find("i.fa-angle-left");
await cut.InvokeAsync(() => prevBtn.Click());
//恢复选中行数为0
checkboxs = cut.FindAll(".is-checked");
Assert.Empty(checkboxs);
//点击向前按钮翻页
await cut.InvokeAsync(() => prevBtn.Click());
//恢复选中行数为1
checkboxs = cut.FindAll(".is-checked");
Assert.Single(checkboxs);
//点击向后翻页按钮
await cut.InvokeAsync(() => nextBtn.Click());
//恢复选中行数为0
checkboxs = cut.FindAll(".is-checked");
Assert.Empty(checkboxs);
//点击向后翻页按钮
await cut.InvokeAsync(() => nextBtn.Click());
//恢复选中行数为2加上表头的复选框选中结果有3项
checkboxs = cut.FindAll(".is-checked");
Assert.Equal(3, checkboxs?.Count);
}
[Fact]
public void TableColumn_Ok()
{