知识点:

1.导入导出

2.分页功能

3.增删改查

4.批量删除

5.批量编辑(审核)

6.列排序与列搜索

7.顶部搜索实现所有列搜索

8.高级搜索实现多条件搜索

9.顶部与刷新与视图列

10.实现文本类型明细行

11.列的统计

12.隐藏列,时间日期列格式化

13.新窗口打开

14.随机数据

15.自由编辑

16.清空数据

17.模板下载

截图

基础工程

表格组件导出 Excel Word Html Pdf

注入FreeSqlDataService服务,支持全数据导出

更新包

<PackageReference Include="BootstrapBlazor" Version="7.2.3-beta03" />
<PackageReference Include="Densen.FreeSql.Extensions.BootstrapBlazor" Version="7.*" />

Program.cs 添加代码

using Densen.DataAcces.FreeSql;
builder.Services.AddSingleton(typeof(FreeSqlDataService<>));
builder.Services.ConfigureJsonLocalizationOptions(op =>
{
// 忽略文化信息丢失日志
op.IgnoreLocalizerMissing = true;
});

Index.razor添加一个 TabItem

Tab 顺便改为懒加载

<Tab IsLazyLoadTabItem="true">
...
<TabItem Text="综合演示">
<ImpExpIII />
</TabItem>
</Tab>

添加打印预览 Pages\_Host.cshtml

< / body > 前加一句

    <script>
function printDiv() {
window.print();
}
</script>

数据实体类 Data\SalesChannels.cs

查看代码

```
using BootstrapBlazor.Components;
using DocumentFormat.OpenXml.Wordprocessing;
using FreeSql.DataAnnotations;
using Magicodes.ExporterAndImporter.Excel;
using OfficeOpenXml.Table;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace b14table.Data;

[ExcelImporter(IsLabelingError = true)]

[ExcelExporter(Name = "导入商品中间表", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]

[AutoGenerateClass(Searchable = true, Filterable = true, Sortable = true, ShowTips = true)]

public class SalesChannels

{

[AutoGenerateColumn(Ignore = true)]

[Column(IsIdentity = true)]

[DisplayName("序号")]

public int ID { get; set; }

[AutoGenerateColumn(ComponentType = typeof(ColorPicker), Width = 30)]
[DisplayName("级别")]
public string? Background { get; set; } [AutoGenerateColumn(FormatString = "yyyy-MM-dd")]
[DisplayName("日期")]
public DateTime Date { get; set; } [Required(ErrorMessage = "{0}不能为空")]
[DisplayName("名称")]
public string? Name { get; set; } [DisplayName("项目数量")]
public int Projects { get; set; } [DisplayName("交单数量")]
public int Orders { get; set; } [DisplayName("结单数量")]
public int Checkouts { get; set; } // 编辑界面无法显示小数, 以后再思考
[DisplayName("结单率")]
[AutoGenerateColumn(Readonly = true)]
public string? CheckoutRates { get => GetCheckoutRates(Checkouts, Orders); set => checkoutRates = value; }
string? checkoutRates; [DisplayName("合格数量")]
public int Qualifieds { get; set; } [DisplayName("合格率")]
[AutoGenerateColumn(Readonly = true)]
public string? QualifiedRates { get => GetQualifiedRates(Qualifieds, Checkouts); set => qualifiedRates = value; }
string? qualifiedRates; [DisplayName("总价值")]
public int Total { get; set; } [DisplayName("应收款")]
public int Receivables { get; set; } [DisplayName("已收款")]
public int Received { get; set; } [AutoGenerateColumn(FormatString = "HH:mm:ss")]
[DisplayName("修改日期")]
public DateTime ModifiedDate { get; set; } = DateTime.Now; [AutoGenerateColumn(TextEllipsis = true, Visible = false, ShowTips = true, ComponentType = typeof(Textarea))]
[DisplayName("备注")]
public string? Remark { get; set; } [AutoGenerateColumn(Visible = false, ComponentType = typeof(BootstrapInput<decimal>), Width = 80)]
[DisplayName("Test1")]
public decimal Test1 { get; set; } private string GetCheckoutRates(int checkouts, int orders) => orders > 0 ? (checkouts /(double) orders).ToString("P2") : "0%"; private string GetQualifiedRates(int qualifieds, int checkouts) => checkouts > 0 ? (qualifieds / (double)checkouts).ToString("P2") : "0%";

}

</details>

### 页面 `Pages\ImpExpIII.razor`

<details>
<summary>查看代码</summary>

@page "/impexpiii"

@using b14table.Data

@using static Blazor100.Service.ImportExportsService

综合演示

<SearchTemplate>
<GroupBox Title="搜索">
<div class="row g-3 form-inline">
<div class="col-12 col-sm-6">
<BootstrapInput @bind-Value="@context.Name" maxlength="50" ShowLabel="true" />
</div>
<div class="col-12 col-sm-6">
<BootstrapInput @bind-Value="@context.Date" maxlength="500" ShowLabel="true" />
</div>
</div>
</GroupBox>
</SearchTemplate> <DetailRowTemplate>
<div>备注: @context.Remark </div>
</DetailRowTemplate> <TableFooter Context="context1"> <TableFooterCell Text="当前页小计:" colspan="4" />
<TableFooterCell Text="总价值" colspan="3" />
<TableFooterCell Aggregate="@Aggregate" Field="@nameof(SalesChannels.Total)" /> <TableFooterCell Text="应收款" colspan="3" />
<TableFooterCell Aggregate="@Aggregate" Field="@nameof(SalesChannels.Receivables)" /> <TableFooterCell Text="已收款" colspan="3" />
<TableFooterCell Aggregate="@Aggregate" Field="@nameof(SalesChannels.Received)" /> </TableFooter> <TableToolbarTemplate>
<TableToolbarButton TItem="SalesChannels" Color="Color.Primary" Text="自由编辑" OnClick="@IsExcelToggle" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Warning" Text="随机数据" IsAsync OnClick="@GetDatasAsync" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Secondary" Text="导入" IsAsync OnClick="@ImportExcel" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Danger" Text="清空" IsAsync OnClick="EmptyAll" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Success" Text="模板" IsAsync OnClick="Export模板Async" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Success" Text="打印" IsAsync OnClickCallback="@PrintPreview" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Secondary" Text="新窗口打开" IsAsync OnClick="@新窗口打开" />
<TableToolbarButton TItem="SalesChannels" Color="Color.Secondary" Text="批量审批" IsAsync OnClickCallback="@批量审批" />
</TableToolbarTemplate> <ExportButtonDropdownTemplate>
<h6 class="dropdown-header">当前页数据</h6>
<div class="dropdown-item" @onclick="_=>ExportExcelAsync(list1.Rows)">
<i class="fas fa-file-excel"></i>
<span>Excel</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportWordAsync(list1.Rows)">
<i class="fas fa-file-word"></i>
<span>Word</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportHtmlAsync(list1.Rows)">
<i class="fa-brands fa-html5"></i>
<span>Html</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportPDFAsync(list1.Rows)">
<i class="fas fa-file-pdf"></i>
<span>PDF</span>
</div>
<div class="dropdown-divider"></div>
<h6 class="dropdown-header">全部数据</h6>
<div class="dropdown-item" @onclick="_=>ExportExcelAsync(DataService.GetAllItems())">
<i class="fas fa-file-excel"></i>
<span>Excel</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportWordAsync(DataService.GetAllItems())">
<i class="fas fa-file-word"></i>
<span>Word</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportHtmlAsync(DataService.GetAllItems())">
<i class="fa-brands fa-html5"></i>
<span>Html</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportPDFAsync(DataService.GetAllItems())">
<i class="fas fa-file-pdf"></i>
<span>PDF</span>
</div>
</ExportButtonDropdownTemplate>

```

页面代码 Pages\ImpExpIII.razor

查看代码

```
using AmeBlazor.Components;
using b14table.Data;
using Blazor100.Service;
using BootstrapBlazor.Components;
using Densen.DataAcces.FreeSql;
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
using System.Diagnostics.CodeAnalysis;
using static Blazor100.Service.ImportExportsService;

namespace b14table.Pages

{

public partial class ImpExpIII

{

    [Inject]
IWebHostEnvironment? HostEnvironment { get; set; } [Inject]
[NotNull]
NavigationManager? NavigationManager { get; set; } [Inject]
[NotNull]
ImportExportsService? ImportExportsService { get; set; } [Inject]
[NotNull]
ToastService? ToastService { get; set; } [Inject]
[NotNull]
FreeSqlDataService<SalesChannels>? DataService { get; set; } [NotNull]
Table<SalesChannels>? list1 { get; set; } [Parameter] public int Footercolspan1 { get; set; } = 3; [Parameter] public int Footercolspan2 { get; set; } = 2; [Parameter] public int Footercolspan3 { get; set; } [Parameter] public int FootercolspanTotal { get; set; } = 2; [Parameter] public string? FooterText { get; set; } = "合计:"; [Parameter] public string? FooterText2 { get; set; } [Parameter] public string? FooterText3 { get; set; } [Parameter] public string? FooterTotal { get; set; } /// <summary>
/// 获得/设置 IJSRuntime 实例
/// </summary>
[Inject]
[NotNull]
protected IJSRuntime? JsRuntime { get; set; }
[Parameter] public string? 新窗口打开Url { get; set; } = "https://localhost:7292/"; // 由于使用了FreeSql ORM 数据服务,可以直接取对象
[Inject]
[NotNull]
IFreeSql? fsql { get; set; } [Inject] ToastService? toastService { get; set; }
[Inject] SwalService? SwalService { get; set; } public bool IsExcel { get; set; }
public bool DoubleClickToEdit { get; set; } = true;
protected string UploadPath = "";
protected string? uploadstatus;
long maxFileSize = 1024 * 1024 * 15;
string? tempfilename; private AggregateType Aggregate { get; set; } protected async Task GetDatasAsync()
{
var datas = GetDemoDatas();
await fsql.Insert<SalesChannels>().AppendData(datas).ExecuteAffrowsAsync();
await list1!.QueryAsync();
} protected override async void OnAfterRender(bool firstRender)
{
if (firstRender)
{
UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "uploads");
if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath);
await list1!.QueryAsync();
}
} protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//懒的人,直接初始化一些数据用用
var res = fsql.Select<SalesChannels>().Count();
if (res == 0)
{
var datas = GetDemoDatas();
await fsql.Insert<SalesChannels>().AppendData(datas).ExecuteAffrowsAsync();
await list1!.QueryAsync();
}
}
} public List<SalesChannels> GetDemoDatas()
{ var list = new List<SalesChannels>();
for (int i = 0; i < 100; i++)
{
try
{
var total = Random.Shared.Next(100, 3000);
list.Add(new SalesChannels()
{
ID = i,
Name = "渠道" + i,
Date = DateTime.Now,
Projects = Random.Shared.Next(10, 55),
Orders = Random.Shared.Next(3, 10),
Qualifieds = i,
Total = total,
Receivables = total - i,
Received = i,
Remark= $"{i} 明细行内嵌套另外一个 Table 组件,由于每行都要关联子表数据,出于性能的考虑,此功能采用 懒加载 模式,即点击展开按钮后,再对嵌套 Table 进行数据填充,通过 ShowDetailRow 回调委托可以控制每一行是否显示明细行,本例中通过 Complete 属性来控制是否显示明细行,可通过翻页来测试本功能"
}); }
catch (Exception e)
{
System.Console.WriteLine(e.Message);
}
}
return list; } private Task IsExcelToggle()
{
IsExcel = !IsExcel;
DoubleClickToEdit = !IsExcel;
StateHasChanged();
return Task.CompletedTask;
} public async Task<bool> Export模板Async()
{
await Export();
return true;
} private async Task<bool> ExportExcelAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Excel);
private async Task<bool> ExportPDFAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Pdf);
private async Task<bool> ExportWordAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Word);
private async Task<bool> ExportHtmlAsync(IEnumerable<SalesChannels> items) => await ExportAutoAsync(items, ExportType.Html); private async Task<bool> ExportAutoAsync(IEnumerable<SalesChannels> items, ExportType exportType = ExportType.Excel)
{
if (items == null || !items.Any())
{
await ToastService.Error("提示", "无数据可导出");
return false;
}
var option = new ToastOption()
{
Category = ToastCategory.Information,
Title = "提示",
Content = $"导出正在执行,请稍等片刻...",
IsAutoHide = false
};
// 弹出 Toast
await ToastService.Show(option);
await Task.Delay(100); // 开启后台进程进行数据处理
await Export(items?.ToList(), exportType); // 关闭 option 相关联的弹窗
option.Close(); // 弹窗告知下载完毕
await ToastService.Show(new ToastOption()
{
Category = ToastCategory.Success,
Title = "提示",
Content = $"导出成功,请检查数据",
IsAutoHide = false
});
return true; } private async Task Export(List<SalesChannels>? items = null, ExportType exportType = ExportType.Excel)
{
try
{
if (items == null || !items.Any())
{
ToastService?.Error($"导出", $"{exportType}出错,无数据可导出");
return;
}
var fileName = items == null ? "模板" : typeof(SalesChannels).Name;
var fullName = Path.Combine(UploadPath, fileName);
fullName = await ImportExportsService.Export(fullName, items, exportType);
fileName = (new System.IO.FileInfo(fullName)).Name;
ToastService?.Success("提示", fileName + "已生成"); //下载后清除文件
NavigationManager.NavigateTo($"uploads/{fileName}", true);
_ = Task.Run(() =>
{
Thread.Sleep(50000);
System.IO.File.Delete(fullName);
}); }
catch (Exception e)
{
ToastService?.Error($"导出", $"{exportType}出错,请检查. {e.Message}");
}
} public async Task<bool> EmptyAll()
{
fsql.Delete<SalesChannels>().Where(a => 1 == 1).ExecuteAffrows();
await ToastService!.Show(new ToastOption()
{
Category = ToastCategory.Success,
Title = "提示",
Content = "已清空数据",
}); await list1!.QueryAsync();
return true;
}
private async Task ImportExcel()
{
if (string.IsNullOrEmpty(tempfilename))
{
ToastService?.Error("提示", "请正确选择文件上传");
return;
}
var option = new ToastOption()
{
Category = ToastCategory.Information,
Title = "提示",
Content = "导入文件中,请稍等片刻...",
IsAutoHide = false
};
// 弹出 Toast
await ToastService!.Show(option);
await Task.Delay(100); // 开启后台进程进行数据处理
var isSuccess = await MockImportExcel(); // 关闭 option 相关联的弹窗
option.Close(); // 弹窗告知下载完毕
await ToastService.Show(new ToastOption()
{
Category = isSuccess ? ToastCategory.Success : ToastCategory.Error,
Title = "提示",
Content = isSuccess ? "操作成功,请检查数据" : "出现错误,请重试导入或者上传",
IsAutoHide = false
}); await list1!.QueryAsync();
}
private async Task<bool> MockImportExcel()
{
var items_temp = await ImportExportsService!.ImportFormExcel<SalesChannels>(tempfilename!);
if (items_temp.items == null)
{
ToastService?.Error("提示", "文件导入失败: " + items_temp.error);
return false;
}
//items = SmartCombine(items_temp, items).ToList(); 新数据和老数据合并处理,略100字
await fsql.Insert<SalesChannels>().AppendData(items_temp!.items.ToList()).ExecuteAffrowsAsync();
return true;
} protected async Task OnChange(InputFileChangeEventArgs e)
{
if (e.File == null) return;
tempfilename = Path.Combine(UploadPath, e.File.Name);
await using FileStream fs = new(tempfilename, FileMode.Create);
using var stream = e.File.OpenReadStream(maxFileSize);
await stream.CopyToAsync(fs); //正式工程此处是回调,简化版必须InvokeAsync一下,自由发挥
_ = Task.Run(async () => await InvokeAsync(async () => await ImportExcel())); } /// <summary>
/// 导出数据方法
/// </summary>
/// <param name="Items"></param>
/// <param name="opt"></param>
/// <returns></returns>
protected async Task<bool> ExportAsync(IEnumerable<SalesChannels> Items, QueryPageOptions opt)
{
var ret = await ExportExcelAsync(Items);
return ret;
} public Task PrintPreview(IEnumerable<SalesChannels> item)
{
//实际工程自己完善js打印
JsRuntime.InvokeVoidAsync("printDiv");
return Task.CompletedTask;
} private Task 新窗口打开()
{
if (string.IsNullOrEmpty(新窗口打开Url))
{
ToastService?.Error("提示", "Url为空!");
return Task.CompletedTask;
}
JsRuntime.NavigateToNewTab(新窗口打开Url);
return Task.CompletedTask;
} public async Task 批量审批(IEnumerable<SalesChannels> items)
{
items.ToList().ForEach(a =>
{
a.Checkouts = a.Orders;
a.Receivables = 0;
a.Received = a.Total;
a.ModifiedDate = DateTime.Now;
});
var res = await fsql.Update<SalesChannels>().SetSource(items).ExecuteAffrowsAsync(); await SwalService!.Show(new SwalOption()
{
Title = res == 0 ? "提示: 操作失败" : "提示: 操作成功" });
if (res != 0) await list1!.QueryAsync(); } }

}

</details>

### 预览

![输入图片说明](https://foruda.gitee.com/images/1673727731911583102/38d46153_125049.gif "QQ录屏2023011421sss1106 (1).gif")

### 源代码

https://github.com/densen2014/Blazor100/tree/master/b04table

https://gitee.com/densen2014/Blazor100/tree/master/b04table

[硬核] Bootstrap Blazor Table 综合演示例子的更多相关文章

  1. Bootstrap Blazor Table 组件(二)

    原文链接:https://www.cnblogs.com/ysmc/p/16128206.html 很多小伙伴在使用 Bootstrap Blazor Table组件的时候,都会有这样的一个需求: 我 ...

  2. Bootstrap Blazor Table 组件(四)自定义列生成

    原文链接:https://www.cnblogs.com/ysmc/p/16223154.html Bootstrap Blazor 官方链接:https://www.blazor.zone/tabl ...

  3. Bootstrap Blazor Table 组件(三)智能生成

    原文链接:https://www.cnblogs.com/ysmc/p/16201153.html Bootstrap Blazor 官网地址:https://www.blazor.zone 有了解过 ...

  4. Bootstrap Blazor 组件介绍 Table (一)自动生成列功能介绍

    Bootstrap Blazor 是一套企业级 UI 组件库,适配移动端支持各种主流浏览器,已经在多个交付项目中使用.通过本套组件可以大大缩短开发周期,节约开发成本.目前已经开发.封装了 70 多个组 ...

  5. Bootstrap Blazor 组件介绍 Table (二)自定义模板列功能介绍

    Bootstrap Blazor 是一套企业级 UI 组件库,适配移动端支持各种主流浏览器,已经在多个交付项目中使用.通过本套组件可以大大缩短开发周期,节约开发成本.目前已经开发.封装了 70 多个组 ...

  6. Bootstrap Blazor 组件介绍 Table (三)列数据格式功能介绍

    Bootstrap Blazor 是一套企业级 UI 组件库,适配移动端支持各种主流浏览器,已经在多个交付项目中使用.通过本套组件可以大大缩短开发周期,节约开发成本.目前已经开发.封装了 70 多个组 ...

  7. bootstrap table 服务器端分页例子分享

    这篇文章主要介绍了bootstrap table 服务器端分页例子分享,需要的朋友可以参考下 1,前台引入所需的js 可以从官网上下载 复制代码代码如下: function getTab(){var ...

  8. Bootstrap Blazor 开源UI库介绍-Table 虚拟滚动行

    今天我们来介绍一下 Bootstrap Blazor 中 Table 组件的虚拟滚动行,什么是虚拟滚动呢,我查到的解释是:只渲染可视区域的列表项,非可见区域的 完全不渲染,在滚动条滚动时动态更新列表项 ...

  9. 重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用

    欢迎关注公众号:bin的技术小屋 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以 ...

  10. [转]bootstrap的table插件动态加载表头

    原文地址:https://blog.csdn.net/abubu123/article/details/78060321 bootstrap的table属性已经很熟悉了,最近遇到一个问题,犹豫每个列表 ...

随机推荐

  1. 齐博x1.2万能参数配置接口

    为何叫做万能参数接口,那是因为可以随意设置后台哪些字段可以给接口使用,还可以无限的新增接口参数,这个参数不仅仅是一个开关或文字,还可以是一张图片.一组图片.一组菜单.一个视频地址等等,非常的灵活. h ...

  2. 齐博x1{:get_user_money(2,$uid)}

    第一項是積分類型,第二項是用戶的UID, 在模板中用得最多的可能是 {:get_user_money(2,$uid)} 以管理員身份登錄後,在前台任何頁麵,隻要添加了標簽,雙擊就可以進入設置管理,如果 ...

  3. grpc中的拦截器

    0.1.索引 https://waterflow.link/articles/1665853719750 当我们编写 HTTP 应用程序时,您可以使用 HTTP 中间件包装特定于路由的应用程序处理程序 ...

  4. 7 步保障 Kubernetes 集群安全

    随着 Kubernetes 的发展和改进,新的安全威胁和风险也逐渐向 K8s 转移,因此 K8s 安全性变得越来越重要,而保护 K8s 集群已成为 DevOps 团队不容忽视的重要任务.K8s 有多种 ...

  5. 浅尝 ECDHE 协议流程

    前言 ECDHE 我之前是听都没听过, 但是新业务需要对前后端通信进行加密, 经过大佬推荐才知道有这个东西, 经过几天的学习和踩坑, 才大致明白其流程和使用方式. 过程坎坷, 好在最后还是成功运用到了 ...

  6. debian如何删除无效的应用图标

    1.看/usr/share/applications下是否有xxx.desktop 2.可以到-/.local/share/applications下看是否有xxx.desktop 来源:https: ...

  7. ubuntu 输入法IBUS 输入不成功问题

    ubuntu 输入法IBUS 输入不成功问题 只需要在 输入如下代码 -Xms128m -Xmx750m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMark ...

  8. Oracle收集统计信息的一些思考

    一.问题 Oracle在收集统计信息时默认的采样比例是DBMS_STATS.AUTO_SAMPLE_SIZE,那么AUTO_SAMPLE_SIZE的值具体是多少? 假设采样比例为10%,那么在计算单个 ...

  9. 2022春每日一题:Day 21

    题目:[SCOI2007]降雨量 这题比较坑,分几种情况,但是可以总起来说,分开写,两个月份都没出现,maybe,否则如果两个月份都大于[l+1,r-1]的最大值,如果两个月份差值=r-l输出,tru ...

  10. (工具) 性能测试基准软件 lmBench (待补充)

    1. lmBench 介绍 Lmbench是一套简易,可移植的,符合ANSI/C标准为UNIX/POSIX而制定的微型测评工具.一般来说,它衡量两个关键特征:反应时间和带宽.Lmbench旨在使系统开 ...