BootstrapBlazor實戰(zhàn) 通用導(dǎo)入導(dǎo)出服務(wù)(Table組件)

1.本文主要內(nèi)容為給Blazor工程構(gòu)建通用導(dǎo)入導(dǎo)出服務(wù)類

基礎(chǔ)工程構(gòu)建取自 [BootstrapBlazor實戰(zhàn) 10分鐘編寫數(shù)據(jù)庫維護(hù)] 項目,使用到的orm為freesql,導(dǎo)入導(dǎo)出庫為Magicodes.IE,還有封裝了Table組件的內(nèi)存數(shù)據(jù)服務(wù)LazyHeroDataService的Densen.FreeSql.Extensions.BootstrapBlazor庫.

主要實現(xiàn)功能(Table組件):

[編輯][添加][刪除]數(shù)據(jù)

[導(dǎo)出]現(xiàn)在表格數(shù)據(jù)

[清空]數(shù)據(jù)

[選擇文件]上傳并導(dǎo)入

[清空]數(shù)據(jù)后再選擇[導(dǎo)入]

[自由編輯]類似Excel模式編輯表格

最終運(yùn)行效果

2.使用 nuget.org 進(jìn)行必須的組件安裝

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 Densen.FreeSql.Extensions.BootstrapBlazor

Densen.FreeSql.Extensions.BootstrapBlazor 庫封裝了Table組件的內(nèi)存數(shù)據(jù)服務(wù)LazyHeroDataService,因篇幅關(guān)系不展開介紹,需要了解的朋友請自行查看源碼?https://github.com/densen2014/Densen.Extensions/blob/master/Blazor/Services/LazyHeroDataService.cs

3.項目添加?Service?文件夾,添加?ImportExportsService.cs?文件

using Magicodes.ExporterAndImporter.Core;

using Magicodes.ExporterAndImporter.Excel;

using Magicodes.ExporterAndImporter.Html;

using Magicodes.ExporterAndImporter.Pdf;

using Magicodes.ExporterAndImporter.Word;

namespace Blazor100.Service

{

? ? /// <summary>

? ? /// 通用導(dǎo)入導(dǎo)出服務(wù)類

? ? /// </summary>

? ? public class ImportExportsService

? ? {

? ? ? ? public enum ExportType

? ? ? ? {

? ? ? ? ? ? Excel,

? ? ? ? ? ? Pdf,

? ? ? ? ? ? Word,

? ? ? ? ? ? Html

? ? ? ? }

? ? ? ? public async Task<string> ExportToExcel<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(),"");

? ? ? ? }

? ? }

}

4.添加增加命名空間引用到?_Imports.razor?文件中

@using Blazor100.Service

@using AME.Services

5.添加ImportExportsService服務(wù)到?Program.cs?文件中

using Blazor100.Service;

builder.Services.AddTransient<ImportExportsService>();

添加封裝了Table組件的內(nèi)存數(shù)據(jù)服務(wù)LazyHeroDataService的DensenExtensions()

builder.Services.AddBootstrapBlazor();?改為

builder.Services.AddDensenExtensions();

6.數(shù)據(jù)實體類

添加導(dǎo)入導(dǎo)出特性到?Data/WeatherForecast.cs?類文件中

完整文件

using BootstrapBlazor.Components;

using FreeSql.DataAnnotations;

using Magicodes.ExporterAndImporter.Excel;

using OfficeOpenXml.Table;

using System.ComponentModel;

namespace b03sqlite.Data;

[ExcelImporter(IsLabelingError = true)]

[ExcelExporter(Name = "導(dǎo)入商品中間表", 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; }

}

6.頁面文件?Pages/ImpExp.razor

@page "/impexp"

@using b03sqlite.Data

<PageTitle>導(dǎo)入導(dǎo)出</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">

? ? <TableToolbarTemplate>

? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Primary" Text="自由編輯" OnClick="@IsExcelToggle" />

? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Warning" Text="隨機(jī)數(shù)據(jù)" IsAsync OnClick="@GetDatasAsync" />

? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Secondary" Text="導(dǎo)入" IsAsync OnClick="@ImportExcel" />

? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Info" Text="導(dǎo)出" IsAsync OnClickCallback="ExportAsync" />

? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Danger" Text="清空" IsAsync OnClick="EmptyAll" />

? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Success" Text="模板" IsAsync OnClick="Export模板Async" />

? ? </TableToolbarTemplate>

</Table>

7.代碼

@code{

? ? [Inject] Microsoft.AspNetCore.Hosting.IWebHostEnvironment? HostEnvironment { get; set; }

? ? [Inject] NavigationManager? navigationManager { get; set; }

? ? [Inject] ImportExportsService? importExportsService { get; set; }

? ? [Inject] ToastService? toastService { get; set; }

? ? [Inject] WeatherForecastService? ForecastService { get; set; }

? ? [Inject] LazyHeroDataService<WeatherForecast>? LazyHeroDataService { get; set; }

? ? 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 override async Task OnInitializedAsync()

? ? //{

? ? //LazyHeroDataService!.Items = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();

? ? //}

? ? protected async Task GetDatasAsync()

? ? {

? ? ? ? LazyHeroDataService!.Items = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();

? ? ? ? await list1!.QueryAsync();

? ? }

? ? protected override void OnAfterRender(bool firstRender)

? ? {

? ? ? ? if (firstRender)

? ? ? ? {

? ? ? ? ? ? UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "Upload");

? ? ? ? ? ? if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath);

? ? ? ? }

? ? }

? ? private Task IsExcelToggle()

? ? {

? ? ? ? IsExcel = !IsExcel;

? ? ? ? DoubleClickToEdit = !IsExcel;

? ? ? ? StateHasChanged();

? ? ? ? return Task.CompletedTask;

? ? }

? ? public async Task<bool> Export模板Async()

? ? {

? ? ? ? await 模板下載();

? ? ? ? return true;

? ? }

? ? private async Task 模板下載(List<WeatherForecast>? items = null)

? ? {

? ? ? ? var ufilename = LazyHeroDataService!.Items == null ? "模板" : "新數(shù)據(jù)";

? ? ? ? var sFileName = ufilename + ".xlsx";

? ? ? ? var filename = Path.Combine(UploadPath, ufilename);

? ? ? ? await importExportsService!.ExportToExcel(filename, items);

? ? ? ? toastService?.Success("提示", ufilename + "已生成");

? ? ? ? //* 流化到前端處理也可以,不一定要用文件形式下載.

? ? ? ? navigationManager?.NavigateTo($"Upload/{sFileName}", true);

? ? ? ? //下載后清除文件

? ? ? ? _ = Task.Run(() =>

? ? ? ? {

? ? ? ? ? ? Thread.Sleep(5000);

? ? ? ? ? ? System.IO.File.Delete(filename);

? ? ? ? });

? ? }

? ? public async Task<bool> ExportAsync(IEnumerable<WeatherForecast> Items)

? ? {

? ? ? ? await 模板下載(LazyHeroDataService!.Items);

? ? ? ? return true;

? ? }

? ? public async Task<bool> EmptyAll()

? ? {

? ? ? ? LazyHeroDataService!.Items = new List<WeatherForecast>();

? ? ? ? await toastService!.Show(new ToastOption()

? ? ? ? {

? ? ? ? ? ? Category = ToastCategory.Success,

? ? ? ? ? ? Title = "提示",

? ? ? ? ? ? Content = "已清空數(shù)據(jù)",

? ? ? ? });

? ? ? ? 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 = "導(dǎo)入文件中,請稍等片刻...",

? ? ? ? ? ? IsAutoHide = false

? ? ? ? };

? ? ? ? // 彈出 Toast

? ? ? ? await toastService!.Show(option);

? ? ? ? await Task.Delay(100);

? ? ? ? // 開啟后臺進(jìn)程進(jìn)行數(shù)據(jù)處理

? ? ? ? var isSuccess= await MockImportExcel();

? ? ? ? // 關(guān)閉 option 相關(guān)聯(lián)的彈窗

? ? ? ? await option.Close();

? ? ? ? // 彈窗告知下載完畢

? ? ? ? await toastService.Show(new ToastOption()

? ? ? ? {

? ? ? ? ? ? Category = isSuccess? ToastCategory.Success : ToastCategory.Error,

? ? ? ? ? ? Title = "提示",

? ? ? ? ? ? Content = isSuccess ? "操作成功,請檢查數(shù)據(jù)":"出現(xiàn)錯誤,請重試導(dǎo)入或者上傳",

? ? ? ? ? ? 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("提示", "文件導(dǎo)入失敗: "+ items_temp.error);

? ? ? ? ? ? return false;

? ? ? ? }

? ? ? ? //items = SmartCombine(items_temp, items).ToList(); 新數(shù)據(jù)和老數(shù)據(jù)合并處理,略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);

? ? ? ? //正式工程此處是回調(diào),簡化版必須InvokeAsync一下,自由發(fā)揮

? ? ? ? _ = Task.Run(async () => await InvokeAsync(async () => await ImportExcel()));

? ? }

}

8.試試Index.razor添加Tab組件看看效果

<Tab>

? ? <TabItem Text="導(dǎo)入導(dǎo)出">

? ? ? ? <ImpExp />

? ? </TabItem>

? ? <TabItem Text="數(shù)據(jù)維護(hù)">

? ? ? ... 原始頁面內(nèi)容

? ? </TabItem>

</Tab>

9.運(yùn)行逐一測試功能

點擊[隨機(jī)數(shù)據(jù)] 生成數(shù)據(jù)

[編輯][添加][刪除]數(shù)據(jù)

[導(dǎo)出]現(xiàn)在表格數(shù)據(jù)

[清空]數(shù)據(jù)

[選擇文件]上傳并導(dǎo)入

[清空]數(shù)據(jù)后再選擇[導(dǎo)入]

[自由編輯]類似Excel模式編輯表格

[導(dǎo)出PDF] 自行擴(kuò)展 importExportsService.ExportToExcel(filename, items,ExportType.Pdf);

[導(dǎo)出Word] 自行擴(kuò)展 importExportsService.ExportToExcel(filename, items,ExportType.Word);

[導(dǎo)出Html] 自行擴(kuò)展 importExportsService.ExportToExcel(filename, items,ExportType.Html);

項目源碼

Github?|?Gitee

關(guān)聯(lián)項目

FreeSql QQ群:4336577(已滿)瓤摧、8578575(已滿)该肴、52508226(在線)

BA & Blazor QQ群:795206915宪拥、675147445

知識共享許可協(xié)議

本作品采用?知識共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議?進(jìn)行許可。歡迎轉(zhuǎn)載戈轿、使用、重新發(fā)布,但務(wù)必保留文章署名AlexChow(包含鏈接:?https://github.com/densen2014?)面褐,不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布取胎。如有任何疑問展哭,請與我聯(lián)系?。

AlexChow

今日頭條?|?博客園?|?知乎?|?Gitee?|?GitHub

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闻蛀,一起剝皮案震驚了整個濱河市匪傍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌循榆,老刑警劉巖析恢,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異秧饮,居然都是意外死亡映挂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門盗尸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柑船,“玉大人,你說我怎么就攤上這事泼各“笆保” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵扣蜻,是天一觀的道長逆巍。 經(jīng)常有香客問我,道長莽使,這世上最難降的妖魔是什么锐极? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮芳肌,結(jié)果婚禮上灵再,老公的妹妹穿的比我還像新娘。我一直安慰自己亿笤,他們只是感情好翎迁,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著净薛,像睡著了一般汪榔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罕拂,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天揍异,我揣著相機(jī)與錄音全陨,去河邊找鬼。 笑死衷掷,一個胖子當(dāng)著我的面吹牛辱姨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戚嗅,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼雨涛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了懦胞?” 一聲冷哼從身側(cè)響起替久,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎躏尉,沒想到半個月后蚯根,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胀糜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年颅拦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片教藻。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡距帅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出括堤,到底是詐尸還是另有隱情碌秸,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布悄窃,位于F島的核電站讥电,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏轧抗。R本人自食惡果不足惜允趟,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸦致。 院中可真熱鬧,春花似錦涣楷、人聲如沸分唾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绽乔。三九已至,卻和暖如春碳褒,著一層夾襖步出監(jiān)牢的瞬間折砸,已是汗流浹背看疗。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留睦授,地道東北人两芳。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像去枷,于是被迫代替她去往敵國和親怖辆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容