10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf
上篇: Bootstrap Blazor 实战 通用导入导出服务(Table组件)
1.新建工程
新建工程b14table
dotnet new blazorserver -o b14table
将项目添加到解决方案中:
dotnet sln add b14table/b14table.csproj
使用 nuget.org 进行 BootstrapBlazor 组件安装, FreeSql sqlite库,字体 ..
dotnet add b03sqlite package BootstrapBlazor
dotnet add b03sqlite package BootstrapBlazor.FontAwesome
dotnet add b03sqlite package FreeSql.Provider.Sqlite
dotnet add b03sqlite Densen.Extensions.BootstrapBlazor
dotnet add b03sqlite package Densen.FreeSql.Extensions.BootstrapBlazor
dotnet add b03sqlite package Magicodes.IE.Core
dotnet add b03sqlite package Magicodes.IE.Excel
dotnet add b03sqlite package Magicodes.IE.Html
dotnet add b03sqlite package Magicodes.IE.Pdf
dotnet add b03sqlite package Magicodes.IE.Word
dotnet add b03sqlite package HtmlToOpenXml.dll
dotnet add b03sqlite package Haukcode.WkHtmlToPdfDotNet
[可选]BootstrapBlazor官方BootstrapBlazor.DataAcces.FreeSql包替换Densen.FreeSql.Extensions.BootstrapBlazor
2.样式表和Javascript 引用
增加主题样式表到 Pages/_Host.cshtml
文件中
删除 <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
并在下面添加两行
<link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet">
<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
添加 Javascript 引用到 Pages/_Layout.cshtml
文件中
在 <script src="_framework/blazor.server.js"></script>
之前添加
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js" asp-append-version="true"></script>
完整文件
@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace b14table.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<!-- 删掉这行 <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> !-->
<link href="css/site.css" rel="stylesheet" />
<!-- 添加下面两行 !-->
<link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet">
<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
<!-- 添加上面两行 !-->
<link href="b14table.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss"></a>
</div>
<!-- 增加这行 !-->
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
3.添加增加命名空间引用到 _Imports.razor
文件中
其中 AME.Services 和 Blazor100.Service 命名空间稍后文件里用到
@using BootstrapBlazor.Components
@using AME.Services
@using Blazor100.Service
@using System.Diagnostics.CodeAnalysis
4.增加 BootstrapBlazorRoot 组件到 App.razor 文件中
<BootstrapBlazorRoot>
<Router AppAssembly="@typeof(App).Assembly">
...
</Router>
</BootstrapBlazorRoot>
5.添加 BootstrapBlazor服务/ FreeSql 数据服务/ ImportExportsService 导出服务 到 Program.cs
文件中
在 builder.Services.AddSingleton<WeatherForecastService>();
后加入
builder.Services.AddFreeSql(option =>
{
option.UseConnectionString(FreeSql.DataType.Sqlite, "Data Source=test.db;") //也可以写到配置文件中
#if DEBUG
//开发环境:自动同步实体
.UseAutoSyncStructure(true)
.UseNoneCommandParameter(true)
//调试sql语句输出
.UseMonitorCommand(cmd => System.Console.WriteLine(cmd.CommandText))
#endif
;
});
builder.Services.AddTransient<ImportExportsService>();
//不写这句因为下面一句扩展包含了 //builder.Services.AddBootstrapBlazor();
builder.Services.AddDensenExtensions();
6. 导出服务 Service/ImportExportsService.cs
using BootstrapBlazor.Components;
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.ExporterAndImporter.Html;
using Magicodes.ExporterAndImporter.Pdf;
using Magicodes.ExporterAndImporter.Word;
namespace Blazor100.Service
{
/// <summary>
/// 通用导入导出服务类
/// </summary>
public class ImportExportsService
{
public enum ExportType
{
Excel,
Pdf,
Word,
Html
}
public async Task<string> Export<T>(string filePath, List<T>? items = null, ExportType exportType = ExportType.Excel) where T : class, new()
{
switch (exportType)
{
case ExportType.Pdf:
var exporterPdf = new PdfExporter();
items = items ?? new List<T>();
var resultPdf = await exporterPdf.ExportListByTemplate(filePath + ".pdf", items);
return resultPdf.FileName;
case ExportType.Word:
var exporterWord = new WordExporter();
items = items ?? new List<T>();
var resultWord = await exporterWord.ExportListByTemplate(filePath + ".docx", items);
return resultWord.FileName;
case ExportType.Html:
var exporterHtml = new HtmlExporter();
items = items ?? new List<T>();
var resultHtml = await exporterHtml.ExportListByTemplate(filePath + ".html", items);
return resultHtml.FileName;
default:
IExporter exporter = new ExcelExporter();
items = items ?? new List<T>();
var result = await exporter.Export(filePath + ".xlsx", items);
return result.FileName;
}
}
public async Task<(IEnumerable<T>? items,string error)> ImportFormExcel<T>(string filePath) where T : class, new()
{
IExcelImporter Importer = new ExcelImporter();
var import = await Importer.Import<T>(filePath);
if (import.Data == null )
{
return (null, import.Exception.Message);
}
return (import.Data!.ToList(),"");
}
}
}
7. 数据实体类 Data/WeatherForecast.cs
using BootstrapBlazor.Components;
using FreeSql.DataAnnotations;
using Magicodes.ExporterAndImporter.Excel;
using OfficeOpenXml.Table;
using System.ComponentModel;
namespace b14table.Data;
[ExcelImporter(IsLabelingError = true)]
[ExcelExporter(Name = "导入商品中间表", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
[AutoGenerateClass(Searchable = true, Filterable = true, Sortable = true)]
public class WeatherForecast
{
[Column(IsIdentity = true)]
[DisplayName("序号")]
public int ID { get; set; }
[DisplayName("日期")]
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
8. 界面和代码 Pages/Index.razor
@page "/"
@using b14table.Data
<PageTitle>Index</PageTitle>
<Tab>
<TabItem Text="导入导出">
<ImpExpII />
</TabItem>
<TabItem Text="数据维护">
<Table TItem="WeatherForecast"
IsPagination="true"
IsStriped="true"
IsBordered="true"
AutoGenerateColumns="true"
ShowSearch="true"
ShowToolbar="true"
ShowExtendButtons="true"
DoubleClickToEdit=true
ShowColumnList=true
ShowCardView=true>
</Table>
@code{
// 由于使用了FreeSql ORM 数据服务,可以直接取对象
[Inject] IFreeSql? fsql { get; set; }
[Inject] ToastService? toastService { get; set; }
//用演示服务的数据初始化数据库
[Inject] WeatherForecastService? ForecastService { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//懒的人,直接初始化一些数据用用
var res = fsql!.Select<WeatherForecast>().Count();
if (res == 0)
{
var forecasts = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();
fsql.Insert<WeatherForecast>().AppendData(forecasts).ExecuteAffrows();
}
}
}
}
</TabItem>
</Tab>
9. 界面和代码 Pages/ImpExpII.razor
@page "/impexpii"
@using b14table.Data
@using static Blazor100.Service.ImportExportsService
<PageTitle>导入导出II</PageTitle>
<InputFile OnChange="OnChange" style="max-width:400px" class="form-control" />
<br/>
<Table @ref="list1"
TItem="WeatherForecast"
IsPagination="true"
IsStriped="true"
IsBordered="true"
AutoGenerateColumns="true"
ShowSearch="true"
ShowToolbar="true"
ShowExtendButtons="true"
DataService="LazyHeroDataService"
OnSaveAsync="LazyHeroDataService!.SaveAsync"
OnDeleteAsync="LazyHeroDataService.DeleteAsync"
DoubleClickToEdit="@DoubleClickToEdit"
IsExcel="@IsExcel"
ScrollingDialogContent="true"
EditDialogIsDraggable="true"
EditDialogSize="Size.ExtraLarge"
EditDialogShowMaximizeButton="true"
ShowExportButton
OnExportAsync="ExportAsync"
PageItemsSource="new int[] {5, 20, 50, 100, 200, 500, 1000 }">
<TableToolbarTemplate>
<TableToolbarButton TItem="WeatherForecast" Color="Color.Primary" Text="自由编辑" OnClick="@IsExcelToggle" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Warning" Text="随机数据" IsAsync OnClick="@GetDatasAsync" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Secondary" Text="导入" IsAsync OnClick="@ImportExcel" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Danger" Text="清空" IsAsync OnClick="EmptyAll" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Success" Text="模板" IsAsync OnClick="Export模板Async" />
</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(LazyHeroDataService!.Items)">
<i class="fas fa-file-excel"></i>
<span>Excel</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportWordAsync(LazyHeroDataService!.Items)">
<i class="fas fa-file-word"></i>
<span>Word</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportHtmlAsync(LazyHeroDataService!.Items)">
<i class="fa-brands fa-html5"></i>
<span>Html</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportPDFAsync(LazyHeroDataService!.Items)">
<i class="fas fa-file-pdf"></i>
<span>PDF</span>
</div>
</ExportButtonDropdownTemplate>
</Table>
@code{
[Inject]
Microsoft.AspNetCore.Hosting.IWebHostEnvironment? HostEnvironment { get; set; }
[Inject]
[NotNull]
NavigationManager? NavigationManager { get; set; }
[Inject]
[NotNull]
ImportExportsService? ImportExportsService { get; set; }
[Inject]
[NotNull]
ToastService? ToastService { get; set; }
[Inject]
WeatherForecastService? ForecastService { get; set; }
[Inject]
[NotNull]
LazyHeroDataService<WeatherForecast>? LazyHeroDataService { get; set; }
[NotNull]
Table<WeatherForecast>? list1 { 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;
protected async Task GetDatasAsync()
{
LazyHeroDataService!.Items = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();
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 GetDatasAsync();
}
}
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<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Excel);
private async Task<bool> ExportPDFAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Pdf);
private async Task<bool> ExportWordAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Word);
private async Task<bool> ExportHtmlAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Html);
private async Task<bool> ExportAutoAsync(IEnumerable<WeatherForecast> items, ExportType exportType = ExportType.Excel)
{
if ((items == null || !items.Any()) && (LazyHeroDataService!.Items == null || !LazyHeroDataService!.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<WeatherForecast>? items=null, ExportType exportType = ExportType.Excel)
{
try
{
if (items==null || !items.Any()) items = LazyHeroDataService!.Items;
var fileName = items == null ? "模板" : typeof(WeatherForecast).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()
{
LazyHeroDataService!.Items = new List<WeatherForecast>();
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<WeatherForecast>(tempfilename!);
if (items_temp.items == null)
{
ToastService?.Error("提示", "文件导入失败: "+ items_temp.error);
return false;
}
//items = SmartCombine(items_temp, items).ToList(); 新数据和老数据合并处理,略100字
LazyHeroDataService!.Items = items_temp!.items.ToList();
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<WeatherForecast> Items, QueryPageOptions opt)
{
var ret = false;
ret = await ExportExcelAsync(Items);
return ret;
}
}
项目源码
关联项目
FreeSql QQ群:4336577(已满)、8578575(已满)、52508226(在线)
BA & Blazor QQ群:795206915、675147445
知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。
AlexChow
今日头条 | 博客园 | 知乎 | Gitee | GitHub
10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf的更多相关文章
- 将页面中表格数据导出excel格式的文件(vue)
近期由于项目需要,需要将页面中的表格数据导出excel格式的文件,折腾了许久,在网上各种百度,虽然资料不少,但是大都不全,踩了许多坑,总算是皇天不负有心人,最后圆满解决了. 1.安装相关依赖(npm安 ...
- 【Bootstrap】 bootstrap-table表格组件
[Bootstrap-table] 顾名思义,这个组件专注于bootstrap风格的表格的设计,并且提供了很多表格的基础和进阶的功能,给我们开发前端的表格省下很多力气. 本文主要参考这位博主的系列文章 ...
- Vue项目中将table组件导出Excel表格以及打印页面内容
体验更优排版请移步原文:http://blog.kwin.wang/programming/vue-table-export-excel-and-print.html 页面中显示的table表格,经常 ...
- Vue+element UI实现表格数据导出Excel组件
介绍 这是一个可以将页面中的表格数据导出为Excel文件的功能组件,该组件一般与表格一起使用,将表格数据传给组件,然后通过点击组件按钮可将表格中的数据导出成Excel文件. 使用方法 由于封装该组件内 ...
- 前端表格数据导出excel
使用tableExport.js导出bootstrap-table表格成excel并且支持中文 1. 下载tableExport.js https://github.com/hhurz/tableEx ...
- 关于调用office com组件导出Excel
服务器环境: 环境为win2008 r2,系统为64位,程序是C#的winform.因为需要处理数据,然后生成Excel,耗时太长,就使用了多线程.winform程序是由计划任务启动,每天晚上去跑. ...
- C# 关于调用office com组件导出Excel
服务器环境: 环境为win2008 r2,系统为64位,程序是C#的winform.因为需要处理数据,然后生成Excel,耗时太长,就使用了多线程.winform程序是由计划任务启动,每天晚上去跑. ...
- 网页表格导入导出Excel
用JS实现网页表格数据导入导出excel. 首先是JS文件中的代码 (function($){ function getRows(target){ var state = $(target).data ...
- 前端 vue表格数据导出Excel 文件实现
实现思路 使用json2csv将后台json数据转化为csv格式数据 采用创建Blob(二进制大对象)的方式来存放缓存数据: 生成下载链接: 创建一个a标签,设置href和download属性 触发a ...
- C#调用NPOI组件导出Excel表格
把一个List集合的数据导出到Excel表格中 public static string RenderToExcel<T>(List<T> datas) { MemoryStr ...
随机推荐
- List接口中的常用方法
void add(int index, Object ele):在index位置插入ele元素boolean addAll(int index, Collection eles):从index位置开始 ...
- Dubbo 03: 直连式 + 接口工程
进一步改正dubbo框架中简单的直连式的不足 需要用到3个相互独立的maven工程,项目1为maven的java工程作为接口工程,项目2,3为maven的web工程 工程1:o3-link-inter ...
- 银行ATM存取款系统(C语言实现)
这里使用的运行工具是DEV C++.老铁们一定要看仔细了.是DEV C++ 仅供借鉴:这个是大一时期写的.大四的时候整理了一下(本人C语言学的也不太好).肯定很多不足和存在漏洞的地方.仅供借鉴.仅供借 ...
- sql面试50题------(11-20)
文章目录 11.查询至少有一门课与学号为'01'的学生所学课程相同的学生的学号和姓名 12.查询和'01'号同学所学课程完全相同的其他同学的学号 13.查询两门及其以上不及格课程的同学的学号,姓名及其 ...
- 快速创建软件安装包-ClickOnce
大家好,我是沙漠尽头的狼. .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台. 今天介绍使用ClickOnce制作软件安装包,首先我们先了解什么是ClickOne. 1. 什么是Click ...
- 一个超经典 WinForm 卡死问题的再反思
一:背景 1.讲故事 这篇文章起源于昨天的一位朋友发给我的dump文件,说它的程序出现了卡死,看了下程序的主线程栈,居然又碰到了 OnUserPreferenceChanged 导致的挂死问题,真的是 ...
- nginx安装及相关操作
工作中经常用到nginx,今天写个自动部署nginx的脚本.nginx版本选用:1.20.2 1.创建nginx安装脚本(nginx.sh) [root@iZ2ze7uphtapcv51egcm7rZ ...
- Springboot实现验证码登录
Springboot实现验证码登录 1.背景 本人近期正在完成毕业设计(旅游信息管理系统)的制作,采用的SpringBoot+Thymeleaf的模式.在登录网站时想要添加验证码验证,通过网上查找资料 ...
- BigDecimal精度详解
[BigDecimal精确度的计数保留法及精度丢失的解决办法] 目录 BigDecimal精确度的计数保留法 1.ROUND_UP 2.ROUND_DOWN 3.ROUND_HALF_UP 4.ROU ...
- 图解S.O.L.I.D原则
如果您熟悉面向对象的编程,那么您可能已经听说过SOLID原理. 这五项软件开发原则是构建软件时要遵循的准则,以便于扩展和维护. 它们受到软件工程师Robert C. Martin的欢迎. 在线上有很多 ...