
Table 表格
常用于单表维护,通过属性配置实现简单的增、删、改、查、排序、过滤、搜索等常用功能,通过 Template
的高级用法能实现非常复杂的业务需求功能
具有搜索功能的表格
设置 ShowSearch
显示查询组件,通过设置 SearchTemplate
模板自定义搜索 UI
Demo
Loading...
自动生成搜索功能的表格
当设置了 ShowSearch
时,如果未设置 SearchTemplate
编辑模板时,组件会尝试自动生成搜索条件 UI
Demo
列信息绑定时通过设置 Searchable
属性,设置搜索条件自动构建 UI
if (options.Searchs.Any())
{
// 逻辑关系使用 FilterLogic.Or
items = items.Where(options.Searchs.GetFilterFunc<Foo>(FilterLogic.Or));
}
Loading...
自定义列搜索模板
当设置了 SearchTemplate
时,组件自动生成搜索 UI 时使用此模板作为呈现 UI
Demo
通过设置姓名列的 SearchTemplate
自定义编辑时使用下拉框来选择姓名
由于是搜索条件,本例中姓名搜索列下拉框增加了 请选择... 项
生成列搜索模板是查找顺序为 SearchTemplate -> AutoGenerate 优先查找是否设置了搜索模板,然后根据绑定字段类型自动生成
Loading...
@page "/tables/search"
<h3>Table 表格</h3>
<h4>常用于单表维护,通过属性配置实现简单的增、删、改、查、排序、过滤、搜索等常用功能,通过 <code>Template</code> 的高级用法能实现非常复杂的业务需求功能</h4>
<Block Title="具有搜索功能的表格" Introduction="设置 <code>ShowSearch</code> 显示查询组件,通过设置 <code>SearchTemplate</code> 模板自定义搜索 UI">
<Table TItem="Foo"
IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true"
ShowToolbar="true" ShowSearch="true" IsMultipleSelect="true" ShowExtendButtons="true"
AddModalTitle="增加测试数据窗口" EditModalTitle="编辑测试数据窗口"
SearchModel="@SearchModel"
OnQueryAsync="@OnQueryAsync" OnResetSearchAsync="@OnResetSearchAsync"
OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" />
<TableColumn @bind-Field="@context.Address" />
<TableColumn @bind-Field="@context.Education" />
</TableColumns>
<SearchTemplate>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<BootstrapInput @bind-Value="@context.Name" placeholder="不可为空,50字以内" maxlength="50" ShowLabel="true" DisplayText="@Localizer[nameof(context.Name)]" />
</div>
<div class="form-group col-12 col-sm-6">
<BootstrapInput @bind-Value="@context.Address" placeholder="不可为空,50字以内" maxlength="50" ShowLabel="true" DisplayText="@Localizer[nameof(context.Address)]" />
</div>
</div>
</div>
</SearchTemplate>
</Table>
</Block>
<Block Title="自动生成搜索功能的表格" Introduction="当设置了 <code>ShowSearch</code> 时,如果未设置 <code>SearchTemplate</code> 编辑模板时,组件会尝试自动生成搜索条件 UI">
<p>列信息绑定时通过设置 <code>Searchable</code> 属性,设置搜索条件自动构建 UI</p>
<Tips>
<p>自动构建搜索弹窗时,由于各列设置 <code>Searchable</code> 此时组件会通过 <code>SearchText</code> 与设置 <code>Searchable</code> 值为 <code>true</code> 的各列自动构建搜索拉姆达表达式,通过 <code>QueryPageOptions</code> 的属性 <code>Searchs</code> 获得</p>
</Tips>
<Pre>if (options.Searchs.Any())
{
// 逻辑关系使用 FilterLogic.Or
items = items.Where(options.Searchs.GetFilterFunc<Foo>(FilterLogic.Or));
}</Pre>
<Table TItem="Foo"
IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true" SearchModel="@SearchModel" ShowSearch="true"
ShowToolbar="true" IsMultipleSelect="true" ShowExtendButtons="true"
AddModalTitle="增加测试数据窗口" EditModalTitle="编辑测试数据窗口"
OnQueryAsync="@OnQueryAsync"
OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" Searchable="true" />
<TableColumn @bind-Field="@context.Address" Searchable="true" />
<TableColumn @bind-Field="@context.Education" />
</TableColumns>
</Table>
</Block>
<Block Title="自定义列搜索模板" Introduction="当设置了 <code>SearchTemplate</code> 时,组件自动生成搜索 UI 时使用此模板作为呈现 UI">
<p>通过设置姓名列的 <code>SearchTemplate</code> 自定义编辑时使用下拉框来选择姓名</p>
<p>由于是搜索条件,本例中姓名搜索列下拉框增加了 请选择... 项</p>
<p>生成列搜索模板是查找顺序为 SearchTemplate -> AutoGenerate 优先查找是否设置了搜索模板,然后根据绑定字段类型自动生成</p>
<Table TItem="Foo"
IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true" SearchModel="@SearchModel" ShowSearch="true"
ShowToolbar="true" IsMultipleSelect="true" ShowExtendButtons="true"
AddModalTitle="增加测试数据窗口" EditModalTitle="编辑测试数据窗口"
OnQueryAsync="@OnQueryAsync"
OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" Searchable="true">
<SearchTemplate Context="value">
@{
var model = value as Foo;
if (model != null)
{
var items = new List<SelectedItem>()
{
new SelectedItem { Text = "请选择 ...", Value = "" },
new SelectedItem { Text = "姓名1", Value = "姓名1" },
new SelectedItem { Text = "姓名2", Value = "姓名2" },
};
<div class="form-group col-12 col-sm-6">
<Select Items="items" @bind-Value="@model.Name" ShowLabel="true" DisplayText="姓名" />
</div>
}
}
</SearchTemplate>
</TableColumn>
<TableColumn @bind-Field="@context.Address" Searchable="true" />
<TableColumn @bind-Field="@context.Education" />
</TableColumns>
</Table>
</Block>
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages.Table
{
/// <summary>
/// Table 组件搜索示例代码
/// </summary>
public sealed partial class TablesSearch
{
private static readonly ConcurrentDictionary<Type, Func<IEnumerable<Foo>, string, SortOrder, IEnumerable<Foo>>> SortLambdaCache = new();
[Inject]
[NotNull]
private IStringLocalizer<Foo>? Localizer { get; set; }
private Foo SearchModel { get; set; } = new Foo();
private static IEnumerable<int> PageItemsSource => new int[] { 4, 10, 20 };
[NotNull]
private List<Foo>? Items { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Items = FooExtensions.GenerateFoo(Localizer);
}
private static Task<Foo> OnAddAsync() => Task.FromResult(new Foo() { DateTime = DateTime.Now });
private Task<bool> OnSaveAsync(Foo item)
{
// 增加数据演示代码
if (item.Id == 0)
{
item.Id = Items.Max(i => i.Id) + 1;
Items.Add(item);
}
else
{
var oldItem = Items.FirstOrDefault(i => i.Id == item.Id);
if (oldItem != null)
{
oldItem.Name = item.Name;
oldItem.Address = item.Address;
oldItem.DateTime = item.DateTime;
oldItem.Count = item.Count;
oldItem.Complete = item.Complete;
oldItem.Education = item.Education;
}
}
return Task.FromResult(true);
}
private Task<bool> OnDeleteAsync(IEnumerable<Foo> items)
{
items.ToList().ForEach(i => Items.Remove(i));
return Task.FromResult(true);
}
private static Task OnResetSearchAsync(Foo item)
{
item.Name = "";
item.Address = "";
return Task.CompletedTask;
}
private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
{
IEnumerable<Foo> items = Items;
// 处理高级搜索
if (!string.IsNullOrEmpty(SearchModel.Name))
{
items = items.Where(item => item.Name?.Contains(SearchModel.Name, StringComparison.OrdinalIgnoreCase) ?? false);
}
if (!string.IsNullOrEmpty(SearchModel.Address))
{
items = items.Where(item => item.Address?.Contains(SearchModel.Address, StringComparison.OrdinalIgnoreCase) ?? false);
}
// 处理 Searchable=true 列与 SeachText 模糊搜索
if (options.Searchs.Any())
{
items = items.Where(options.Searchs.GetFilterFunc<Foo>(FilterLogic.Or));
}
else
{
// 处理 SearchText 模糊搜索
if (!string.IsNullOrEmpty(options.SearchText))
{
items = items.Where(item => (item.Name?.Contains(options.SearchText) ?? false)
|| (item.Address?.Contains(options.SearchText) ?? false));
}
}
// 过滤
var isFiltered = false;
if (options.Filters.Any())
{
items = items.Where(options.Filters.GetFilterFunc<Foo>());
isFiltered = true;
}
// 排序
var isSorted = false;
if (!string.IsNullOrEmpty(options.SortName))
{
var invoker = SortLambdaCache.GetOrAdd(typeof(Foo), key => LambdaExtensions.GetSortLambda<Foo>().Compile());
items = invoker(items, options.SortName, options.SortOrder);
isSorted = true;
}
// 设置记录总数
var total = items.Count();
// 内存分页
items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList();
return Task.FromResult(new QueryData<Foo>()
{
Items = items,
TotalCount = total,
IsSorted = isSorted,
IsFiltered = isFiltered,
IsSearch = !string.IsNullOrEmpty(SearchModel.Name) || !string.IsNullOrEmpty(SearchModel.Address)
});
}
}
}