mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-11-29 18:49:08 +08:00
feat(Table): support export as Pdf (#2550)
* doc: 更新示例文档 * feat: 增加 Pdf 导出方法 * chore: 增加 Csv 相关资源文件 * refactor: 完善 IHtml2Pdf 接口服务 * refactor: 重构 TableExport 导出服务 * feat: 合并导出服务 * feat: 增加 IHtml2Pdf 服务 * feat: 增加 Csv 图标参数 * feat: 增加 ExportCsvDropdownItemText 参数 * feat: 内置导出 Csv 按钮参数 * feat: 移除 Pdf/Excel 服务统一使用 TableExport 服务 * refator: 调整注入服务 * refactor: 更改图标参数名称 * refactor: 增加图标宽度 * refactor: 精简代码 * doc: 更新导出按钮示例 * doc: 重构 Html2Pdf 示例 * feat: 增加 ITableExportPdf 服务 * feat: 增加 PdfSteamAsync 方法 * doc: 重构代码 * feat: 实现项目 Pdf 导出服务 * refactor: 增加 PdfStreamAsync 方法 * feat: 增加 ExportPdfAsync 方法 * chore: 更新图标 * test: 更新单元测试 * chore: 更新字典 * chore: bump version 8.0.6-beta01 * chore: bump version 8.0.2-beta01 * chore: bump version 8.0.1-beta01 * chore: bump version 8.0.2-beta01 * chore: 更新依赖组件包到最新 * refactor: 重构代码消除警告信息 * test: 更新单元测试 * refactor: 精简代码 * test: 更新单元测试
This commit is contained in:
parent
498d5f92ff
commit
9b2d9d467a
@ -55,3 +55,4 @@ Splittings
|
||||
Foos
|
||||
Localizer
|
||||
onchange
|
||||
Render
|
||||
|
@ -230,6 +230,7 @@
|
||||
"ExportToastTitle": "Daten exportieren",
|
||||
"ExportToastContent": "Daten exportieren {0}, automatisches Schließen in {1} Sekunden",
|
||||
"ExportToastInProgressContent": "Daten exportieren, automatisches Schließen in {0} Sekunden",
|
||||
"ExportCsvDropdownItemText": "MS-Csv",
|
||||
"ExportExcelDropdownItemText": "MS-Excel",
|
||||
"ExportPdfDropdownItemText": "Pdf",
|
||||
"PageInfoText": "{0} - {1} Total {2}",
|
||||
|
@ -230,6 +230,7 @@
|
||||
"ExportToastTitle": "Exportar datos",
|
||||
"ExportToastContent": "Exportar datos {0}, cierre automático en {0} segundos",
|
||||
"ExportToastInProgressContent": "Exportar datos, cierre automático en {0} segundos",
|
||||
"ExportCsvDropdownItemText": "MS-Csv",
|
||||
"ExportExcelDropdownItemText": "MS-Excel",
|
||||
"ExportPdfDropdownItemText": "Pdf",
|
||||
"PageInfoText": "{0} - {1} Total {2}",
|
||||
|
@ -230,6 +230,7 @@
|
||||
"ExportToastTitle": "Exportar dados",
|
||||
"ExportToastContent": "Exportar dados {0}, Fechamento automático em {0} segundos",
|
||||
"ExportToastInProgressContent": "Exportar dados, Fechamento automático em {0} segundos",
|
||||
"ExportCsvDropdownItemText": "MS-Csv",
|
||||
"ExportExcelDropdownItemText": "MS-Excel",
|
||||
"ExportPdfDropdownItemText": "Pdf",
|
||||
"PageInfoText": "{0} - {1} Total {2}",
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"BootstrapBlazor.Components.AutoComplete": {
|
||||
"NoDataTip": "ไม่มีข้อมูลที่ตรงกัน",
|
||||
"PlaceHolder": "กรุณากรอก"
|
||||
@ -225,6 +225,7 @@
|
||||
"ExportToastTitle": "ส่งออกข้อมูล",
|
||||
"ExportToastContent": "ส่งออกข้อมูล {0},{1} ปิดอัตโนมัติหลังจากวินาที",
|
||||
"ExportToastInProgressContent": "กำลังส่งออกข้อมูล โปรดทราบภายหลัง, {0} ปิดอัตโนมัติหลังจากวินาที",
|
||||
"ExportCsvDropdownItemText": "ไมโครซอฟท์ Csv รูปแบบ",
|
||||
"ExportExcelDropdownItemText": "ไมโครซอฟท์ Excel รูปแบบ",
|
||||
"ExportPdfDropdownItemText": "Pdf รูปแบบ",
|
||||
"PageInfoText": "{0} - {1} ทั้งหมด {2} บทความ",
|
||||
|
@ -239,6 +239,7 @@
|
||||
"ExportToastTitle": "匯出資料",
|
||||
"ExportToastContent": "匯出資料 {0},{1} 秒後自動關閉",
|
||||
"ExportToastInProgressContent": "正在匯出資料,請稍後, {0} 秒後自動關閉",
|
||||
"ExportCsvDropdownItemText": "微軟 Csv 格式",
|
||||
"ExportExcelDropdownItemText": "微軟 Excel 格式",
|
||||
"ExportPdfDropdownItemText": "Pdf 格式"
|
||||
},
|
||||
|
@ -42,12 +42,12 @@
|
||||
<PackageReference Include="BootstrapBlazor.FileViewer" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.Gantt" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.Html2Pdf" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.Html2Pdf" Version="8.0.2-beta01" />
|
||||
<PackageReference Include="BootstrapBlazor.ImageCropper" Version="*" />
|
||||
<PackageReference Include="BootstrapBlazor.Live2DDisplay" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.Markdown" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.MaterialDesign" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.MaterialDesign.Extensions" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.MaterialDesign.Extensions" Version="8.0.2-beta01" />
|
||||
<PackageReference Include="BootstrapBlazor.Middleware" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.MindMap" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.MouseFollower" Version="8.0.0" />
|
||||
@ -56,7 +56,7 @@
|
||||
<PackageReference Include="BootstrapBlazor.SignaturePad" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.Splitting" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.SummerNote" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.TableExport" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor.TableExport" Version="8.0.1-beta01" />
|
||||
<PackageReference Include="BootstrapBlazor.Topology" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.VideoPlayer" Version="8.0.1" />
|
||||
<PackageReference Include="BootstrapBlazor.WebAPI" Version="8.0.0" />
|
||||
|
@ -19,10 +19,6 @@ public partial class Html2Pdfs
|
||||
[NotNull]
|
||||
private DownloadService? DownloadService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IComponentHtmlRenderer? HtmlRenderService { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private IWebHostEnvironment? WebHostEnvironment { get; set; }
|
||||
@ -63,7 +59,7 @@ public partial class Html2Pdfs
|
||||
|
||||
// 拼接导出文件网址
|
||||
var url = $"{NavigationManager.BaseUri}{fileName}";
|
||||
var data = await PdfService.ExportDataAsync(url);
|
||||
var data = await PdfService.PdfDataAsync(url);
|
||||
using var stream = new MemoryStream(data);
|
||||
await DownloadService.DownloadFromStreamAsync("table.pdf", stream);
|
||||
await ToastService.Success("Pdf Export", "Export pdf element success.");
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<PackageTips Name="BootstrapBlazor.TableExport" />
|
||||
|
||||
<p><b>@Localizer["TablesExportTips"]:</b></p>
|
||||
<p class="mt-3"><b>@Localizer["TablesExportTips"]:</b></p>
|
||||
|
||||
<Pre>public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
@ -38,6 +38,24 @@
|
||||
</Table>
|
||||
</DemoBlock>
|
||||
|
||||
<DemoBlock Title="@Localizer["TablesExportShowExportCsvButtonTitle"]"
|
||||
Introduction="@Localizer["TablesExportShowExportCsvButtonIntro"]"
|
||||
Name="ShowCsvExportButton">
|
||||
<Table TItem="Foo"
|
||||
IsPagination="true" PageItemsSource="@PageItemsSource"
|
||||
IsStriped="true" IsBordered="true" IsMultipleSelect="true"
|
||||
ShowToolbar="true" ShowDefaultButtons="false"
|
||||
ShowExportButton="true" ShowExportCsvButton="true" ShowExportPdfButton="true"
|
||||
OnQueryAsync="@OnQueryAsync">
|
||||
<TableColumns>
|
||||
<TableColumn @bind-Field="@context.DateTime" Width="180" />
|
||||
<TableColumn @bind-Field="@context.Name" Width="100" />
|
||||
<TableColumn @bind-Field="@context.Address" />
|
||||
<TableColumn @bind-Field="@context.Count" />
|
||||
</TableColumns>
|
||||
</Table>
|
||||
</DemoBlock>
|
||||
|
||||
<DemoBlock Title="@Localizer["TablesExportOnExportAsyncTitle"]"
|
||||
Introduction="@Localizer["TablesExportOnExportAsyncIntro"]"
|
||||
Name="OnExportAsync">
|
||||
|
@ -25,6 +25,7 @@ public partial class TablesExport
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
private List<Foo>? Items { get; set; }
|
||||
|
||||
private static IEnumerable<int> PageItemsSource => new int[] { 4, 10, 20 };
|
||||
|
||||
/// <summary>
|
||||
@ -53,7 +54,7 @@ public partial class TablesExport
|
||||
// 自定义导出方法
|
||||
// 通过 context 参数可以自己查询数据进行导出操作
|
||||
// 本例使用 context 传递来的 Rows/Columns 自定义文件名为 Test.xlsx
|
||||
var ret = await Exporter.ExportAsync(context.Rows, context.Columns, "Test.xlsx");
|
||||
var ret = await TableExport.ExportExcelAsync(context.Rows, context.Columns, "Test.xlsx");
|
||||
|
||||
// 返回 true 时自动弹出提示框
|
||||
return ret;
|
||||
@ -61,7 +62,7 @@ public partial class TablesExport
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private ITableExcelExport? Exporter { get; set; }
|
||||
private ITableExport? TableExport { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
@ -124,7 +125,7 @@ public partial class TablesExport
|
||||
// 自定义导出模板导出当前页面数据为 Excel 方法
|
||||
// 使用 BootstrapBlazor 内置服务 ITableExcelExport 实例方法 ExportAsync 进行导出操作
|
||||
// 导出数据使用 context 传递来的 Rows/Columns 即为当前页数据
|
||||
var ret = await Exporter.ExportAsync(context.Rows, context.Columns, $"Test_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
|
||||
var ret = await TableExport.ExportExcelAsync(context.Rows, context.Columns, $"Test_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
|
||||
|
||||
// 返回 true 时自动弹出提示框
|
||||
await ShowToast(ret);
|
||||
@ -145,7 +146,7 @@ public partial class TablesExport
|
||||
var data = Items.Where(filter.GetFilterFunc<Foo>());
|
||||
|
||||
// 导出符合条件的所有数据 data
|
||||
var ret = await Exporter.ExportAsync(data, context.Columns, $"Test_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
|
||||
var ret = await TableExport.ExportExcelAsync(data, context.Columns, $"Test_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
|
||||
|
||||
// 返回 true 时自动弹出提示框
|
||||
await ShowToast(ret);
|
||||
@ -156,7 +157,7 @@ public partial class TablesExport
|
||||
// 自定义导出模板导出当前页面数据为 Csv 方法
|
||||
// 使用 BootstrapBlazor 内置服务 ITableExcelExport 实例方法 ExportCsvAsync 进行导出操作
|
||||
// 导出数据使用 context 传递来的 Rows/Columns 即为当前页数据
|
||||
var ret = await Exporter.ExportCsvAsync(context.Rows, context.Columns, $"Test_{DateTime.Now:yyyyMMddHHmmss}.csv");
|
||||
var ret = await TableExport.ExportCsvAsync(context.Rows, context.Columns, $"Test_{DateTime.Now:yyyyMMddHHmmss}.csv");
|
||||
|
||||
// 返回 true 时自动弹出提示框
|
||||
await ShowToast(ret);
|
||||
|
@ -143,6 +143,7 @@ internal static class ServicesExtensions
|
||||
|
||||
// 增加 Table Excel 导出服务
|
||||
services.AddBootstrapBlazorTableExcelExport();
|
||||
services.AddTransient<ITableExportPdf, TableExportPdfService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
@ -5136,6 +5136,8 @@
|
||||
"TablesExportNote2": "Add Table Excel export service",
|
||||
"TablesExportShowExportButtonTitle": "Table export function",
|
||||
"TablesExportShowExportButtonIntro": "Whether to display the export button by setting the <code>ShowExportButton</code> property, the default is <code>false</code>",
|
||||
"TablesExportShowExportCsvButtonTitle": "Export Csv/Pdf Button",
|
||||
"TablesExportShowExportCsvButtonIntro": "Show/hide <code>Csv/Pdf</code> button by set <code>ShowExportCsvButton=\"true\"</code> <code>ShowExportPdfButton=\"true\"</code>",
|
||||
"TablesExportOnExportAsyncTitle": "Custom export method",
|
||||
"TablesExportOnExportAsyncIntro": "You can customize the export method by setting the <code>OnExportAsync</code> callback delegate method. If you don't set it, the built-in export function of the component will be used.",
|
||||
"TablesExportButtonDropdownTemplateTitle": "Custom export dropdown button",
|
||||
|
@ -5136,6 +5136,8 @@
|
||||
"TablesExportNote2": "增加 Table Excel 导出服务",
|
||||
"TablesExportShowExportButtonTitle": "表格导出功能",
|
||||
"TablesExportShowExportButtonIntro": "通过设置 <code>ShowExportButton=\"true\"</code> 属性是否显示导出按钮,默认为<code>false</code>",
|
||||
"TablesExportShowExportCsvButtonTitle": "导出 Csv/Pdf",
|
||||
"TablesExportShowExportCsvButtonIntro": "通过设置 <code>ShowExportCsvButton=\"true\"</code> <code>ShowExportPdfButton=\"true\"</code> 控制 <code>Csv/Pdf</code> 导出按钮",
|
||||
"TablesExportOnExportAsyncTitle": "自定义导出方法",
|
||||
"TablesExportOnExportAsyncIntro": "通过设置 <code>OnExportAsync</code> 回调委托方法可自定义导出方法,不设置将使用组件内置导出函数",
|
||||
"TablesExportButtonDropdownTemplateTitle": "自定义导出下拉框按钮",
|
||||
|
@ -7,17 +7,12 @@ namespace BootstrapBlazor.Server.Services;
|
||||
/// <summary>
|
||||
/// 演示网站示例数据注入服务实现类
|
||||
/// </summary>
|
||||
internal class TableDemoDataService<TModel> : DataServiceBase<TModel> where TModel : class, new()
|
||||
class TableDemoDataService<TModel>(IStringLocalizer<TModel> localizer) : DataServiceBase<TModel> where TModel : class, new()
|
||||
{
|
||||
[NotNull]
|
||||
private List<TModel>? Items { get; set; }
|
||||
|
||||
private IStringLocalizer<TModel> Localizer { get; set; }
|
||||
|
||||
public TableDemoDataService(IStringLocalizer<TModel> localizer)
|
||||
{
|
||||
Localizer = localizer;
|
||||
}
|
||||
private IStringLocalizer<TModel> Localizer { get; } = localizer;
|
||||
|
||||
/// <summary>
|
||||
/// 查询操作方法
|
||||
|
46
src/BootstrapBlazor.Server/Services/TableExportPdfService.cs
Normal file
46
src/BootstrapBlazor.Server/Services/TableExportPdfService.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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/
|
||||
|
||||
namespace BootstrapBlazor.Server.Services;
|
||||
|
||||
class TableExportPdfService(IWebHostEnvironment webHostEnvironment, NavigationManager navigationManager, IHtml2Pdf html2Pdf) : ITableExportPdf
|
||||
{
|
||||
private readonly IWebHostEnvironment _webHostEnvironment = webHostEnvironment;
|
||||
private readonly NavigationManager _navigationManager = navigationManager;
|
||||
private readonly IHtml2Pdf _html2Pdf = html2Pdf;
|
||||
|
||||
public async Task<byte[]> PdfDataAsync(string content)
|
||||
{
|
||||
var url = await GenerateHtmlAsync(content);
|
||||
|
||||
// 生成 Pdf
|
||||
return await _html2Pdf.PdfDataAsync(url);
|
||||
}
|
||||
|
||||
public async Task<Stream> PdfStreamAsync(string content)
|
||||
{
|
||||
var url = await GenerateHtmlAsync(content);
|
||||
|
||||
// 生成 Pdf
|
||||
return await _html2Pdf.PdfStreamAsync(url);
|
||||
}
|
||||
|
||||
private async Task<string> GenerateHtmlAsync(string content)
|
||||
{
|
||||
// 通过 template 模板文件生成网页文件
|
||||
var templateFileName = Path.Combine(_webHostEnvironment.WebRootPath, "pdf/template.htm");
|
||||
var template = await File.ReadAllTextAsync(templateFileName);
|
||||
|
||||
// 生成静态 html 文件
|
||||
var htmlFileName = $"pdf/{Guid.NewGuid()}.html";
|
||||
var filePath = Path.Combine(_webHostEnvironment.WebRootPath, htmlFileName);
|
||||
using var writer = File.CreateText(filePath);
|
||||
await writer.WriteLineAsync(string.Format(template, content));
|
||||
await writer.FlushAsync();
|
||||
writer.Close();
|
||||
|
||||
// 拼接导出文件网址
|
||||
return $"{_navigationManager.BaseUri}{htmlFileName}";
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>8.0.5</Version>
|
||||
<Version>8.0.6-beta01</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">
|
||||
|
@ -125,6 +125,13 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShowExportCsvButton)
|
||||
{
|
||||
<div class="dropdown-item" @onclick="@ExportCsvAsync">
|
||||
<i class="@CsvExportIcon"></i>
|
||||
<span>@ExportCsvDropdownItemText</span>
|
||||
</div>
|
||||
}
|
||||
if (ShowExportExcelButton)
|
||||
{
|
||||
<div class="dropdown-item" @onclick="@ExportExcelAsync">
|
||||
|
@ -414,6 +414,7 @@ public partial class Table<TItem>
|
||||
ExportToastTitle ??= Localizer[nameof(ExportToastTitle)];
|
||||
ExportToastContent ??= Localizer[nameof(ExportToastContent)];
|
||||
ExportToastInProgressContent ??= Localizer[nameof(ExportToastInProgressContent)];
|
||||
ExportCsvDropdownItemText ??= Localizer[nameof(ExportCsvDropdownItemText)];
|
||||
ExportExcelDropdownItemText ??= Localizer[nameof(ExportExcelDropdownItemText)];
|
||||
ExportPdfDropdownItemText ??= Localizer[nameof(ExportPdfDropdownItemText)];
|
||||
CopyColumnTooltipText ??= Localizer[nameof(CopyColumnTooltipText)];
|
||||
|
@ -63,6 +63,12 @@ public partial class Table<TItem>
|
||||
[Parameter]
|
||||
public bool ShowExportExcelButton { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示 Csv 导出按钮 默认为 false 显示
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ShowExportCsvButton { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示 Pdf 导出按钮 默认为 false 显示
|
||||
/// </summary>
|
||||
@ -75,6 +81,12 @@ public partial class Table<TItem>
|
||||
[Parameter]
|
||||
public string? ExportButtonIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 内置导出 Csv 按钮图标
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? CsvExportIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 内置导出 Excel 按钮图标
|
||||
/// </summary>
|
||||
@ -117,6 +129,12 @@ public partial class Table<TItem>
|
||||
[Parameter]
|
||||
public RenderFragment<ITableExportContext<TItem>>? ExportButtonDropdownTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 内置导出微软 Csv 按钮文本 默认 null 读取资源文件
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? ExportCsvDropdownItemText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 内置导出微软 Excel 按钮文本 默认 null 读取资源文件
|
||||
/// </summary>
|
||||
@ -374,16 +392,12 @@ public partial class Table<TItem>
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private ITableExcelExport? ExcelExport { get; set; }
|
||||
|
||||
[Inject]
|
||||
[NotNull]
|
||||
private ITablePdfExport? PdfExport { get; set; }
|
||||
private ITableExport? TableExport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 各列是否显示状态集合
|
||||
/// </summary>
|
||||
private List<ColumnVisibleItem> VisibleColumns { get; } = new();
|
||||
private List<ColumnVisibleItem> VisibleColumns { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 获得当前可见列集合
|
||||
@ -1021,15 +1035,19 @@ public partial class Table<TItem>
|
||||
|
||||
private Task ExportAsync() => ExecuteExportAsync(() => OnExportAsync != null
|
||||
? OnExportAsync(new TableExportDataContext<TItem>(TableExportType.Unknown, Rows, GetVisibleColumns(), BuildQueryPageOptions()))
|
||||
: ExcelExport.ExportAsync(Rows, GetVisibleColumns()));
|
||||
: TableExport.ExportAsync(Rows, GetVisibleColumns()));
|
||||
|
||||
private Task ExportCsvAsync() => ExecuteExportAsync(() => OnExportAsync != null
|
||||
? OnExportAsync(new TableExportDataContext<TItem>(TableExportType.Pdf, Rows, GetVisibleColumns(), BuildQueryPageOptions()))
|
||||
: TableExport.ExportCsvAsync(Rows, GetVisibleColumns()));
|
||||
|
||||
private Task ExportPdfAsync() => ExecuteExportAsync(() => OnExportAsync != null
|
||||
? OnExportAsync(new TableExportDataContext<TItem>(TableExportType.Pdf, Rows, GetVisibleColumns(), BuildQueryPageOptions()))
|
||||
: PdfExport.ExportAsync(Rows, GetVisibleColumns()));
|
||||
: TableExport.ExportPdfAsync(Rows, GetVisibleColumns()));
|
||||
|
||||
private Task ExportExcelAsync() => ExecuteExportAsync(() => OnExportAsync != null
|
||||
? OnExportAsync(new TableExportDataContext<TItem>(TableExportType.Excel, Rows, GetVisibleColumns(), BuildQueryPageOptions()))
|
||||
: ExcelExport.ExportAsync(Rows, GetVisibleColumns()));
|
||||
: TableExport.ExportExcelAsync(Rows, GetVisibleColumns()));
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前 Table 选中的所有行数据
|
||||
|
@ -130,9 +130,9 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
|
||||
private static string? GetColspan(int colspan) => colspan > 1 ? colspan.ToString() : null;
|
||||
|
||||
private bool IsShowFooter => ShowFooter && (Rows.Any() || !IsHideFooterWhenNoData);
|
||||
private bool IsShowFooter => ShowFooter && (Rows.Count > 0 || !IsHideFooterWhenNoData);
|
||||
|
||||
private int PageStartIndex => Rows.Any() ? (PageIndex - 1) * PageItems + 1 : 0;
|
||||
private int PageStartIndex => Rows.Count > 0 ? (PageIndex - 1) * PageItems + 1 : 0;
|
||||
|
||||
private string? PageInfoLabelString => Localizer[nameof(PageInfoText), PageStartIndex, (PageIndex - 1) * PageItems + Rows.Count, TotalCount];
|
||||
|
||||
@ -187,7 +187,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
/// <summary>
|
||||
/// 明细行集合用于数据懒加载
|
||||
/// </summary>
|
||||
protected List<TItem> ExpandRows { get; } = new List<TItem>();
|
||||
protected List<TItem> ExpandRows { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件工作模式为 Excel 模式 默认 false
|
||||
@ -350,7 +350,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
/// <summary>
|
||||
/// 明细行集合用于数据懒加载
|
||||
/// </summary>
|
||||
protected List<TItem> DetailRows { get; } = new List<TItem>();
|
||||
protected List<TItem> DetailRows { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 获得 表头集合
|
||||
@ -695,8 +695,9 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
RefreshButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableRefreshButtonIcon);
|
||||
CardViewButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableCardViewButtonIcon);
|
||||
ColumnListButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableColumnListButtonIcon);
|
||||
ExcelExportIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableExcelExportIcon);
|
||||
PdfExportIcon ??= IconTheme.GetIconByKey(ComponentIcons.TablePdfExportIcon);
|
||||
CsvExportIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableExportCsvIcon);
|
||||
ExcelExportIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableExportExcelIcon);
|
||||
PdfExportIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableExportPdfIcon);
|
||||
SearchButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableSearchButtonIcon);
|
||||
ResetSearchButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableResetSearchButtonIcon);
|
||||
CloseButtonIcon ??= IconTheme.GetIconByKey(ComponentIcons.TableCloseButtonIcon);
|
||||
@ -845,6 +846,8 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
|
||||
private string? GetTableName(bool hasHeader) => hasHeader ? ClientTableName : null;
|
||||
|
||||
private readonly JsonSerializerOptions _serializerOption = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
private async Task<IEnumerable<ColumnWidth>> ReloadColumnWidth()
|
||||
{
|
||||
IEnumerable<ColumnWidth>? ret = null;
|
||||
@ -858,10 +861,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
var doc = JsonDocument.Parse(jsonData);
|
||||
if (doc.RootElement.TryGetProperty("cols", out var element))
|
||||
{
|
||||
ret = element.Deserialize<IEnumerable<ColumnWidth>>(new JsonSerializerOptions()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
});
|
||||
ret = element.Deserialize<IEnumerable<ColumnWidth>>(_serializerOption);
|
||||
}
|
||||
if (doc.RootElement.TryGetProperty("table", out var tableEl) && tableEl.TryGetInt32(out var tableWidth))
|
||||
{
|
||||
@ -1106,7 +1106,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
var onValueChanged = Utility.GetOnValueChangedInvoke<IDynamicObject>(col.PropertyType);
|
||||
if (DynamicContext.OnValueChanged != null)
|
||||
{
|
||||
var parameters = col.ComponentParameters?.ToList() ?? new List<KeyValuePair<string, object>>();
|
||||
var parameters = col.ComponentParameters?.ToList() ?? [];
|
||||
parameters.Add(new(nameof(ValidateBase<string>.OnValueChanged), onValueChanged.Invoke(d, col, (model, column, val) => DynamicContext.OnValueChanged(model, column, val))));
|
||||
col.ComponentParameters = parameters;
|
||||
}
|
||||
@ -1134,7 +1134,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
/// <summary>
|
||||
/// 获得 过滤集合
|
||||
/// </summary>
|
||||
public Dictionary<string, IFilterAction> Filters { get; } = new();
|
||||
public Dictionary<string, IFilterAction> Filters { get; } = [];
|
||||
#endregion
|
||||
|
||||
private async ValueTask<ItemsProviderResult<TItem>> LoadItems(ItemsProviderRequest request)
|
||||
@ -1165,7 +1165,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
.AddClass("is-dbcell", trigger)
|
||||
.Build();
|
||||
|
||||
private bool IsShowEmpty => ShowEmpty && !Rows.Any();
|
||||
private bool IsShowEmpty => ShowEmpty && Rows.Count == 0;
|
||||
|
||||
private int GetColumnCount()
|
||||
{
|
||||
@ -1224,7 +1224,7 @@ public partial class Table<TItem> : ITable, IModelEqualityComparer<TItem> where
|
||||
/// 返回 true 时按钮禁用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool GetDeleteButtonStatus() => ShowAddForm || AddInCell || !SelectedRows.Any();
|
||||
private bool GetDeleteButtonStatus() => ShowAddForm || AddInCell || SelectedRows.Count == 0;
|
||||
|
||||
private async Task InvokeItemsChanged()
|
||||
{
|
||||
|
@ -555,14 +555,19 @@ public enum ComponentIcons
|
||||
TableColumnListButtonIcon,
|
||||
|
||||
/// <summary>
|
||||
/// Table 组件 ExcelExportIcon 属性图标
|
||||
/// Table 组件 ExportExcelIcon 属性图标
|
||||
/// </summary>
|
||||
TableExcelExportIcon,
|
||||
TableExportExcelIcon,
|
||||
|
||||
/// <summary>
|
||||
/// Table 组件 PdfExportIcon 属性图标
|
||||
/// Table 组件 ExportCsvIcon 属性图标
|
||||
/// </summary>
|
||||
TablePdfExportIcon,
|
||||
TableExportCsvIcon,
|
||||
|
||||
/// <summary>
|
||||
/// Table 组件 ExportPdfIcon 属性图标
|
||||
/// </summary>
|
||||
TableExportPdfIcon,
|
||||
|
||||
/// <summary>
|
||||
/// Table 组件 SearchButtonIcon 属性图标
|
||||
|
@ -37,9 +37,6 @@ public static class BootstrapBlazorServiceCollectionExtensions
|
||||
services.TryAddSingleton<IZipArchiveService, DefaultZipArchiveService>();
|
||||
services.TryAddSingleton(typeof(IDispatchService<>), typeof(DefaultDispatchService<>));
|
||||
|
||||
services.TryAddTransient<ITableExcelExport, DefaultExcelExport>();
|
||||
services.TryAddTransient<ITablePdfExport, DefaultPdfExport>();
|
||||
|
||||
services.TryAddScoped(typeof(IDataService<>), typeof(NullDataService<>));
|
||||
services.TryAddScoped<IIPLocatorProvider, DefaultIPLocatorProvider>();
|
||||
services.TryAddScoped<IReconnectorProvider, ReconnectorProvider>();
|
||||
@ -63,6 +60,9 @@ public static class BootstrapBlazorServiceCollectionExtensions
|
||||
services.AddScoped<NotificationService>();
|
||||
services.AddScoped<EyeDropperService>();
|
||||
|
||||
services.TryAddTransient<ITableExport, DefaultTableExport>();
|
||||
services.TryAddTransient<ITableExportPdf, DefaultTableExportPdf>();
|
||||
|
||||
services.ConfigureBootstrapBlazorOption(configureOptions);
|
||||
services.ConfigureIPLocatorOption();
|
||||
|
||||
|
@ -225,6 +225,7 @@
|
||||
"ExportToastTitle": "Export",
|
||||
"ExportToastContent": "Export data {0}, auto close after {1}s",
|
||||
"ExportToastInProgressContent": "Exporting data, please wait a moment, auto close after {0}s",
|
||||
"ExportCsvDropdownItemText": "MS-Csv",
|
||||
"ExportExcelDropdownItemText": "MS-Excel",
|
||||
"ExportPdfDropdownItemText": "Pdf",
|
||||
"PageInfoText": "{0} - {1} Total {2}",
|
||||
|
@ -225,6 +225,7 @@
|
||||
"ExportToastTitle": "导出数据",
|
||||
"ExportToastContent": "导出数据 {0},{1} 秒后自动关闭",
|
||||
"ExportToastInProgressContent": "正在导出数据,请稍后, {0} 秒后自动关闭",
|
||||
"ExportCsvDropdownItemText": "微软 Csv 格式",
|
||||
"ExportExcelDropdownItemText": "微软 Excel 格式",
|
||||
"ExportPdfDropdownItemText": "Pdf 格式",
|
||||
"PageInfoText": "{0} - {1} 共 {2} 条",
|
||||
|
@ -165,8 +165,9 @@ public class IconThemeOptions
|
||||
{ ComponentIcons.TableRefreshButtonIcon, "fa-solid fa-arrows-rotate" },
|
||||
{ ComponentIcons.TableCardViewButtonIcon, "fa-solid fa-bars" },
|
||||
{ ComponentIcons.TableColumnListButtonIcon, "fa-solid fa-table-list" },
|
||||
{ ComponentIcons.TableExcelExportIcon, "fa-regular fa-file-excel" },
|
||||
{ ComponentIcons.TablePdfExportIcon, "fa-regular fa-file-pdf" },
|
||||
{ ComponentIcons.TableExportCsvIcon, "fa-solid fa-fw fa-file-csv" },
|
||||
{ ComponentIcons.TableExportExcelIcon, "fa-solid fa-fw fa-file-excel" },
|
||||
{ ComponentIcons.TableExportPdfIcon, "fa-solid fa-fw fa-file-pdf" },
|
||||
{ ComponentIcons.TableSearchButtonIcon, "fa-solid fa-magnifying-glass" },
|
||||
{ ComponentIcons.TableResetSearchButtonIcon, "fa-regular fa-trash-can" },
|
||||
{ ComponentIcons.TableCloseButtonIcon, "fa-solid fa-xmark" },
|
||||
|
@ -9,9 +9,9 @@ namespace BootstrapBlazor.Components;
|
||||
|
||||
class ComponentHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory) : IComponentHtmlRenderer
|
||||
{
|
||||
private IServiceProvider ServiceProvider { get; set; } = serviceProvider;
|
||||
private readonly IServiceProvider _serviceProvider = serviceProvider;
|
||||
|
||||
private ILoggerFactory LoggerFactory { get; set; } = loggerFactory;
|
||||
private readonly ILoggerFactory _loggerFactory = loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@ -21,7 +21,7 @@ class ComponentHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory log
|
||||
/// <returns></returns>
|
||||
public async Task<string> RenderAsync<TComponent>(IDictionary<string, object?>? parameters = null) where TComponent : IComponent
|
||||
{
|
||||
using var htmlRenderer = new HtmlRenderer(ServiceProvider, LoggerFactory);
|
||||
using var htmlRenderer = new HtmlRenderer(_serviceProvider, _loggerFactory);
|
||||
var html = await htmlRenderer.Dispatcher.InvokeAsync(async () =>
|
||||
{
|
||||
parameters ??= new Dictionary<string, object?>();
|
||||
@ -40,7 +40,7 @@ class ComponentHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory log
|
||||
/// <returns></returns>
|
||||
public async Task<string> RenderAsync(Type componentType, IDictionary<string, object?>? parameters = null)
|
||||
{
|
||||
using var htmlRenderer = new HtmlRenderer(ServiceProvider, LoggerFactory);
|
||||
using var htmlRenderer = new HtmlRenderer(_serviceProvider, _loggerFactory);
|
||||
var html = await htmlRenderer.Dispatcher.InvokeAsync(async () =>
|
||||
{
|
||||
parameters ??= new Dictionary<string, object?>();
|
||||
|
@ -4,18 +4,9 @@
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
internal class DefaultIconTheme : IIconTheme
|
||||
class DefaultIconTheme(IOptions<IconThemeOptions> options) : IIconTheme
|
||||
{
|
||||
private IOptions<IconThemeOptions> Options { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public DefaultIconTheme(IOptions<IconThemeOptions> options)
|
||||
{
|
||||
Options = options;
|
||||
}
|
||||
private readonly IOptions<IconThemeOptions> _options = options;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@ -23,9 +14,9 @@ internal class DefaultIconTheme : IIconTheme
|
||||
/// <returns></returns>
|
||||
public Dictionary<ComponentIcons, string> GetIcons()
|
||||
{
|
||||
if (!Options.Value.Icons.TryGetValue(Options.Value.ThemeKey, out var icons))
|
||||
if (!_options.Value.Icons.TryGetValue(_options.Value.ThemeKey, out var icons))
|
||||
{
|
||||
icons = new Dictionary<ComponentIcons, string>();
|
||||
icons = [];
|
||||
}
|
||||
return icons;
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
// 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/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
class DefaultPdfExport : ITablePdfExport
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="cols"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportAsync<TItem>(IEnumerable<TItem> items, IEnumerable<ITableColumn>? cols = null, string? fileName = null) where TItem : class
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
class DefaultExcelExport : ITableExcelExport
|
||||
class DefaultTableExport : ITableExport
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@ -15,6 +15,15 @@ class DefaultExcelExport : ITableExcelExport
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportExcelAsync<TItem>(IEnumerable<TItem> items, IEnumerable<ITableColumn>? cols = null, string? fileName = null)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
@ -27,4 +36,17 @@ class DefaultExcelExport : ITableExcelExport
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="cols"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportPdfAsync<TItem>(IEnumerable<TItem> items, IEnumerable<ITableColumn>? cols, string? fileName = null)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
25
src/BootstrapBlazor/Services/DefaultTableExportPdf.cs
Normal file
25
src/BootstrapBlazor/Services/DefaultTableExportPdf.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
class DefaultTableExportPdf : ITableExportPdf
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public Task<byte[]> PdfDataAsync(string content) => Task.FromResult(Array.Empty<byte>());
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public Task<Stream> PdfStreamAsync(string content) => Task.FromResult(Stream.Null);
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
// 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 PuppeteerSharp;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
@ -15,13 +13,11 @@ public interface IHtml2Pdf
|
||||
/// Export method
|
||||
/// </summary>
|
||||
/// <param name="url">url</param>
|
||||
/// <param name="options">the instance of PdfOptions</param>
|
||||
Task<byte[]> ExportDataAsync(string url, PdfOptions? options = null);
|
||||
Task<byte[]> PdfDataAsync(string url);
|
||||
|
||||
/// <summary>
|
||||
/// 导出流
|
||||
/// Export method
|
||||
/// </summary>
|
||||
/// <param name="url">url</param>
|
||||
/// <param name="options">the instance of PdfOptions</param>
|
||||
Task<Stream> ExportStreamAsync(string url, PdfOptions? options = null);
|
||||
Task<Stream> PdfStreamAsync(string url);
|
||||
}
|
@ -7,6 +7,7 @@ namespace BootstrapBlazor.Components;
|
||||
/// <summary>
|
||||
/// Table 组件 Excel 导出接口
|
||||
/// </summary>
|
||||
[Obsolete("已过期,请使用 ITableExport 代替 Please use ITableExport instead")]
|
||||
public interface ITableExcelExport
|
||||
{
|
||||
/// <summary>
|
||||
@ -24,4 +25,12 @@ public interface ITableExcelExport
|
||||
/// <param name="cols">当前可见列数据集合 默认 null 导出全部列</param>
|
||||
/// <param name="fileName">文件名 默认 null ExportData_{DateTime.Now:yyyyMMddHHmmss}.xlsx</param>
|
||||
Task<bool> ExportCsvAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null);
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Pdf 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">当前可见列数据集合 默认 null 导出全部列</param>
|
||||
/// <param name="fileName">文件名 默认 null ExportData_{DateTime.Now:yyyyMMddHHmmss}.xlsx</param>
|
||||
Task<bool> ExportPdfAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null);
|
||||
}
|
||||
|
43
src/BootstrapBlazor/Services/ITableExport.cs
Normal file
43
src/BootstrapBlazor/Services/ITableExport.cs
Normal file
@ -0,0 +1,43 @@
|
||||
// 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/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Table 组件 Excel 导出接口
|
||||
/// </summary>
|
||||
public interface ITableExport
|
||||
{
|
||||
/// <summary>
|
||||
/// 导出 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">当前可见列数据集合 默认 null 导出全部列</param>
|
||||
/// <param name="fileName">文件名 默认 null ExportData_{DateTime.Now:yyyyMMddHHmmss}.xlsx</param>
|
||||
Task<bool> ExportAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null);
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Excel 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">当前可见列数据集合 默认 null 导出全部列</param>
|
||||
/// <param name="fileName">文件名 默认 null ExportData_{DateTime.Now:yyyyMMddHHmmss}.xlsx</param>
|
||||
Task<bool> ExportExcelAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null);
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Csv 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">当前可见列数据集合 默认 null 导出全部列</param>
|
||||
/// <param name="fileName">文件名 默认 null ExportData_{DateTime.Now:yyyyMMddHHmmss}.xlsx</param>
|
||||
Task<bool> ExportCsvAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null);
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Pdf 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">当前可见列数据集合 默认 null 导出全部列</param>
|
||||
/// <param name="fileName">文件名 默认 null ExportData_{DateTime.Now:yyyyMMddHHmmss}.xlsx</param>
|
||||
Task<bool> ExportPdfAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null);
|
||||
}
|
23
src/BootstrapBlazor/Services/ITableExportPdf.cs
Normal file
23
src/BootstrapBlazor/Services/ITableExportPdf.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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/
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Table 组件 Pdf 导出接口
|
||||
/// </summary>
|
||||
public interface ITableExportPdf
|
||||
{
|
||||
/// <summary>
|
||||
/// 导出 Pdf 数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<byte[]> PdfDataAsync(string content);
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Pdf 流
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<Stream> PdfStreamAsync(string content);
|
||||
}
|
@ -7,6 +7,7 @@ namespace BootstrapBlazor.Components;
|
||||
/// <summary>
|
||||
/// Table 组件 Pdf 导出接口
|
||||
/// </summary>
|
||||
[Obsolete("已过期,统一使用 ITableExport 接口")]
|
||||
public interface ITablePdfExport
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -16,7 +16,7 @@ public class CssBuilder
|
||||
/// Call Build() to return the completed CSS Classes as a string.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public static CssBuilder Default(string? value = null) => new CssBuilder(value);
|
||||
public static CssBuilder Default(string? value = null) => new(value);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CssBuilder used to define conditional CSS classes used in a component.
|
||||
@ -25,7 +25,7 @@ public class CssBuilder
|
||||
/// <param name="value"></param>
|
||||
protected CssBuilder(string? value)
|
||||
{
|
||||
stringBuffer = new List<string>();
|
||||
stringBuffer = [];
|
||||
AddClass(value);
|
||||
}
|
||||
|
||||
@ -124,5 +124,5 @@ public class CssBuilder
|
||||
/// Finalize the completed CSS Classes as a string.
|
||||
/// </summary>
|
||||
/// <returns>string</returns>
|
||||
public string? Build() => stringBuffer.Any() ? string.Join(" ", stringBuffer) : null;
|
||||
public string? Build() => stringBuffer.Count > 0 ? string.Join(" ", stringBuffer) : null;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>8.0.1</Version>
|
||||
<Version>8.0.2-beta01</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@ -10,6 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="8.0.6-beta01" />
|
||||
<PackageReference Include="PuppeteerSharp" Version="13.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -7,35 +7,39 @@ using PuppeteerSharp;
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// 默认 Html to Pdf 实现
|
||||
/// </summary>
|
||||
class DefaultPdfService : IHtml2Pdf
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public async Task<byte[]> ExportDataAsync(string url, PdfOptions? options = null)
|
||||
public async Task<byte[]> PdfDataAsync(string url)
|
||||
{
|
||||
using var browserFetcher = new BrowserFetcher();
|
||||
await browserFetcher.DownloadAsync();
|
||||
|
||||
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions() { Headless = true });
|
||||
await using var page = await browser.NewPageAsync();
|
||||
await page.GoToAsync(url);
|
||||
|
||||
var content = await page.GetContentAsync();
|
||||
return await page.PdfDataAsync(options ?? new PdfOptions());
|
||||
return await page.PdfDataAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public async Task<Stream> ExportStreamAsync(string url, PdfOptions? options = null)
|
||||
public async Task<Stream> PdfStreamAsync(string url)
|
||||
{
|
||||
using var browserFetcher = new BrowserFetcher();
|
||||
await browserFetcher.DownloadAsync();
|
||||
|
||||
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions() { Headless = true });
|
||||
await using var page = await browser.NewPageAsync();
|
||||
await page.GoToAsync(url);
|
||||
|
||||
var content = await page.GetContentAsync();
|
||||
return await page.PdfStreamAsync(options ?? new PdfOptions());
|
||||
return await page.PdfStreamAsync();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>8.0.1</Version>
|
||||
<Version>8.0.2-beta01</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@ -11,7 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="8.0.5" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="8.0.6-beta01" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -142,8 +142,9 @@ internal class DefaultIcon
|
||||
{ ComponentIcons.TableRefreshButtonIcon, "mdi mdi-refresh" },
|
||||
{ ComponentIcons.TableCardViewButtonIcon, "mdi mdi-menu" },
|
||||
{ ComponentIcons.TableColumnListButtonIcon, "mdi mdi-format-list-bulleted" },
|
||||
{ ComponentIcons.TableExcelExportIcon, "mdi mdi-file-excel" },
|
||||
{ ComponentIcons.TablePdfExportIcon, "mdi mdi-file-pdf-box" },
|
||||
{ ComponentIcons.TableExportCsvIcon, "mdi mdi-file-table-box" },
|
||||
{ ComponentIcons.TableExportExcelIcon, "mdi mdi-file-excel-box" },
|
||||
{ ComponentIcons.TableExportPdfIcon, "mdi mdi-file-pdf-box" },
|
||||
{ ComponentIcons.TableSearchButtonIcon, "mdi mdi-magnify" },
|
||||
{ ComponentIcons.TableResetSearchButtonIcon, "mdi mdi-trash-can-outline" },
|
||||
{ ComponentIcons.TableCloseButtonIcon, "mdi mdi-close" },
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>8.0.0</Version>
|
||||
<Version>8.0.1-beta01</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BootstrapBlazor" Version="8.0.0" />
|
||||
<PackageReference Include="BootstrapBlazor" Version="8.0.6-beta01" />
|
||||
<PackageReference Include="MiniExcel" Version="1.31.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -0,0 +1,172 @@
|
||||
// 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 Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MiniExcelLibs;
|
||||
using System.Text;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
class DefaultTableExport(IServiceProvider serviceProvider) : ITableExport
|
||||
{
|
||||
private IServiceProvider ServiceProvider { get; set; } = serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 导出 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">导出列集合 默认 null 全部导出</param>
|
||||
/// <param name="fileName">导出后下载文件名</param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols = null, string? fileName = null) => InternalExportAsync(items, cols, ExcelType.XLSX, fileName);
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Excel 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">导出列集合 默认 null 全部导出</param>
|
||||
/// <param name="fileName">导出后下载文件名</param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportExcelAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols = null, string? fileName = null) => InternalExportAsync(items, cols, ExcelType.XLSX, fileName);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel"></typeparam>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="cols"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportCsvAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null) => InternalExportAsync(items, cols, ExcelType.CSV, fileName);
|
||||
|
||||
private async Task<bool> InternalExportAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, ExcelType excelType, string? fileName = null)
|
||||
{
|
||||
var value = new List<Dictionary<string, object?>>();
|
||||
cols ??= Utility.GetTableColumns<TModel>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
var row = new Dictionary<string, object?>();
|
||||
foreach (var pi in cols)
|
||||
{
|
||||
var val = await FormatValue(pi, Utility.GetPropertyValue(item, pi.GetFieldName()));
|
||||
row.Add(pi.GetDisplayName(), val);
|
||||
}
|
||||
value.Add(row);
|
||||
}
|
||||
}
|
||||
using var stream = new MemoryStream();
|
||||
await MiniExcel.SaveAsAsync(stream, value, excelType: excelType);
|
||||
|
||||
fileName ??= $"ExportData_{DateTime.Now:yyyyMMddHHmmss}.{GetExtension()}";
|
||||
stream.Position = 0;
|
||||
var downloadService = ServiceProvider.GetRequiredService<DownloadService>();
|
||||
await downloadService.DownloadFromStreamAsync(fileName, stream);
|
||||
return true;
|
||||
|
||||
string GetExtension() => excelType == ExcelType.XLSX ? "xlsx" : "csv";
|
||||
}
|
||||
|
||||
private static async Task<object?> FormatValue(ITableColumn col, object? value)
|
||||
{
|
||||
var ret = value;
|
||||
if (col.Lookup != null)
|
||||
{
|
||||
ret = col.Lookup.FirstOrDefault(i => i.Value.Equals(value?.ToString(), col.LookupStringComparison))?.Text;
|
||||
}
|
||||
if (col.Formatter != null)
|
||||
{
|
||||
// 格式化回调委托
|
||||
ret = await col.Formatter(value);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(col.FormatString))
|
||||
{
|
||||
// 格式化字符串
|
||||
ret = Utility.Format(value, col.FormatString);
|
||||
}
|
||||
else if (col.PropertyType.IsEnum())
|
||||
{
|
||||
ret = col.PropertyType.ToDescriptionString(value?.ToString());
|
||||
}
|
||||
else if (value is IEnumerable<object> v)
|
||||
{
|
||||
ret = string.Join(",", v);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel"></typeparam>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="cols"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ExportPdfAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null)
|
||||
{
|
||||
var ret = false;
|
||||
var logger = ServiceProvider.GetRequiredService<ILogger<DefaultTableExport>>();
|
||||
|
||||
try
|
||||
{
|
||||
// 生成表格
|
||||
var html = await GenerateTableHtmlAsync(items, cols);
|
||||
|
||||
// 得到 Pdf 文件数据
|
||||
var pdfService = ServiceProvider.GetRequiredService<ITableExportPdf>();
|
||||
var stream = await pdfService.PdfStreamAsync(html);
|
||||
|
||||
// 下载 Pdf 文件
|
||||
var downloadService = ServiceProvider.GetRequiredService<DownloadService>();
|
||||
fileName ??= $"ExportData_{DateTime.Now:yyyyMMddHHmmss}.pdf";
|
||||
await downloadService.DownloadFromStreamAsync(fileName, stream);
|
||||
ret = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "ExportPdfAsync execute failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static async Task<string> GenerateTableHtmlAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
cols ??= Utility.GetTableColumns<TModel>();
|
||||
builder.AppendLine("<table class=\"table table-bordered table-striped\">");
|
||||
|
||||
// 生成表头
|
||||
builder.AppendLine("<thead><tr>");
|
||||
foreach (var pi in cols)
|
||||
{
|
||||
builder.AppendLine($"<th><div class=\"table-cell\">{pi.GetDisplayName()}</div></th>");
|
||||
}
|
||||
builder.AppendLine("</tr></thead>");
|
||||
|
||||
builder.AppendLine("<tbody>");
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
builder.AppendLine("<tr>");
|
||||
foreach (var pi in cols)
|
||||
{
|
||||
var val = await FormatValue(pi, Utility.GetPropertyValue(item, pi.GetFieldName()));
|
||||
builder.AppendLine($"<td><div class=\"table-cell\">{val}</div></td>");
|
||||
}
|
||||
builder.AppendLine("</tr>");
|
||||
}
|
||||
}
|
||||
builder.AppendLine("</tbody>");
|
||||
builder.AppendLine("</table>");
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
// 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 Microsoft.Extensions.DependencyInjection;
|
||||
using MiniExcelLibs;
|
||||
|
||||
namespace BootstrapBlazor.Components;
|
||||
|
||||
class ExcelExport : ITableExcelExport
|
||||
{
|
||||
private IServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
public ExcelExport(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出 Excel 方法
|
||||
/// </summary>
|
||||
/// <param name="items">导出数据集合</param>
|
||||
/// <param name="cols">导出列集合 默认 null 全部导出</param>
|
||||
/// <param name="fileName">导出后下载文件名</param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> ExportAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols = null, string? fileName = null) => InternalExportAsync(items, cols, ExcelType.XLSX, fileName);
|
||||
|
||||
public Task<bool> ExportCsvAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, string? fileName = null) => InternalExportAsync(items, cols, ExcelType.CSV, fileName);
|
||||
|
||||
private async Task<bool> InternalExportAsync<TModel>(IEnumerable<TModel> items, IEnumerable<ITableColumn>? cols, ExcelType excelType, string? fileName = null)
|
||||
{
|
||||
var value = new List<Dictionary<string, object?>>();
|
||||
cols ??= Utility.GetTableColumns<TModel>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
var row = new Dictionary<string, object?>();
|
||||
foreach (var pi in cols)
|
||||
{
|
||||
var val = await FormatValue(pi, Utility.GetPropertyValue(item, pi.GetFieldName()));
|
||||
row.Add(pi.GetDisplayName(), val);
|
||||
}
|
||||
value.Add(row);
|
||||
}
|
||||
}
|
||||
using var stream = new MemoryStream();
|
||||
await MiniExcel.SaveAsAsync(stream, value, excelType: excelType);
|
||||
|
||||
fileName ??= $"ExportData_{DateTime.Now:yyyyMMddHHmmss}.{GetExtension()}";
|
||||
stream.Position = 0;
|
||||
var downloadService = ServiceProvider.GetRequiredService<DownloadService>();
|
||||
await downloadService.DownloadFromStreamAsync(fileName, stream);
|
||||
return true;
|
||||
|
||||
string GetExtension() => excelType == ExcelType.XLSX ? "xlsx" : "csv";
|
||||
}
|
||||
|
||||
private static async Task<object?> FormatValue(ITableColumn col, object? value)
|
||||
{
|
||||
var ret = value;
|
||||
if (col.Lookup != null)
|
||||
{
|
||||
ret = col.Lookup.FirstOrDefault(i => i.Value.Equals(value?.ToString(), col.LookupStringComparison))?.Text;
|
||||
}
|
||||
if (col.Formatter != null)
|
||||
{
|
||||
// 格式化回调委托
|
||||
ret = await col.Formatter(value);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(col.FormatString))
|
||||
{
|
||||
// 格式化字符串
|
||||
ret = Utility.Format(value, col.FormatString);
|
||||
}
|
||||
else if (col.PropertyType.IsEnum())
|
||||
{
|
||||
ret = col.PropertyType.ToDescriptionString(value?.ToString());
|
||||
}
|
||||
else if (value is IEnumerable<object> v)
|
||||
{
|
||||
ret = string.Join(",", v);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ namespace Microsoft.Extensions.DependencyInjection;
|
||||
/// <summary>
|
||||
/// BootstrapBlazor 服务扩展类
|
||||
/// </summary>
|
||||
public static class TableExcelExportServiceCollectionExtensions
|
||||
public static class TableExportServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 增加 BootstrapBlazor 服务
|
||||
@ -16,7 +16,7 @@ public static class TableExcelExportServiceCollectionExtensions
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddBootstrapBlazorTableExcelExport(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<ITableExcelExport, ExcelExport>();
|
||||
services.AddTransient<ITableExport, DefaultTableExport>();
|
||||
return services;
|
||||
}
|
||||
}
|
@ -752,7 +752,7 @@ public class TableTest : TableTestBase
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShowExportButton_Ok()
|
||||
public async Task ShowExportButton_Ok()
|
||||
{
|
||||
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
|
||||
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
|
||||
@ -789,15 +789,22 @@ public class TableTest : TableTestBase
|
||||
|
||||
// Excel 导出图标监测
|
||||
// Pdf 导出图标监测
|
||||
table.DoesNotContain("fa-regular fa-file-excel");
|
||||
table.DoesNotContain("fa-regular fa-file-pdf");
|
||||
table.DoesNotContain("fa-solid fa-fw fa-file-excel");
|
||||
table.DoesNotContain("fa-solid fa-fw fa-file-pdf");
|
||||
|
||||
table.SetParametersAndRender(pb =>
|
||||
{
|
||||
pb.Add(a => a.ShowExportCsvButton, true);
|
||||
pb.Add(a => a.ShowExportExcelButton, true);
|
||||
pb.Add(a => a.ShowExportPdfButton, true);
|
||||
});
|
||||
table.Contains("fa-regular fa-file-excel");
|
||||
table.Contains("fa-regular fa-file-pdf");
|
||||
table.Contains("fa-solid fa-fw fa-file-csv");
|
||||
table.Contains("fa-solid fa-fw fa-file-excel");
|
||||
table.Contains("fa-solid fa-fw fa-file-pdf");
|
||||
|
||||
// 导出 csv
|
||||
var button = table.Find(".fa-file-csv");
|
||||
await table.InvokeAsync(() => button.Click());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -807,7 +814,7 @@ public class TableTest : TableTestBase
|
||||
ITableExportDataContext<Foo>? exportContext = null;
|
||||
bool exported = false;
|
||||
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
|
||||
var export = Context.Services.GetRequiredService<ITableExcelExport>();
|
||||
var export = Context.Services.GetRequiredService<ITableExport>();
|
||||
var cut = Context.RenderComponent<BootstrapBlazorRoot>(pb =>
|
||||
{
|
||||
pb.AddChildContent<Table<Foo>>(pb =>
|
||||
@ -6158,6 +6165,7 @@ public class TableTest : TableTestBase
|
||||
pb.Add(a => a.OnQueryAsync, OnQueryAsync(localizer));
|
||||
pb.Add(a => a.ShowToolbar, true);
|
||||
pb.Add(a => a.ShowExportButton, true);
|
||||
pb.Add(a => a.ShowExportCsvButton, true);
|
||||
pb.Add(a => a.ShowExportPdfButton, true);
|
||||
pb.Add(a => a.TableColumns, foo => builder =>
|
||||
{
|
||||
@ -6169,33 +6177,29 @@ public class TableTest : TableTestBase
|
||||
});
|
||||
});
|
||||
|
||||
cut.InvokeAsync(() =>
|
||||
var buttons = cut.FindAll(".dropdown-menu-end .dropdown-item");
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
var button = cut.Find(".dropdown-menu-end .dropdown-item");
|
||||
button.Click();
|
||||
});
|
||||
|
||||
cut.InvokeAsync(() =>
|
||||
{
|
||||
var buttons = cut.FindAll(".dropdown-menu-end .dropdown-item");
|
||||
buttons[buttons.Count - 1].Click();
|
||||
});
|
||||
cut.InvokeAsync(() =>
|
||||
{
|
||||
button.Click();
|
||||
});
|
||||
}
|
||||
|
||||
var table = cut.FindComponent<Table<Foo>>();
|
||||
table.SetParametersAndRender(pb =>
|
||||
{
|
||||
pb.Add(a => a.OnExportAsync, _ => Task.FromResult(true));
|
||||
});
|
||||
cut.InvokeAsync(() =>
|
||||
|
||||
buttons = cut.FindAll(".dropdown-menu-end .dropdown-item");
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
var button = cut.Find(".dropdown-menu-end .dropdown-item");
|
||||
button.Click();
|
||||
});
|
||||
cut.InvokeAsync(() =>
|
||||
{
|
||||
var buttons = cut.FindAll(".dropdown-menu-end .dropdown-item");
|
||||
buttons[buttons.Count - 1].Click();
|
||||
});
|
||||
cut.InvokeAsync(() =>
|
||||
{
|
||||
button.Click();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
Loading…
Reference in New Issue
Block a user