10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf

上篇: Bootstrap Blazor 实战 通用导入导出服务(Table组件)

10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf插图1

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

2.样式表和Javascript 引用

增加主题样式表到 Pages/_Host.cshtml 文件中

删除

并在下面添加两行



添加 Javascript 引用到 Pages/_Layout.cshtml 文件中

之前添加


完整文件

@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace b14table.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

    
    
    

    
    

    
    
    
    

    
    
    

    

    
An error has occurred. This application may no longer respond until reloaded. An unhandled exception has occurred. See browser dev tools for details. Reload 🗙

3.添加增加命名空间引用到 _Imports.razor 文件中

其中 AME.Services 和 Blazor100.Service 命名空间稍后文件里用到

@using BootstrapBlazor.Components 
@using AME.Services
@using Blazor100.Service
@using System.Diagnostics.CodeAnalysis

4.增加 BootstrapBlazorRoot 组件到 App.razor 文件中


    
        ...
    

5.添加 BootstrapBlazor服务/ FreeSql 数据服务/ ImportExportsService 导出服务 到 Program.cs 文件中

builder.Services.AddSingleton(); 后加入


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();
//不写这句因为下面一句扩展包含了 //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
{
    /// 
    /// 通用导入导出服务类
    /// 
    public class ImportExportsService
    {
        public enum ExportType
        {
            Excel,
            Pdf,
            Word,
            Html
        }

        public async Task Export(string filePath, List? items = null, ExportType exportType = ExportType.Excel) where T : class, new()
        {
            switch (exportType)
            {
                case ExportType.Pdf:
                    var exporterPdf = new PdfExporter();
                    items = items ?? new List();
                    var resultPdf = await exporterPdf.ExportListByTemplate(filePath + ".pdf", items);
                    return resultPdf.FileName;
                case ExportType.Word:
                    var exporterWord = new WordExporter();
                    items = items ?? new List();
                    var resultWord = await exporterWord.ExportListByTemplate(filePath + ".docx", items);
                    return resultWord.FileName;
                case ExportType.Html:
                    var exporterHtml = new HtmlExporter();
                    items = items ?? new List();
                    var resultHtml = await exporterHtml.ExportListByTemplate(filePath + ".html", items);
                    return resultHtml.FileName;
                default:
                    IExporter exporter = new ExcelExporter();
                    items = items ?? new List();
                    var result = await exporter.Export(filePath + ".xlsx", items);
                    return result.FileName;
            }
        }

        public async Task? items,string error)> ImportFormExcel(string filePath) where T : class, new()
        {
            IExcelImporter Importer = new ExcelImporter();
            var import = await Importer.Import(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
Index


    
        
     
    
        
@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().Count(); if (res == 0) { var forecasts = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList(); fsql.Insert().AppendData(forecasts).ExecuteAffrows(); } } } }

9. 界面和代码 Pages/ImpExpII.razor

@page "/impexpii"
@using b14table.Data
@using static Blazor100.Service.ImportExportsService

导入导出II



@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? LazyHeroDataService { get; set; } [NotNull] Table? 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 Export模板Async() { await Export(); return true; } private async Task ExportExcelAsync(IEnumerable items) => await ExportAutoAsync(items, ExportType.Excel); private async Task ExportPDFAsync(IEnumerable items) => await ExportAutoAsync(items, ExportType.Pdf); private async Task ExportWordAsync(IEnumerable items) => await ExportAutoAsync(items, ExportType.Word); private async Task ExportHtmlAsync(IEnumerable items) => await ExportAutoAsync(items, ExportType.Html); private async Task ExportAutoAsync(IEnumerable 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? 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 EmptyAll() { LazyHeroDataService!.Items = new List(); 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 MockImportExcel() { var items_temp = await ImportExportsService!.ImportFormExcel(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())); } /// /// 导出数据方法 /// /// /// /// protected async Task ExportAsync(IEnumerable Items, QueryPageOptions opt) { var ret = false; ret = await ExportExcelAsync(Items); return ret; } }

项目源码

Github | Gitee

关联项目

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

THE END
分享
二维码